VirtualBox

source: vbox/trunk/src/bldprogs/VBoxDef2LazyLoad.cpp@ 59410

Last change on this file since 59410 was 59404, checked in by vboxsync, 9 years ago

Forward-ported r104938, r104943, r104950, r104952, r104953, r104987, r104988, r104990 from 5.0:

  • VBoxStub: Lazy import DLLs not in the KnownDlls list (and then some) and check that we don't accidentally add new imports as time goes by.
  • VBoxStub: the dlls have export names, so use them instead of the ordinals.
  • VBoxDef2LazyLoad fixes and error reporting, fixed missing VBoxCheckImports dependency during use in VBoxStub.
  • iprt/initterm.h,vbox-img,VBoxStub: Introduced RTR3INIT_FLAGS_STANDALONE_APP for statically linked applications that are expected to run outside the normal VirtualBox installation directory and need to be on their toes wrt dynamic library search paths. (Only windows, really.) Also, _always_ initialize IPRT first, don't ever do anything before that unless it 104% must be done there.
  • RTR3INIT_FLAGS_STANDALONE_APP trumps concerns about Vista GUI
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.8 KB
Line 
1/* $Id: VBoxDef2LazyLoad.cpp 59404 2016-01-19 10:10:39Z vboxsync $ */
2/** @file
3 * VBoxDef2LazyLoad - Lazy Library Loader Generator.
4 *
5 * @note Only tested on win.amd64 & darwin.amd64.
6 */
7
8/*
9 * Copyright (C) 2013-2015 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#include <ctype.h>
25#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28#include <iprt/types.h>
29
30
31/*********************************************************************************************************************************
32* Structures and Typedefs *
33*********************************************************************************************************************************/
34typedef struct MYEXPORT
35{
36 struct MYEXPORT *pNext;
37 /** Pointer to unmangled name for stdcall (after szName), NULL if not. */
38 char *pszUnstdcallName;
39 /** Pointer to the exported name. */
40 char const *pszExportedNm;
41 unsigned uOrdinal;
42 bool fNoName;
43 char szName[1];
44} MYEXPORT;
45typedef MYEXPORT *PMYEXPORT;
46
47
48
49/*********************************************************************************************************************************
50* Global Variables *
51*********************************************************************************************************************************/
52/** @name Options
53 * @{ */
54static const char *g_pszOutput = NULL;
55static const char *g_pszLibrary = NULL;
56static const char *g_apszInputs[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
57static unsigned g_cInputs = 0;
58static bool g_fIgnoreData = true;
59static bool g_fWithExplictLoadFunction = false;
60static bool g_fSystemLibrary = false;
61/** @} */
62
63/** Pointer to the export name list head. */
64static PMYEXPORT g_pExpHead = NULL;
65/** Pointer to the next pointer for insertion. */
66static PMYEXPORT *g_ppExpNext = &g_pExpHead;
67
68
69
70static const char *leftStrip(const char *psz)
71{
72 while (isspace(*psz))
73 psz++;
74 return psz;
75}
76
77
78static char *leftStrip(char *psz)
79{
80 while (isspace(*psz))
81 psz++;
82 return psz;
83}
84
85
86static unsigned wordLength(const char *pszWord)
87{
88 unsigned off = 0;
89 char ch;
90 while ( (ch = pszWord[off]) != '\0'
91 && ch != '='
92 && ch != ','
93 && ch != ':'
94 && !isspace(ch) )
95 off++;
96 return off;
97}
98
99
100/**
101 * Parses the module definition file, collecting export information.
102 *
103 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
104 * details has been displayed.
105 * @param pInput The input stream.
106 */
107static RTEXITCODE parseInputInner(FILE *pInput, const char *pszInput)
108{
109 /*
110 * Process the file line-by-line.
111 */
112 bool fInExports = false;
113 unsigned iLine = 0;
114 char szLine[16384];
115 while (fgets(szLine, sizeof(szLine), pInput))
116 {
117 iLine++;
118
119 /*
120 * Strip leading and trailing spaces from the line as well as
121 * trailing comments.
122 */
123 char *psz = leftStrip(szLine);
124 if (*psz == ';')
125 continue; /* comment line. */
126
127 char *pszComment = strchr(psz, ';');
128 if (pszComment)
129 *pszComment = '\0';
130
131 unsigned cch = (unsigned)strlen(psz);
132 while (cch > 0 && (isspace(psz[cch - 1]) || psz[cch - 1] == '\r' || psz[cch - 1] == '\n'))
133 psz[--cch] = '\0';
134
135 if (!cch)
136 continue;
137
138 /*
139 * Check for known directives.
140 */
141 size_t cchWord0 = wordLength(psz);
142#define WORD_CMP(pszWord1, cchWord1, szWord2) \
143 ( (cchWord1) == sizeof(szWord2) - 1 && memcmp(pszWord1, szWord2, sizeof(szWord2) - 1) == 0 )
144 if (WORD_CMP(psz, cchWord0, "EXPORTS"))
145 {
146 fInExports = true;
147
148 /* In case there is an export on the same line. (Really allowed?) */
149 psz = leftStrip(psz + sizeof("EXPORTS") - 1);
150 if (!*psz)
151 continue;
152 }
153 /* Directives that we don't care about, but need to catch in order to
154 terminate the EXPORTS section in a timely manner. */
155 else if ( WORD_CMP(psz, cchWord0, "NAME")
156 || WORD_CMP(psz, cchWord0, "LIBRARY")
157 || WORD_CMP(psz, cchWord0, "DESCRIPTION")
158 || WORD_CMP(psz, cchWord0, "STACKSIZE")
159 || WORD_CMP(psz, cchWord0, "SECTIONS")
160 || WORD_CMP(psz, cchWord0, "SEGMENTS")
161 || WORD_CMP(psz, cchWord0, "VERSION")
162 )
163 {
164 fInExports = false;
165 }
166
167 /*
168 * Process exports:
169 * entryname[=internalname] [@ordinal[ ][NONAME]] [DATA] [PRIVATE]
170 */
171 if (fInExports)
172 {
173 const char *pchName = psz;
174 unsigned cchName = wordLength(psz);
175
176 psz = leftStrip(psz + cchName);
177 if (*psz == '=')
178 {
179 psz = leftStrip(psz + 1);
180 psz = leftStrip(psz + wordLength(psz));
181 }
182
183 bool fNoName = false;
184 unsigned uOrdinal = ~0U;
185 if (*psz == '@')
186 {
187 psz++;
188 if (!isdigit(*psz))
189 {
190 fprintf(stderr, "%s:%u: error: Invalid ordinal spec.\n", pszInput, iLine);
191 return RTEXITCODE_FAILURE;
192 }
193 uOrdinal = *psz++ - '0';
194 while (isdigit(*psz))
195 {
196 uOrdinal *= 10;
197 uOrdinal += *psz++ - '0';
198 }
199 psz = leftStrip(psz);
200 cch = wordLength(psz);
201 if (WORD_CMP(psz, cch, "NONAME"))
202 {
203 fNoName = true;
204 psz = leftStrip(psz + cch);
205 }
206 }
207
208 while (*psz)
209 {
210 cch = wordLength(psz);
211 if (WORD_CMP(psz, cch, "DATA"))
212 {
213 if (!g_fIgnoreData)
214 {
215 fprintf(stderr, "%s:%u: error: Cannot wrap up DATA export '%.*s'.\n",
216 pszInput, iLine, cchName, pchName);
217 return RTEXITCODE_SUCCESS;
218 }
219 }
220 else if (!WORD_CMP(psz, cch, "PRIVATE"))
221 {
222 fprintf(stderr, "%s:%u: error: Cannot wrap up DATA export '%.*s'.\n",
223 pszInput, iLine, cchName, pchName);
224 return RTEXITCODE_SUCCESS;
225 }
226 psz = leftStrip(psz + cch);
227 }
228
229 /*
230 * Check for stdcall mangling.
231 */
232 size_t cbExp = sizeof(MYEXPORT) + cchName;
233 unsigned cchStdcall = 0;
234 if (cchName > 3 && *pchName == '_' && isdigit(pchName[cchName - 1]))
235 {
236 if (cchName > 3 && pchName[cchName - 2] == '@')
237 cchStdcall = 2;
238 else if (cchName > 4 && pchName[cchName - 3] == '@' && isdigit(pchName[cchName - 2]))
239 cchStdcall = 3;
240 if (cchStdcall)
241 cbExp += cchName - 1 - cchStdcall;
242 }
243
244 /*
245 * Add the export.
246 */
247
248 PMYEXPORT pExp = (PMYEXPORT)malloc(cbExp);
249 if (!pExp)
250 {
251 fprintf(stderr, "%s:%u: error: Out of memory.\n", pszInput, iLine);
252 return RTEXITCODE_SUCCESS;
253 }
254 memcpy(pExp->szName, pchName, cchName);
255 pExp->szName[cchName] = '\0';
256 if (!cchStdcall)
257 {
258 pExp->pszUnstdcallName = NULL;
259 pExp->pszExportedNm = pExp->szName;
260 }
261 else
262 {
263 pExp->pszUnstdcallName = &pExp->szName[cchName + 1];
264 memcpy(pExp->pszUnstdcallName, pchName + 1, cchName - 1 - cchStdcall);
265 pExp->pszUnstdcallName[cchName - 1 - cchStdcall] = '\0';
266 pExp->pszExportedNm = pExp->pszUnstdcallName;
267 }
268 pExp->uOrdinal = uOrdinal;
269 pExp->fNoName = fNoName;
270 pExp->pNext = NULL;
271 *g_ppExpNext = pExp;
272 g_ppExpNext = &pExp->pNext;
273 }
274 }
275
276 /*
277 * Why did we quit the loop, EOF or error?
278 */
279 if (feof(pInput))
280 return RTEXITCODE_SUCCESS;
281 fprintf(stderr, "error: Read while reading '%s' (iLine=%u).\n", pszInput, iLine);
282 return RTEXITCODE_FAILURE;
283}
284
285
286/**
287 * Parses a_apszInputs, populating the list pointed to by g_pExpHead.
288 *
289 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
290 * details has been displayed.
291 */
292static RTEXITCODE parseInputs(void)
293{
294 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
295 for (unsigned i = 0; i < g_cInputs; i++)
296 {
297 FILE *pInput = fopen(g_apszInputs[i], "r");
298 if (pInput)
299 {
300 RTEXITCODE rcExit2 = parseInputInner(pInput, g_apszInputs[i]);
301 fclose(pInput);
302 if (rcExit2 == RTEXITCODE_SUCCESS && !g_pExpHead)
303 {
304 fprintf(stderr, "error: Found no exports in '%s'.\n", g_apszInputs[i]);
305 rcExit2 = RTEXITCODE_FAILURE;
306 }
307 if (rcExit2 != RTEXITCODE_SUCCESS)
308 rcExit = rcExit2;
309 }
310 else
311 {
312 fprintf(stderr, "error: Failed to open '%s' for reading.\n", g_apszInputs[i]);
313 rcExit = RTEXITCODE_FAILURE;
314 }
315 }
316 return rcExit;
317}
318
319
320/**
321 * Generates the assembly source code, writing it to @a pOutput.
322 *
323 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
324 * details has been displayed.
325 * @param pOutput The output stream (caller checks it for errors
326 * when closing).
327 */
328static RTEXITCODE generateOutputInner(FILE *pOutput)
329{
330 fprintf(pOutput, ";;\n");
331 for (unsigned i = 0; i < g_cInputs; i++)
332 fprintf(pOutput, ";; Autogenerated from '%s'.\n", g_apszInputs[i]);
333
334 fprintf(pOutput,
335 ";; DO NOT EDIT!\n"
336 ";;\n"
337 "\n"
338 "\n"
339 "%%include \"iprt/asmdefs.mac\"\n"
340 "\n"
341 "\n");
342
343 /*
344 * Put the thunks first for alignment and other reasons. It's the hot part of the code.
345 */
346 fprintf(pOutput,
347 ";\n"
348 "; Thunks.\n"
349 ";\n"
350 "BEGINCODE\n");
351 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
352 if (!pExp->pszUnstdcallName)
353 fprintf(pOutput,
354 "BEGINPROC %s\n"
355 " jmp RTCCPTR_PRE [g_pfn%s xWrtRIP]\n"
356 "ENDPROC %s\n",
357 pExp->szName, pExp->szName, pExp->szName);
358 else
359 fprintf(pOutput,
360 "%%ifdef RT_ARCH_X86\n"
361 "global %s\n"
362 "%s:\n"
363 " jmp RTCCPTR_PRE [g_pfn%s xWrtRIP]\n"
364 "%%else\n"
365 "BEGINPROC %s\n"
366 " jmp RTCCPTR_PRE [g_pfn%s xWrtRIP]\n"
367 "ENDPROC %s\n"
368 "%%endif\n",
369 pExp->szName, pExp->szName, pExp->pszUnstdcallName,
370 pExp->pszUnstdcallName, pExp->pszUnstdcallName, pExp->pszUnstdcallName);
371
372 fprintf(pOutput,
373 "\n"
374 "\n");
375
376 /*
377 * Import pointers
378 */
379 fprintf(pOutput,
380 ";\n"
381 "; Import pointers. Initialized to point a lazy loading stubs.\n"
382 ";\n"
383 "BEGINDATA\n"
384 "g_apfnImports:\n");
385 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
386 fprintf(pOutput,
387 "%%ifdef ASM_FORMAT_PE\n"
388 "global __imp_%s\n"
389 "__imp_%s:\n"
390 "%%endif\n"
391 "g_pfn%s RTCCPTR_DEF ___LazyLoad___%s\n"
392 "\n",
393 pExp->szName,
394 pExp->szName,
395 pExp->pszExportedNm,
396 pExp->pszExportedNm);
397 fprintf(pOutput,
398 "RTCCPTR_DEF 0 ; Terminator entry for traversal.\n"
399 "\n"
400 "\n");
401
402 /*
403 * Now for the less important stuff, starting with the names.
404 *
405 * We keep the names separate so we can traverse them in parallel to
406 * g_apfnImports in the load-everything routine further down.
407 */
408 fprintf(pOutput,
409 ";\n"
410 "; Imported names.\n"
411 ";\n"
412 "BEGINCODE\n"
413 "g_szLibrary: db '%s',0\n"
414 "\n"
415 "g_szzNames:\n",
416 g_pszLibrary);
417 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
418 if (!pExp->fNoName)
419 fprintf(pOutput, " g_sz%s:\n db '%s',0\n", pExp->pszExportedNm, pExp->pszExportedNm);
420 else
421 fprintf(pOutput, " g_sz%s:\n db '#%u',0\n", pExp->pszExportedNm, pExp->uOrdinal);
422 fprintf(pOutput,
423 "g_EndOfNames: db 0\n"
424 "\n"
425 "g_szFailLoadFmt: db 'Lazy loader failed to load \"%%s\": %%Rrc', 10, 0\n"
426 "g_szFailResolveFmt: db 'Lazy loader failed to resolve symbol \"%%s\" in \"%%s\": %%Rrc', 10, 0\n"
427 "\n"
428 "\n");
429
430 /*
431 * The per import lazy load code.
432 */
433 fprintf(pOutput,
434 ";\n"
435 "; Lazy load+resolve stubs.\n"
436 ";\n"
437 "BEGINCODE\n");
438 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
439 {
440 if (!pExp->fNoName)
441 fprintf(pOutput,
442 "___LazyLoad___%s:\n"
443 /* "int3\n" */
444 "%%ifdef RT_ARCH_AMD64\n"
445 " lea rax, [g_sz%s wrt rip]\n"
446 " lea r10, [g_pfn%s wrt rip]\n"
447 " call LazyLoadResolver\n"
448 "%%elifdef RT_ARCH_X86\n"
449 " push g_sz%s\n"
450 " push g_pfn%s\n"
451 " call LazyLoadResolver\n"
452 " add esp, 8h\n"
453 "%%else\n"
454 " %%error \"Unsupported architecture\"\n"
455 "%%endif\n"
456 ,
457 pExp->pszExportedNm,
458 pExp->pszExportedNm,
459 pExp->pszExportedNm,
460 pExp->pszExportedNm,
461 pExp->pszExportedNm);
462 else
463 fprintf(pOutput,
464 "___LazyLoad___%s:\n"
465 /* "int3\n" */
466 "%%ifdef RT_ARCH_AMD64\n"
467 " mov eax, %u\n"
468 " lea r10, [g_pfn%s wrt rip]\n"
469 " call LazyLoadResolver\n"
470 "%%elifdef RT_ARCH_X86\n"
471 " push %u\n"
472 " push g_pfn%s\n"
473 " call LazyLoadResolver\n"
474 " add esp, 8h\n"
475 "%%else\n"
476 " %%error \"Unsupported architecture\"\n"
477 "%%endif\n"
478 ,
479 pExp->pszExportedNm,
480 pExp->uOrdinal,
481 pExp->pszExportedNm,
482 pExp->uOrdinal,
483 pExp->pszExportedNm);
484 if (!pExp->pszUnstdcallName)
485 fprintf(pOutput, " jmp NAME(%s)\n", pExp->szName);
486 else
487 fprintf(pOutput,
488 "%%ifdef RT_ARCH_X86\n"
489 " jmp %s\n"
490 "%%else\n"
491 " jmp NAME(%s)\n"
492 "%%endif\n"
493 ,
494 pExp->szName, pExp->szName);
495 fprintf(pOutput, "\n");
496 }
497 fprintf(pOutput,
498 "\n"
499 "\n"
500 "\n");
501
502 /*
503 * The code that does the loading and resolving.
504 */
505 fprintf(pOutput,
506 ";\n"
507 "; The module handle.\n"
508 ";\n"
509 "BEGINDATA\n"
510 "g_hMod RTCCPTR_DEF 0\n"
511 "\n"
512 "\n"
513 "\n");
514
515 /*
516 * How we load the module needs to be selectable later on.
517 *
518 * The LazyLoading routine returns the module handle in RCX/ECX, caller
519 * saved all necessary registers.
520 */
521 if (!g_fSystemLibrary)
522 fprintf(pOutput,
523 ";\n"
524 ";SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod,\n"
525 "; uint32_t fFlags, PRTERRINFO pErrInfo);\n"
526 ";\n"
527 "EXTERN_IMP2 SUPR3HardenedLdrLoadAppPriv\n"
528 "%%ifdef IN_RT_R3\n"
529 "extern NAME(RTAssertMsg2Weak)\n"
530 "%%else\n"
531 "EXTERN_IMP2 RTAssertMsg2Weak\n"
532 "%%endif\n"
533 "BEGINCODE\n"
534 "\n"
535 "LazyLoading:\n"
536 " mov xCX, [g_hMod xWrtRIP]\n"
537 " or xCX, xCX\n"
538 " jnz .return\n"
539 "\n"
540 "%%ifdef ASM_CALL64_GCC\n"
541 " xor rcx, rcx ; pErrInfo\n"
542 " xor rdx, rdx ; fFlags (local load)\n"
543 " lea rsi, [g_hMod wrt rip] ; phLdrMod\n"
544 " lea rdi, [g_szLibrary wrt rip] ; pszFilename\n"
545 " sub rsp, 08h\n"
546 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
547 " add rsp, 08h\n"
548 "\n"
549 "%%elifdef ASM_CALL64_MSC\n"
550 " xor r9, r9 ; pErrInfo\n"
551 " xor r8, r8 ; fFlags (local load)\n"
552 " lea rdx, [g_hMod wrt rip] ; phLdrMod\n"
553 " lea rcx, [g_szLibrary wrt rip] ; pszFilename\n"
554 " sub rsp, 28h\n"
555 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
556 " add rsp, 28h\n"
557 "\n"
558 "%%elifdef RT_ARCH_X86\n"
559 " sub xSP, 0ch\n"
560 " push 0 ; pErrInfo\n"
561 " push 0 ; fFlags (local load)\n"
562 " push g_hMod ; phLdrMod\n"
563 " push g_szLibrary ; pszFilename\n"
564 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
565 " add esp, 1ch\n"
566 "%%else\n"
567 " %%error \"Unsupported architecture\"\n"
568 "%%endif\n");
569 else
570 fprintf(pOutput,
571 ";\n"
572 "; RTDECL(int) RTLdrLoadSystem(const char *pszFilename, bool fNoUnload, PRTLDRMOD phLdrMod);\n"
573 ";\n"
574 "%%ifdef IN_RT_R3\n"
575 "extern NAME(RTLdrLoadSystem)\n"
576 "extern NAME(RTAssertMsg2Weak)\n"
577 "%%else\n"
578 "EXTERN_IMP2 RTLdrLoadSystem\n"
579 "EXTERN_IMP2 RTAssertMsg2Weak\n"
580 "%%endif\n"
581 "BEGINCODE\n"
582 "\n"
583 "LazyLoading:\n"
584 " mov xCX, [g_hMod xWrtRIP]\n"
585 " or xCX, xCX\n"
586 " jnz .return\n"
587 "\n"
588 "%%ifdef ASM_CALL64_GCC\n"
589 " lea rdx, [g_hMod wrt rip] ; phLdrMod\n"
590 " mov esi, 1 ; fNoUnload=true\n"
591 " lea rdi, [g_szLibrary wrt rip] ; pszFilename\n"
592 " sub rsp, 08h\n"
593 " %%ifdef IN_RT_R3\n"
594 " call NAME(RTLdrLoadSystem)\n"
595 " %%else\n"
596 " call IMP2(RTLdrLoadSystem)\n"
597 " %%endif\n"
598 " add rsp, 08h\n"
599 "\n"
600 "%%elifdef ASM_CALL64_MSC\n"
601 " lea r8, [g_hMod wrt rip] ; phLdrMod\n"
602 " mov edx, 1 ; fNoUnload=true\n"
603 " lea rcx, [g_szLibrary wrt rip] ; pszFilename\n"
604 " sub rsp, 28h\n"
605 " %%ifdef IN_RT_R3\n"
606 " call NAME(RTLdrLoadSystem)\n"
607 " %%else\n"
608 " call IMP2(RTLdrLoadSystem)\n"
609 " %%endif\n"
610 " add rsp, 28h\n"
611 "\n"
612 "%%elifdef RT_ARCH_X86\n"
613 " push g_hMod ; phLdrMod\n"
614 " push 1 ; fNoUnload=true\n"
615 " push g_szLibrary ; pszFilename\n"
616 " %%ifdef IN_RT_R3\n"
617 " call NAME(RTLdrLoadSystem)\n"
618 " %%else\n"
619 " call IMP2(RTLdrLoadSystem)\n"
620 " %%endif\n"
621 " add esp, 0ch\n"
622 "%%else\n"
623 " %%error \"Unsupported architecture\"\n"
624 "%%endif\n");
625 fprintf(pOutput,
626 " or eax, eax\n"
627 " jnz .badload\n"
628 " mov xCX, [g_hMod xWrtRIP]\n"
629 ".return:\n"
630 " ret\n"
631 "\n"
632 ".badload:\n"
633 "%%ifdef ASM_CALL64_GCC\n"
634 " mov edx, eax\n"
635 " lea rsi, [g_szLibrary wrt rip]\n"
636 " lea rdi, [g_szFailLoadFmt wrt rip]\n"
637 " sub rsp, 08h\n"
638 "%%elifdef ASM_CALL64_MSC\n"
639 " mov r8d, eax\n"
640 " lea rdx, [g_szLibrary wrt rip]\n"
641 " lea rcx, [g_szFailLoadFmt wrt rip]\n"
642 " sub rsp, 28h\n"
643 "%%elifdef RT_ARCH_X86\n"
644 " push eax\n"
645 " push g_szLibrary\n"
646 " push g_szFailLoadFmt\n"
647 "%%endif\n"
648 "%%ifdef IN_RT_R3\n"
649 " call NAME(RTAssertMsg2Weak)\n"
650 "%%else\n"
651 " call IMP2(RTAssertMsg2Weak)\n"
652 "%%endif\n"
653 ".badloadloop:\n"
654 " int3\n"
655 " jmp .badloadloop\n"
656 "LazyLoading_End:\n"
657 "\n"
658 "\n");
659
660
661 fprintf(pOutput,
662 ";\n"
663 ";RTDECL(int) RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvValue);\n"
664 ";\n"
665 "%%ifdef IN_RT_R3\n"
666 "extern NAME(RTLdrGetSymbol)\n"
667 "%%else\n"
668 "EXTERN_IMP2 RTLdrGetSymbol\n"
669 "%%endif\n"
670 "BEGINCODE\n"
671 "LazyLoadResolver:\n"
672 "%%ifdef RT_ARCH_AMD64\n"
673 " push rbp\n"
674 " mov rbp, rsp\n"
675 " push r15\n"
676 " push r14\n"
677 " mov r15, rax ; name\n"
678 " mov r14, r10 ; ppfn\n"
679 " push r9\n"
680 " push r8\n"
681 " push rcx\n"
682 " push rdx\n"
683 " push r12\n"
684 " %%ifdef ASM_CALL64_GCC\n"
685 " push rsi\n"
686 " push rdi\n"
687 " mov r12, rsp\n"
688 " %%else\n"
689 " mov r12, rsp\n"
690 " sub rsp, 20h\n"
691 " %%endif\n"
692 " and rsp, 0fffffff0h ; Try make sure the stack is aligned\n"
693 "\n"
694 " call LazyLoading ; returns handle in rcx\n"
695 " %%ifdef ASM_CALL64_GCC\n"
696 " mov rdi, rcx ; hLdrMod\n"
697 " mov rsi, r15 ; pszSymbol\n"
698 " mov rdx, r14 ; ppvValue\n"
699 " %%else\n"
700 " mov rdx, r15 ; pszSymbol\n"
701 " mov r8, r14 ; ppvValue\n"
702 " %%endif\n"
703 " %%ifdef IN_RT_R3\n"
704 " call NAME(RTLdrGetSymbol)\n"
705 " %%else\n"
706 " call IMP2(RTLdrGetSymbol)\n"
707 " %%endif\n"
708 " or eax, eax\n"
709 " jnz .badsym\n"
710 "\n"
711 " mov rsp, r12\n"
712 " %%ifdef ASM_CALL64_GCC\n"
713 " pop rdi\n"
714 " pop rsi\n"
715 " %%endif\n"
716 " pop r12\n"
717 " pop rdx\n"
718 " pop rcx\n"
719 " pop r8\n"
720 " pop r9\n"
721 " pop r14\n"
722 " pop r15\n"
723 " leave\n"
724 "\n"
725 "%%elifdef RT_ARCH_X86\n"
726 " push ebp\n"
727 " mov ebp, esp\n"
728 " push eax\n"
729 " push ecx\n"
730 " push edx\n"
731 " and esp, 0fffffff0h\n"
732 "\n"
733 ".loaded:\n"
734 " call LazyLoading ; returns handle in ecx\n"
735 " push dword [ebp + 8] ; value addr\n"
736 " push dword [ebp + 12] ; symbol name\n"
737 " push ecx\n"
738 " %%ifdef IN_RT_R3\n"
739 " call NAME(RTLdrGetSymbol)\n"
740 " %%else\n"
741 " call IMP2(RTLdrGetSymbol)\n"
742 " %%endif\n"
743 " or eax, eax\n"
744 " jnz .badsym\n"
745 " lea esp, [ebp - 0ch]\n"
746 " pop edx\n"
747 " pop ecx\n"
748 " pop eax\n"
749 " leave\n"
750 "%%else\n"
751 " %%error \"Unsupported architecture\"\n"
752 "%%endif\n"
753 " ret\n"
754 "\n"
755 ".badsym:\n"
756 "%%ifdef ASM_CALL64_GCC\n"
757 " mov ecx, eax\n"
758 " lea rdx, [g_szLibrary wrt rip]\n"
759 " mov rsi, r15\n"
760 " lea rdi, [g_szFailResolveFmt wrt rip]\n"
761 " sub rsp, 08h\n"
762 "%%elifdef ASM_CALL64_MSC\n"
763 " mov r9d, eax\n"
764 " mov r8, r15\n"
765 " lea rdx, [g_szLibrary wrt rip]\n"
766 " lea rcx, [g_szFailResolveFmt wrt rip]\n"
767 " sub rsp, 28h\n"
768 "%%elifdef RT_ARCH_X86\n"
769 " push eax\n"
770 " push dword [ebp + 12]\n"
771 " push g_szLibrary\n"
772 " push g_szFailResolveFmt\n"
773 "%%endif\n"
774 "%%ifdef IN_RT_R3\n"
775 " call NAME(RTAssertMsg2Weak)\n"
776 "%%else\n"
777 " call IMP2(RTAssertMsg2Weak)\n"
778 "%%endif\n"
779 ".badsymloop:\n"
780 " int3\n"
781 " jmp .badsymloop\n"
782 "\n"
783 "LazyLoadResolver_End:\n"
784 "\n"
785 "\n"
786 );
787
788
789
790 /*
791 * C callable method for explicitly loading the library and optionally
792 * resolving all the imports.
793 */
794 if (g_fWithExplictLoadFunction)
795 {
796 if (g_fSystemLibrary) /* Lazy bird. */
797 {
798 fprintf(stderr, "error: cannot use --system with --explicit-load-function, sorry\n");
799 return RTEXITCODE_FAILURE;
800 }
801
802 int cchLibBaseName = (int)(strchr(g_pszLibrary, '.') ? strchr(g_pszLibrary, '.') - g_pszLibrary : strlen(g_pszLibrary));
803 fprintf(pOutput,
804 ";;\n"
805 "; ExplicitlyLoad%.*s(bool fResolveAllImports, pErrInfo);\n"
806 ";\n"
807 "EXTERN_IMP2 RTErrInfoSet\n"
808 "BEGINCODE\n"
809 "BEGINPROC ExplicitlyLoad%.*s\n"
810 " push xBP\n"
811 " mov xBP, xSP\n"
812 " push xBX\n"
813 "%%ifdef ASM_CALL64_GCC\n"
814 " %%define pszCurStr r14\n"
815 " push r14\n"
816 "%%else\n"
817 " %%define pszCurStr xDI\n"
818 " push xDI\n"
819 "%%endif\n"
820 " sub xSP, 40h\n"
821 "\n"
822 " ;\n"
823 " ; Save parameters on stack (64-bit only).\n"
824 " ;\n"
825 "%%ifdef ASM_CALL64_GCC\n"
826 " mov [xBP - xCB * 3], rdi ; fResolveAllImports\n"
827 " mov [xBP - xCB * 4], rsi ; pErrInfo\n"
828 "%%elifdef ASM_CALL64_MSC\n"
829 " mov [xBP - xCB * 3], rcx ; fResolveAllImports\n"
830 " mov [xBP - xCB * 4], rdx ; pErrInfo\n"
831 "%%endif\n"
832 "\n"
833 " ;\n"
834 " ; Is the module already loaded?\n"
835 " ;\n"
836 " cmp RTCCPTR_PRE [g_hMod xWrtRIP], 0\n"
837 " jnz .loaded\n"
838 "\n"
839 " ;\n"
840 " ; Load the module.\n"
841 " ;\n"
842 "%%ifdef ASM_CALL64_GCC\n"
843 " mov rcx, [xBP - xCB * 4] ; pErrInfo\n"
844 " xor rdx, rdx ; fFlags (local load)\n"
845 " lea rsi, [g_hMod wrt rip] ; phLdrMod\n"
846 " lea rdi, [g_szLibrary wrt rip] ; pszFilename\n"
847 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
848 "\n"
849 "%%elifdef ASM_CALL64_MSC\n"
850 " mov r9, [xBP - xCB * 4] ; pErrInfo\n"
851 " xor r8, r8 ; fFlags (local load)\n"
852 " lea rdx, [g_hMod wrt rip] ; phLdrMod\n"
853 " lea rcx, [g_szLibrary wrt rip] ; pszFilename\n"
854 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
855 "\n"
856 "%%elifdef RT_ARCH_X86\n"
857 " sub xSP, 0ch\n"
858 " push dword [xBP + 12] ; pErrInfo\n"
859 " push 0 ; fFlags (local load)\n"
860 " push g_hMod ; phLdrMod\n"
861 " push g_szLibrary ; pszFilename\n"
862 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
863 " add esp, 1ch\n"
864 "%%else\n"
865 " %%error \"Unsupported architecture\"\n"
866 "%%endif\n"
867 " or eax, eax\n"
868 " jnz .return\n"
869 "\n"
870 " ;\n"
871 " ; Resolve the imports too if requested to do so.\n"
872 " ;\n"
873 ".loaded:\n"
874 "%%ifdef ASM_ARCH_X86\n"
875 " cmp byte [xBP + 8], 0\n"
876 "%%else\n"
877 " cmp byte [xBP - xCB * 3], 0\n"
878 "%%endif\n"
879 " je .return\n"
880 "\n"
881 " lea pszCurStr, [g_szzNames xWrtRIP]\n"
882 " lea xBX, [g_apfnImports xWrtRIP]\n"
883 ".next_import:\n"
884 " cmp RTCCPTR_PRE [xBX], 0\n"
885 " je .return\n"
886 "%%ifdef ASM_CALL64_GCC\n"
887 " mov rdx, xBX ; ppvValue\n"
888 " mov rsi, pszCurStr ; pszSymbol\n"
889 " mov rdi, [g_hMod wrt rip] ; hLdrMod\n"
890 " call IMP2(RTLdrGetSymbol)\n"
891 "%%elifdef ASM_CALL64_MSC\n"
892 " mov r8, xBX ; ppvValue\n"
893 " mov rdx, pszCurStr ; pszSymbol\n"
894 " mov rcx, [g_hMod wrt rip] ; pszSymbol\n"
895 " call IMP2(RTLdrGetSymbol)\n"
896 "%%else\n"
897 " push xBX ; ppvValue\n"
898 " push pszCurStr ; pszSymbol\n"
899 " push RTCCPTR_PRE [g_hMod] ; hLdrMod\n"
900 " call IMP2(RTLdrGetSymbol)\n"
901 " add xSP, 0ch\n"
902 "%%endif\n"
903 " or eax, eax\n"
904 " jnz .symbol_error\n"
905 "\n"
906 " ; Advance.\n"
907 " add xBX, RTCCPTR_CB\n"
908 " xor eax, eax\n"
909 " mov xCX, 0ffffffffh\n"
910 "%%ifdef ASM_CALL64_GCC\n"
911 " mov xDI, pszCurStr\n"
912 " repne scasb\n"
913 " mov pszCurStr, xDI\n"
914 "%%else\n"
915 " repne scasb\n"
916 "%%endif\n"
917 " jmp .next_import\n"
918 "\n"
919 " ;\n"
920 " ; Error loading a symbol. Call RTErrInfoSet on pErrInfo (preserves eax).\n"
921 " ;\n"
922 ".symbol_error:\n"
923 "%%ifdef ASM_CALL64_GCC\n"
924 " mov rdx, pszCurStr ; pszMsg\n"
925 " mov esi, eax ; rc\n"
926 " mov rdi, [xBP - xCB * 4] ; pErrInfo\n"
927 " call IMP2(RTErrInfoSet)\n"
928 "%%elifdef ASM_CALL64_MSC\n"
929 " mov r8, pszCurStr ; pszMsg\n"
930 " mov edx, eax ; rc\n"
931 " mov rcx, [xBP - xCB * 4] ; pErrInfo\n"
932 " call IMP2(RTErrInfoSet)\n"
933 "%%else\n"
934 " push pszCurStr ; pszMsg\n"
935 " push eax ; pszSymbol\n"
936 " push dword [xBP + 0ch] ; pErrInfo\n"
937 " call IMP2(RTErrInfoSet)\n"
938 " add xSP, 0ch\n"
939 "%%endif\n"
940 " "
941 "\n"
942 ".return:\n"
943 " mov pszCurStr, [xBP - xCB * 2]\n"
944 " mov xBX, [xBP - xCB * 1]\n"
945 " leave\n"
946 " ret\n"
947 "ENDPROC ExplicitlyLoad%.*s\n"
948 "\n"
949 "\n"
950 ,
951 cchLibBaseName, g_pszLibrary,
952 cchLibBaseName, g_pszLibrary,
953 cchLibBaseName, g_pszLibrary
954 );
955 }
956
957
958 return RTEXITCODE_SUCCESS;
959}
960
961
962/**
963 * Generates the assembly source code, writing it to g_pszOutput.
964 *
965 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
966 * details has been displayed.
967 */
968static RTEXITCODE generateOutput(void)
969{
970 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
971 FILE *pOutput = fopen(g_pszOutput, "w");
972 if (pOutput)
973 {
974 rcExit = generateOutputInner(pOutput);
975 if (fclose(pOutput))
976 {
977 fprintf(stderr, "error: Error closing '%s'.\n", g_pszOutput);
978 rcExit = RTEXITCODE_FAILURE;
979 }
980 }
981 else
982 fprintf(stderr, "error: Failed to open '%s' for writing.\n", g_pszOutput);
983 return rcExit;
984}
985
986
987/**
988 * Displays usage information.
989 *
990 * @returns RTEXITCODE_SUCCESS.
991 * @param pszArgv0 The argv[0] string.
992 */
993static int usage(const char *pszArgv0)
994{
995 printf("usage: %s [options] --libary <loadname> --output <lazyload.asm> <input.def>\n"
996 "\n"
997 "Options:\n"
998 " --explicit-load-function, --no-explicit-load-function\n"
999 " Whether to include the explicit load function, default is not to.\n"
1000 "\n"
1001 "Copyright (C) 2013-2015 Oracle Corporation\n"
1002 , pszArgv0);
1003
1004 return RTEXITCODE_SUCCESS;
1005}
1006
1007
1008int main(int argc, char **argv)
1009{
1010 /*
1011 * Parse options.
1012 */
1013 for (int i = 1; i < argc; i++)
1014 {
1015 const char *psz = argv[i];
1016 if (*psz == '-')
1017 {
1018 if (!strcmp(psz, "--output") || !strcmp(psz, "-o"))
1019 {
1020 if (++i >= argc)
1021 {
1022 fprintf(stderr, "syntax error: File name expected after '%s'.\n", psz);
1023 return RTEXITCODE_SYNTAX;
1024 }
1025 g_pszOutput = argv[i];
1026 }
1027 else if (!strcmp(psz, "--library") || !strcmp(psz, "-l"))
1028 {
1029 if (++i >= argc)
1030 {
1031 fprintf(stderr, "syntax error: Library name expected after '%s'.\n", psz);
1032 return RTEXITCODE_SYNTAX;
1033 }
1034 g_pszLibrary = argv[i];
1035 }
1036 else if (!strcmp(psz, "--explicit-load-function"))
1037 g_fWithExplictLoadFunction = true;
1038 else if (!strcmp(psz, "--no-explicit-load-function"))
1039 g_fWithExplictLoadFunction = false;
1040 else if (!strcmp(psz, "--system"))
1041 g_fSystemLibrary = true;
1042 /** @todo Support different load methods so this can be used on system libs and
1043 * such if we like. */
1044 else if ( !strcmp(psz, "--help")
1045 || !strcmp(psz, "-help")
1046 || !strcmp(psz, "-h")
1047 || !strcmp(psz, "-?") )
1048 return usage(argv[0]);
1049 else if ( !strcmp(psz, "--version")
1050 || !strcmp(psz, "-V"))
1051 {
1052 printf("$Revision: 59404 $\n");
1053 return RTEXITCODE_SUCCESS;
1054 }
1055 else
1056 {
1057 fprintf(stderr, "syntax error: Unknown option '%s'.\n", psz);
1058 return RTEXITCODE_SYNTAX;
1059 }
1060 }
1061 else
1062 {
1063 if (g_cInputs >= RT_ELEMENTS(g_apszInputs))
1064 {
1065 fprintf(stderr, "syntax error: Too many input files, max is %d.\n", (int)RT_ELEMENTS(g_apszInputs));
1066 return RTEXITCODE_SYNTAX;
1067 }
1068 g_apszInputs[g_cInputs++] = argv[i];
1069 }
1070 }
1071 if (g_cInputs == 0)
1072 {
1073 fprintf(stderr, "syntax error: No input file specified.\n");
1074 return RTEXITCODE_SYNTAX;
1075 }
1076 if (!g_pszOutput)
1077 {
1078 fprintf(stderr, "syntax error: No output file specified.\n");
1079 return RTEXITCODE_SYNTAX;
1080 }
1081 if (!g_pszLibrary)
1082 {
1083 fprintf(stderr, "syntax error: No library name specified.\n");
1084 return RTEXITCODE_SYNTAX;
1085 }
1086
1087 /*
1088 * Do the job.
1089 */
1090 RTEXITCODE rcExit = parseInputs();
1091 if (rcExit == RTEXITCODE_SUCCESS)
1092 rcExit = generateOutput();
1093 return rcExit;
1094}
1095
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette