VirtualBox

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

Last change on this file since 74094 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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