VirtualBox

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

Last change on this file since 53738 was 53738, checked in by vboxsync, 10 years ago

32-bit build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.9 KB
Line 
1/* $Id: VBoxDef2LazyLoad.cpp 53738 2015-01-05 14:50:31Z vboxsync $ */
2/** @file
3 * VBoxDef2LazyLoad - Lazy Library Loader Generator.
4 *
5 * @note Only tested on win.amd64.
6 */
7
8/*
9 * Copyright (C) 2013 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* Header Files *
22*******************************************************************************/
23#include <ctype.h>
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#include <iprt/types.h>
28
29
30/*******************************************************************************
31* Structures and Typedefs *
32*******************************************************************************/
33typedef struct MYEXPORT
34{
35 struct MYEXPORT *pNext;
36 bool fNoName;
37 unsigned uOrdinal;
38 char szName[1];
39} MYEXPORT;
40typedef MYEXPORT *PMYEXPORT;
41
42
43
44/*******************************************************************************
45* Global Variables *
46*******************************************************************************/
47/** @name Options
48 * @{ */
49static const char *g_pszOutput = NULL;
50static const char *g_pszLibrary = NULL;
51static const char *g_apszInputs[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
52static unsigned g_cInputs = 0;
53static bool g_fIgnoreData = true;
54static bool g_fWithExplictLoadFunction = false;
55/** @} */
56
57/** Pointer to the export name list head. */
58static PMYEXPORT g_pExpHead = NULL;
59/** Pointer to the next pointer for insertion. */
60static PMYEXPORT *g_ppExpNext = &g_pExpHead;
61
62
63
64static const char *leftStrip(const char *psz)
65{
66 while (isspace(*psz))
67 psz++;
68 return psz;
69}
70
71
72static char *leftStrip(char *psz)
73{
74 while (isspace(*psz))
75 psz++;
76 return psz;
77}
78
79
80static unsigned wordLength(const char *pszWord)
81{
82 unsigned off = 0;
83 char ch;
84 while ( (ch = pszWord[off]) != '\0'
85 && ch != '='
86 && ch != ','
87 && ch != ':'
88 && !isspace(ch) )
89 off++;
90 return off;
91}
92
93
94/**
95 * Parses the module definition file, collecting export information.
96 *
97 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
98 * details has been displayed.
99 * @param pInput The input stream.
100 */
101static RTEXITCODE parseInputInner(FILE *pInput, const char *pszInput)
102{
103 /*
104 * Process the file line-by-line.
105 */
106 bool fInExports = false;
107 unsigned iLine = 0;
108 char szLine[16384];
109 while (fgets(szLine, sizeof(szLine), pInput))
110 {
111 iLine++;
112
113 /*
114 * Strip leading and trailing spaces from the line as well as
115 * trailing comments.
116 */
117 char *psz = leftStrip(szLine);
118 if (*psz == ';')
119 continue; /* comment line. */
120
121 char *pszComment = strchr(psz, ';');
122 if (pszComment)
123 *pszComment = '\0';
124
125 unsigned cch = (unsigned)strlen(psz);
126 while (cch > 0 && (isspace(psz[cch - 1]) || psz[cch - 1] == '\r' || psz[cch - 1] == '\n'))
127 psz[--cch] = '\0';
128
129 if (!cch)
130 continue;
131
132 /*
133 * Check for known directives.
134 */
135 size_t cchWord0 = wordLength(psz);
136#define WORD_CMP(pszWord1, cchWord1, szWord2) \
137 ( (cchWord1) == sizeof(szWord2) - 1 && memcmp(pszWord1, szWord2, sizeof(szWord2) - 1) == 0 )
138 if (WORD_CMP(psz, cchWord0, "EXPORTS"))
139 {
140 fInExports = true;
141
142 /* In case there is an export on the same line. (Really allowed?) */
143 psz = leftStrip(psz + sizeof("EXPORTS") - 1);
144 if (!*psz)
145 continue;
146 }
147 /* Directives that we don't care about, but need to catch in order to
148 terminate the EXPORTS section in a timely manner. */
149 else if ( WORD_CMP(psz, cchWord0, "NAME")
150 || WORD_CMP(psz, cchWord0, "LIBRARY")
151 || WORD_CMP(psz, cchWord0, "DESCRIPTION")
152 || WORD_CMP(psz, cchWord0, "STACKSIZE")
153 || WORD_CMP(psz, cchWord0, "SECTIONS")
154 || WORD_CMP(psz, cchWord0, "SEGMENTS")
155 || WORD_CMP(psz, cchWord0, "VERSION")
156 )
157 {
158 fInExports = false;
159 }
160
161 /*
162 * Process exports:
163 * entryname[=internalname] [@ordinal[ ][NONAME]] [DATA] [PRIVATE]
164 */
165 if (fInExports)
166 {
167 const char *pchName = psz;
168 unsigned cchName = wordLength(psz);
169
170 psz = leftStrip(psz + cchName);
171 if (*psz == '=')
172 {
173 psz = leftStrip(psz + 1);
174 psz = leftStrip(psz + wordLength(psz));
175 }
176
177 bool fNoName = true;
178 unsigned uOrdinal = ~0U;
179 if (*psz == '@')
180 {
181 psz++;
182 if (!isdigit(*psz))
183 {
184 fprintf(stderr, "%s:%u: error: Invalid ordinal spec.\n", pszInput, iLine);
185 return RTEXITCODE_FAILURE;
186 }
187 uOrdinal = *psz++ - '0';
188 while (isdigit(*psz))
189 {
190 uOrdinal *= 10;
191 uOrdinal += *psz++ - '0';
192 }
193 psz = leftStrip(psz);
194 cch = wordLength(psz);
195 if (WORD_CMP(psz, cch, "NONAME"))
196 {
197#if 0
198 fNoName = true;
199 psz = leftStrip(psz + cch);
200#else
201 fprintf(stderr, "%s:%u: error: NONAME export not implemented.\n", pszInput, iLine);
202 return RTEXITCODE_FAILURE;
203#endif
204 }
205 }
206
207 while (*psz)
208 {
209 cch = wordLength(psz);
210 if (WORD_CMP(psz, cch, "DATA"))
211 {
212 if (!g_fIgnoreData)
213 {
214 fprintf(stderr, "%s:%u: error: Cannot wrap up DATA export '%.*s'.\n",
215 pszInput, iLine, cchName, pchName);
216 return RTEXITCODE_SUCCESS;
217 }
218 }
219 else if (!WORD_CMP(psz, cch, "PRIVATE"))
220 {
221 fprintf(stderr, "%s:%u: error: Cannot wrap up DATA export '%.*s'.\n",
222 pszInput, iLine, cchName, pchName);
223 return RTEXITCODE_SUCCESS;
224 }
225 psz = leftStrip(psz + cch);
226 }
227
228 /*
229 * Add the export.
230 */
231 PMYEXPORT pExp = (PMYEXPORT)malloc(sizeof(*pExp) + cchName);
232 if (!pExp)
233 {
234 fprintf(stderr, "%s:%u: error: Out of memory.\n", pszInput, iLine);
235 return RTEXITCODE_SUCCESS;
236 }
237 memcpy(pExp->szName, pchName, cchName);
238 pExp->szName[cchName] = '\0';
239 pExp->uOrdinal = uOrdinal;
240 pExp->fNoName = fNoName;
241 pExp->pNext = NULL;
242 *g_ppExpNext = pExp;
243 g_ppExpNext = &pExp->pNext;
244 }
245 }
246
247 /*
248 * Why did we quit the loop, EOF or error?
249 */
250 if (feof(pInput))
251 return RTEXITCODE_SUCCESS;
252 fprintf(stderr, "error: Read while reading '%s' (iLine=%u).\n", pszInput, iLine);
253 return RTEXITCODE_FAILURE;
254}
255
256
257/**
258 * Parses a_apszInputs, populating the list pointed to by g_pExpHead.
259 *
260 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
261 * details has been displayed.
262 */
263static RTEXITCODE parseInputs(void)
264{
265 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
266 for (unsigned i = 0; i < g_cInputs; i++)
267 {
268 FILE *pInput = fopen(g_apszInputs[i], "r");
269 if (pInput)
270 {
271 RTEXITCODE rcExit2 = parseInputInner(pInput, g_apszInputs[i]);
272 fclose(pInput);
273 if (rcExit2 == RTEXITCODE_SUCCESS && !g_pExpHead)
274 {
275 fprintf(stderr, "error: Found no exports in '%s'.\n", g_apszInputs[i]);
276 rcExit2 = RTEXITCODE_FAILURE;
277 }
278 if (rcExit2 != RTEXITCODE_SUCCESS)
279 rcExit = rcExit2;
280 }
281 else
282 {
283 fprintf(stderr, "error: Failed to open '%s' for reading.\n", g_apszInputs[i]);
284 rcExit = RTEXITCODE_FAILURE;
285 }
286 }
287 return rcExit;
288}
289
290
291/**
292 * Generates the assembly source code, writing it to @a pOutput.
293 *
294 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
295 * details has been displayed.
296 * @param pOutput The output stream (caller checks it for errors
297 * when closing).
298 */
299static RTEXITCODE generateOutputInner(FILE *pOutput)
300{
301 fprintf(pOutput, ";;\n");
302 for (unsigned i = 0; i < g_cInputs; i++)
303 fprintf(pOutput, ";; Autogenerated from '%s'.\n", g_apszInputs[i]);
304
305 fprintf(pOutput,
306 ";; DO NOT EDIT!\n"
307 ";;\n"
308 "\n"
309 "\n"
310 "%%include \"iprt/asmdefs.mac\"\n"
311 "\n"
312 "\n");
313
314 /*
315 * Put the thunks first for alignment and other reasons. It's the hot part of the code.
316 */
317 fprintf(pOutput,
318 ";\n"
319 "; Thunks.\n"
320 ";\n"
321 "BEGINCODE\n");
322 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
323 fprintf(pOutput,
324 "BEGINPROC %s\n"
325 " jmp RTCCPTR_PRE [g_pfn%s xWrtRIP]\n"
326 "ENDPROC %s\n",
327 pExp->szName,
328 pExp->szName,
329 pExp->szName);
330 fprintf(pOutput,
331 "\n"
332 "\n");
333
334 /*
335 * Import pointers
336 */
337 fprintf(pOutput,
338 ";\n"
339 "; Import pointers. Initialized to point a lazy loading stubs.\n"
340 ";\n"
341 "BEGINDATA\n"
342 "g_apfnImports:\n");
343 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
344 fprintf(pOutput,
345 "%%ifdef ASM_FORMAT_PE\n"
346 "global __imp_%s\n"
347 "__imp_%s:\n"
348 "%%endif\n"
349 "g_pfn%s RTCCPTR_DEF ___LazyLoad___%s\n",
350 pExp->szName,
351 pExp->szName,
352 pExp->szName,
353 pExp->szName);
354 fprintf(pOutput,
355 "RTCCPTR_DEF 0 ; Terminator entry for traversal.\n"
356 "\n"
357 "\n");
358
359 /*
360 * Now for the less important stuff, starting with the names.
361 *
362 * We keep the names separate so we can traverse them in parallel to
363 * g_apfnImports in the load-everything routine further down.
364 */
365 fprintf(pOutput,
366 ";\n"
367 "; Imported names.\n"
368 ";\n"
369 "BEGINCODE\n"
370 "g_szLibrary db '%s',0\n"
371 "g_szzNames:\n",
372 g_pszLibrary);
373 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
374 fprintf(pOutput, "g_sz%s: db '%s',0\n", pExp->szName, pExp->szName);
375 fprintf(pOutput,
376 "g_EndOfNames: db 0\n"
377 "\n"
378 "\n");
379
380 /*
381 * The per import lazy load code.
382 */
383 fprintf(pOutput,
384 ";\n"
385 "; Lazy load+resolve stubs.\n"
386 ";\n"
387 "BEGINCODE\n");
388 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
389 fprintf(pOutput,
390 "___LazyLoad___%s:\n"
391 /* "int3\n" */
392 "%%ifdef RT_ARCH_AMD64\n"
393 " lea rax, [g_sz%s wrt rip]\n"
394 " lea r10, [g_pfn%s wrt rip]\n"
395 "%%elifdef RT_ARCH_X86\n"
396 " push g_sz%s\n"
397 " push g_pfn%s\n"
398 "%%else\n"
399 " %%error \"Unsupported architecture\"\n"
400 "%%endif\n"
401 " call NAME(LazyLoadResolver)\n"
402 "%%ifdef RT_ARCH_X86\n"
403 " add esp, 8h\n"
404 "%%endif\n"
405 " jmp NAME(%s)\n"
406 "\n"
407 ,
408 pExp->szName,
409 pExp->szName,
410 pExp->szName,
411 pExp->szName,
412 pExp->szName,
413 pExp->szName);
414 fprintf(pOutput,
415 "\n"
416 "\n"
417 "\n");
418
419 /*
420 * The code that does the loading and resolving.
421 */
422 fprintf(pOutput,
423 ";\n"
424 "; The module handle.\n"
425 ";\n"
426 "BEGINDATA\n"
427 "g_hMod RTCCPTR_DEF 0\n"
428 "\n"
429 "\n"
430 "\n");
431
432 /*
433 * How we load the module needs to be selectable later on.
434 *
435 * The LazyLoading routine returns the module handle in RCX/ECX, caller
436 * saved all necessary registers.
437 */
438 fprintf(pOutput,
439 ";\n"
440 ";SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod,\n"
441 "; uint32_t fFlags, PRTERRINFO pErrInfo);\n"
442 ";\n"
443 "EXTERN_IMP2 SUPR3HardenedLdrLoadAppPriv\n"
444 "BEGINCODE\n"
445 "\n"
446 "BEGINPROC LazyLoading\n"
447 " mov xCX, [g_hMod xWrtRIP]\n"
448 " or xCX, xCX\n"
449 " jnz .return\n"
450 "\n"
451 "%%ifdef ASM_CALL64_GCC\n"
452 " xor rcx, rcx ; pErrInfo\n"
453 " xor rdx, rdx ; fFlags (local load)\n"
454 " lea rsi, [g_hMod wrt rip] ; phLdrMod\n"
455 " lea rdi, [g_szLibrary wrt rip] ; pszFilename\n"
456 " sub rsp, 08h\n"
457 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
458 " add rsp, 08h\n"
459 "\n"
460 "%%elifdef ASM_CALL64_MSC\n"
461 " xor r9, r9 ; pErrInfo\n"
462 " xor r8, r8 ; fFlags (local load)\n"
463 " lea rdx, [g_hMod wrt rip] ; phLdrMod\n"
464 " lea rcx, [g_szLibrary wrt rip] ; pszFilename\n"
465 " sub rsp, 28h\n"
466 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
467 " add rsp, 28h\n"
468 "\n"
469 "%%elifdef RT_ARCH_X86\n"
470 " sub xSP, 0ch\n"
471 " push 0 ; pErrInfo\n"
472 " push 0 ; fFlags (local load)\n"
473 " push g_hMod ; phLdrMod\n"
474 " push g_szLibrary ; pszFilename\n"
475 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
476 " add esp, 1ch\n"
477 "%%else\n"
478 " %%error \"Unsupported architecture\"\n"
479 "%%endif\n"
480 " or eax, eax\n"
481 " jz .loadok\n"
482 ".badload:\n"
483 " int3\n"
484 " jmp .badload\n"
485 ".loadok:\n"
486 " mov xCX, [g_hMod xWrtRIP]\n"
487 ".return:\n"
488 " ret\n"
489 "ENDPROC LazyLoading\n"
490 "\n"
491 "\n");
492
493
494 fprintf(pOutput,
495 ";\n"
496 ";RTDECL(int) RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvValue);\n"
497 ";\n"
498 "EXTERN_IMP2 RTLdrGetSymbol\n"
499 "BEGINCODE\n"
500 "BEGINPROC LazyLoadResolver\n"
501 "%%ifdef RT_ARCH_AMD64\n"
502 " push rbp\n"
503 " mov rbp, rsp\n"
504 " push r15\n"
505 " push r14\n"
506 " mov r15, rax ; name\n"
507 " mov r14, r10 ; ppfn\n"
508 " push r9\n"
509 " push r8\n"
510 " push rcx\n"
511 " push rdx\n"
512 " push r12\n"
513 " %%ifdef ASM_CALL64_GCC\n"
514 " push rsi\n"
515 " push rdi\n"
516 " mov r12, rsp\n"
517 " %%else\n"
518 " mov r12, rsp\n"
519 " sub rsp, 20h\n"
520 " %%endif\n"
521 " and rsp, 0fffffff0h ; Try make sure the stack is aligned\n"
522 "\n"
523 " call NAME(LazyLoading) ; returns handle in rcx\n"
524 " %%ifdef ASM_CALL64_GCC\n"
525 " mov rdi, rcx ; hLdrMod\n"
526 " mov rsi, r15 ; pszSymbol\n"
527 " mov rdx, r14 ; ppvValue\n"
528 " %%else\n"
529 " mov rdx, r15 ; pszSymbol\n"
530 " mov r8, r14 ; ppvValue\n"
531 " %%endif\n"
532 " call IMP2(RTLdrGetSymbol)\n"
533 " or eax, eax\n"
534 " jz .symok\n"
535 ".badsym:\n"
536 " int3\n"
537 " jmp .badsym\n"
538 ".symok:\n"
539 "\n"
540 " mov rsp, r12\n"
541 " %%ifdef ASM_CALL64_GCC\n"
542 " pop rdi\n"
543 " pop rsi\n"
544 " %%endif\n"
545 " pop r12\n"
546 " pop rdx\n"
547 " pop rcx\n"
548 " pop r8\n"
549 " pop r9\n"
550 " pop r14\n"
551 " pop r15\n"
552 " leave\n"
553 "\n"
554 "%%elifdef RT_ARCH_X86\n"
555 " push ebp\n"
556 " mov ebp, esp\n"
557 " push eax\n"
558 " push ecx\n"
559 " push edx\n"
560 " and esp, 0fffffff0h\n"
561 "\n"
562 ".loaded:\n"
563 " mov eax, [ebp + 4] ; value addr\n"
564 " push eax\n"
565 " mov edx, [ebp + 8] ; symbol name\n"
566 " push edx\n"
567 " call NAME(LazyLoading) ; returns handle in ecx\n"
568 " mov ecx, [g_hMod]\n"
569 " call IMP2(RTLdrGetSymbol)\n"
570 " or eax, eax\n"
571 " jz .symok\n"
572 ".badsym:\n"
573 " int3\n"
574 " jmp .badsym\n"
575 ".symok:\n"
576 " lea esp, [ebp - 0ch]\n"
577 " pop edx\n"
578 " pop ecx\n"
579 " pop eax\n"
580 " leave\n"
581 "%%else\n"
582 " %%error \"Unsupported architecture\"\n"
583 "%%endif\n"
584 " ret\n"
585 "ENDPROC LazyLoadResolver\n"
586 "\n"
587 "\n"
588 );
589
590
591
592 /*
593 * C callable method for explicitly loading the library and optionally
594 * resolving all the imports.
595 */
596 if (g_fWithExplictLoadFunction)
597 {
598 int cchLibBaseName = (int)(strchr(g_pszLibrary, '.') ? strchr(g_pszLibrary, '.') - g_pszLibrary : strlen(g_pszLibrary));
599 fprintf(pOutput,
600 ";;\n"
601 "; ExplicitlyLoad%.*s(bool fResolveAllImports, pErrInfo);\n"
602 ";\n"
603 "EXTERN_IMP2 RTErrInfoSet\n"
604 "BEGINCODE\n"
605 "BEGINPROC ExplicitlyLoad%.*s\n"
606 " push xBP\n"
607 " mov xBP, xSP\n"
608 " push xBX\n"
609 "%%ifdef ASM_CALL64_GCC\n"
610 " %%define pszCurStr r14\n"
611 " push r14\n"
612 "%%else\n"
613 " %%define pszCurStr xDI\n"
614 " push xDI\n"
615 "%%endif\n"
616 " sub xSP, 40h\n"
617 "\n"
618 " ;\n"
619 " ; Save parameters on stack (64-bit only).\n"
620 " ;\n"
621 "%%ifdef ASM_CALL64_GCC\n"
622 " mov [xBP - xCB * 3], rdi ; fResolveAllImports\n"
623 " mov [xBP - xCB * 4], rsi ; pErrInfo\n"
624 "%%elifdef ASM_CALL64_MSC\n"
625 " mov [xBP - xCB * 3], rcx ; fResolveAllImports\n"
626 " mov [xBP - xCB * 4], rdx ; pErrInfo\n"
627 "%%endif\n"
628 "\n"
629 " ;\n"
630 " ; Is the module already loaded?\n"
631 " ;\n"
632 " cmp RTCCPTR_PRE [g_hMod xWrtRIP], 0\n"
633 " jnz .loaded\n"
634 "\n"
635 " ;\n"
636 " ; Load the module.\n"
637 " ;\n"
638 "%%ifdef ASM_CALL64_GCC\n"
639 " mov rcx, [xBP - xCB * 4] ; pErrInfo\n"
640 " xor rdx, rdx ; fFlags (local load)\n"
641 " lea rsi, [g_hMod wrt rip] ; phLdrMod\n"
642 " lea rdi, [g_szLibrary wrt rip] ; pszFilename\n"
643 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
644 "\n"
645 "%%elifdef ASM_CALL64_MSC\n"
646 " xor r9, [xBP - xCB * 4] ; pErrInfo\n"
647 " xor r8, r8 ; fFlags (local load)\n"
648 " lea rdx, [g_hMod wrt rip] ; phLdrMod\n"
649 " lea rcx, [g_szLibrary wrt rip] ; pszFilename\n"
650 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
651 "\n"
652 "%%elifdef RT_ARCH_X86\n"
653 " sub xSP, 0ch\n"
654 " push dword [xBP + 12] ; pErrInfo\n"
655 " push 0 ; fFlags (local load)\n"
656 " push g_hMod ; phLdrMod\n"
657 " push g_szLibrary ; pszFilename\n"
658 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
659 " add esp, 1ch\n"
660 "%%else\n"
661 " %%error \"Unsupported architecture\"\n"
662 "%%endif\n"
663 " or eax, eax\n"
664 " jnz .return\n"
665 "\n"
666 " ;\n"
667 " ; Resolve the imports too if requested to do so.\n"
668 " ;\n"
669 ".loaded:\n"
670 "%%ifdef ASM_ARCH_X86\n"
671 " cmp byte [xBP + 8], 0\n"
672 "%%else\n"
673 " cmp byte [xBP - xCB * 3], 0\n"
674 "%%endif\n"
675 " je .return\n"
676 "\n"
677 " lea pszCurStr, [g_szzNames xWrtRIP]\n"
678 " lea xBX, [g_apfnImports xWrtRIP]\n"
679 ".next_import:\n"
680 " cmp RTCCPTR_PRE [xBX], 0\n"
681 " je .return\n"
682 "%%ifdef ASM_CALL64_GCC\n"
683 " mov rdx, xBX ; ppvValue\n"
684 " mov rsi, pszCurStr ; pszSymbol\n"
685 " mov rdi, [g_hMod wrt rip] ; hLdrMod\n"
686 " call IMP2(RTLdrGetSymbol)\n"
687 "%%elifdef ASM_CALL64_MSC\n"
688 " mov r8, xBX ; ppvValue\n"
689 " mov rdx, pszCurStr ; pszSymbol\n"
690 " mov rcx, [g_hMod wrt rip] ; pszSymbol\n"
691 " call IMP2(RTLdrGetSymbol)\n"
692 "%%else\n"
693 " push xBX ; ppvValue\n"
694 " push pszCurStr ; pszSymbol\n"
695 " push RTCCPTR_PRE [g_hMod] ; hLdrMod\n"
696 " call IMP2(RTLdrGetSymbol)\n"
697 " add xSP, 0ch\n"
698 "%%endif\n"
699 " or eax, eax\n"
700 " jnz .symbol_error\n"
701 "\n"
702 " ; Advance.\n"
703 " add xBX, RTCCPTR_CB\n"
704 " xor eax, eax\n"
705 " mov xCX, 0ffffffffh\n"
706 "%%ifdef ASM_CALL64_GCC\n"
707 " mov xDI, pszCurStr\n"
708 " repne scasb\n"
709 " mov pszCurStr, xDI\n"
710 "%%else\n"
711 " repne scasb\n"
712 "%%endif\n"
713 " jmp .next_import\n"
714 "\n"
715 " ;\n"
716 " ; Error loading a symbol. Call RTErrInfoSet on pErrInfo (preserves eax).\n"
717 " ;\n"
718 ".symbol_error:\n"
719 "%%ifdef ASM_CALL64_GCC\n"
720 " mov rdx, pszCurStr ; pszMsg\n"
721 " mov esi, eax ; rc\n"
722 " mov rdi, [xBP - xCB * 4] ; pErrInfo\n"
723 " call IMP2(RTErrInfoSet)\n"
724 "%%elifdef ASM_CALL64_MSC\n"
725 " mov r8, pszCurStr ; pszMsg\n"
726 " mov edx, eax ; rc\n"
727 " mov rcx, [xBP - xCB * 4] ; pErrInfo\n"
728 " call IMP2(RTErrInfoSet)\n"
729 "%%else\n"
730 " push pszCurStr ; pszMsg\n"
731 " push eax ; pszSymbol\n"
732 " push dword [xBP + 0ch] ; pErrInfo\n"
733 " call IMP2(RTErrInfoSet)\n"
734 " add xSP, 0ch\n"
735 "%%endif\n"
736 " "
737 "\n"
738 ".return:\n"
739 " lea xSP, [xBP - xCB * 3]\n"
740 " pop pszCurStr\n"
741 " pop xBX\n"
742 " leave\n"
743 " ret\n"
744 "ENDPROC ExplicitlyLoad%.*s\n"
745 "\n"
746 "\n"
747 ,
748 cchLibBaseName, g_pszLibrary,
749 cchLibBaseName, g_pszLibrary,
750 cchLibBaseName, g_pszLibrary
751 );
752 }
753
754
755 return RTEXITCODE_SUCCESS;
756}
757
758
759/**
760 * Generates the assembly source code, writing it to g_pszOutput.
761 *
762 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
763 * details has been displayed.
764 */
765static RTEXITCODE generateOutput(void)
766{
767 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
768 FILE *pOutput = fopen(g_pszOutput, "w");
769 if (pOutput)
770 {
771 rcExit = generateOutputInner(pOutput);
772 if (fclose(pOutput))
773 {
774 fprintf(stderr, "error: Error closing '%s'.\n", g_pszOutput);
775 rcExit = RTEXITCODE_FAILURE;
776 }
777 }
778 else
779 fprintf(stderr, "error: Failed to open '%s' for writing.\n", g_pszOutput);
780 return rcExit;
781}
782
783
784/**
785 * Displays usage information.
786 *
787 * @returns RTEXITCODE_SUCCESS.
788 * @param pszArgv0 The argv[0] string.
789 */
790static int usage(const char *pszArgv0)
791{
792 printf("usage: %s [options] --libary <loadname> --output <lazyload.asm> <input.def>\n"
793 "\n"
794 "Options:\n"
795 " --explicit-load-function, --no-explicit-load-function\n"
796 " Whether to include the explicit load function, default is not to.\n"
797 "\n"
798 "Copyright (C) 2013-2015 Oracle Corporation\n"
799 , pszArgv0);
800
801 return RTEXITCODE_SUCCESS;
802}
803
804
805int main(int argc, char **argv)
806{
807 /*
808 * Parse options.
809 */
810 for (int i = 1; i < argc; i++)
811 {
812 const char *psz = argv[i];
813 if (*psz == '-')
814 {
815 if (!strcmp(psz, "--output") || !strcmp(psz, "-o"))
816 {
817 if (++i >= argc)
818 {
819 fprintf(stderr, "syntax error: File name expected after '%s'.\n", psz);
820 return RTEXITCODE_SYNTAX;
821 }
822 g_pszOutput = argv[i];
823 }
824 else if (!strcmp(psz, "--library") || !strcmp(psz, "-l"))
825 {
826 if (++i >= argc)
827 {
828 fprintf(stderr, "syntax error: Library name expected after '%s'.\n", psz);
829 return RTEXITCODE_SYNTAX;
830 }
831 g_pszLibrary = argv[i];
832 }
833 else if (!strcmp(psz, "--explicit-load-function"))
834 g_fWithExplictLoadFunction = true;
835 else if (!strcmp(psz, "--no-explicit-load-function"))
836 g_fWithExplictLoadFunction = false;
837 /** @todo Support different load methods so this can be used on system libs and
838 * such if we like. */
839 else if ( !strcmp(psz, "--help")
840 || !strcmp(psz, "-help")
841 || !strcmp(psz, "-h")
842 || !strcmp(psz, "-?") )
843 return usage(argv[0]);
844 else if ( !strcmp(psz, "--version")
845 || !strcmp(psz, "-V"))
846 {
847 printf("$Revision: 53738 $\n");
848 return RTEXITCODE_SUCCESS;
849 }
850 else
851 {
852 fprintf(stderr, "syntax error: Unknown option '%s'.\n", psz);
853 return RTEXITCODE_SYNTAX;
854 }
855 }
856 else
857 {
858 if (g_cInputs >= RT_ELEMENTS(g_apszInputs))
859 {
860 fprintf(stderr, "syntax error: Too many input files, max is %d.\n", (int)RT_ELEMENTS(g_apszInputs));
861 return RTEXITCODE_SYNTAX;
862 }
863 g_apszInputs[g_cInputs++] = argv[i];
864 }
865 }
866 if (g_cInputs == 0)
867 {
868 fprintf(stderr, "syntax error: No input file specified.\n");
869 return RTEXITCODE_SYNTAX;
870 }
871 if (!g_pszOutput)
872 {
873 fprintf(stderr, "syntax error: No output file specified.\n");
874 return RTEXITCODE_SYNTAX;
875 }
876 if (!g_pszLibrary)
877 {
878 fprintf(stderr, "syntax error: No library name specified.\n");
879 return RTEXITCODE_SYNTAX;
880 }
881
882 /*
883 * Do the job.
884 */
885 RTEXITCODE rcExit = parseInputs();
886 if (rcExit == RTEXITCODE_SUCCESS)
887 rcExit = generateOutput();
888 return rcExit;
889}
890
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