VirtualBox

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

Last change on this file since 57444 was 57353, checked in by vboxsync, 9 years ago

scm: Added fixing of flower boxes marking sections in C/C++ source file, like 'Header Files' and 'Defined Constants And Macros'. Applied it to the bldprogs.

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