VirtualBox

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

最後變更 在這個檔案從100273是 100273,由 vboxsync 提交於 21 月 前

bldprogs/VBoxDef2LazyLoad: Include the executable file format of OS/2 to
be the Linear Executable (LX) format since it was accidentally omitted
from the list of OSes. Attempt at a follow-up build fix to r157968.
bugref:10457

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 67.6 KB
 
1/* $Id: VBoxDef2LazyLoad.cpp 100273 2023-06-23 17:01:59Z 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-2023 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.alldomusa.eu.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * SPDX-License-Identifier: GPL-3.0-only
28 */
29
30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
34#include <ctype.h>
35#include <stdio.h>
36#include <string.h>
37#include <stdlib.h>
38#include <iprt/types.h>
39#include <iprt/ldr.h> /* For RTLDRARCH. */
40
41
42/*********************************************************************************************************************************
43* Structures and Typedefs *
44*********************************************************************************************************************************/
45typedef struct MYEXPORT
46{
47 struct MYEXPORT *pNext;
48 /** Pointer to unmangled name for stdcall (after szName), NULL if not. */
49 char *pszUnstdcallName;
50 /** Pointer to the exported name. */
51 char const *pszExportedNm;
52 unsigned uOrdinal;
53 /** NONAME. */
54 bool fNoName;
55 /** DATA symbol if true, otherwise function. */
56 bool fData;
57 char szName[1];
58} MYEXPORT;
59typedef MYEXPORT *PMYEXPORT;
60
61
62/*********************************************************************************************************************************
63* Global Variables *
64*********************************************************************************************************************************/
65/** @name Options
66 * @{ */
67static const char *g_pszOutput = NULL;
68static const char *g_pszLibrary = NULL;
69static const char *g_apszInputs[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
70static unsigned g_cInputs = 0;
71static bool g_fIgnoreData = true;
72static bool g_fWithExplictLoadFunction = false;
73static bool g_fSystemLibrary = false;
74#if defined(RT_ARCH_AMD64)
75static RTLDRARCH g_enmTarget = RTLDRARCH_AMD64;
76#elif defined(RT_ARCH_X86)
77static RTLDRARCH g_enmTarget = RTLDRARCH_X86_32;
78#elif defined(RT_ARCH_ARM64)
79static RTLDRARCH g_enmTarget = RTLDRARCH_ARM64;
80#else
81# error "Port me!"
82#endif
83#if defined(RT_OS_DARWIN)
84static RTLDRFMT g_enmLdrFmt = RTLDRFMT_MACHO;
85#elif defined(RT_OS_WINDOWS)
86static RTLDRFMT g_enmLdrFmt = RTLDRFMT_PE;
87#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_SOLARIS) \
88 || defined(RT_OS_NETBSD) || defined(RT_OS_OPENBSD)
89static RTLDRFMT g_enmLdrFmt = RTLDRFMT_ELF;
90#elif defined(RT_OS_OS2)
91static RTLDRFMT g_enmLdrFmt = RTLDRFMT_LX;
92#else
93# error "Port me!"
94#endif
95/** @} */
96
97/** Pointer to the export name list head. */
98static PMYEXPORT g_pExpHead = NULL;
99/** Pointer to the next pointer for insertion. */
100static PMYEXPORT *g_ppExpNext = &g_pExpHead;
101
102
103
104#if 0 /* unused */
105static const char *leftStrip(const char *psz)
106{
107 while (isspace(*psz))
108 psz++;
109 return psz;
110}
111#endif
112
113
114static char *leftStrip(char *psz)
115{
116 while (isspace(*psz))
117 psz++;
118 return psz;
119}
120
121
122static unsigned wordLength(const char *pszWord)
123{
124 unsigned off = 0;
125 char ch;
126 while ( (ch = pszWord[off]) != '\0'
127 && ch != '='
128 && ch != ','
129 && ch != ':'
130 && !isspace(ch) )
131 off++;
132 return off;
133}
134
135
136/**
137 * Parses the module definition file, collecting export information.
138 *
139 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
140 * details has been displayed.
141 * @param pInput The input stream.
142 */
143static RTEXITCODE parseInputInner(FILE *pInput, const char *pszInput)
144{
145 /*
146 * Process the file line-by-line.
147 */
148 bool fInExports = false;
149 unsigned iLine = 0;
150 char szLine[16384];
151 while (fgets(szLine, sizeof(szLine), pInput))
152 {
153 iLine++;
154
155 /*
156 * Strip leading and trailing spaces from the line as well as
157 * trailing comments.
158 */
159 char *psz = leftStrip(szLine);
160 if (*psz == ';')
161 continue; /* comment line. */
162
163 char *pszComment = strchr(psz, ';');
164 if (pszComment)
165 *pszComment = '\0';
166
167 unsigned cch = (unsigned)strlen(psz);
168 while (cch > 0 && (isspace(psz[cch - 1]) || psz[cch - 1] == '\r' || psz[cch - 1] == '\n'))
169 psz[--cch] = '\0';
170
171 if (!cch)
172 continue;
173
174 /*
175 * Check for known directives.
176 */
177 size_t cchWord0 = wordLength(psz);
178#define WORD_CMP(pszWord1, cchWord1, szWord2) \
179 ( (cchWord1) == sizeof(szWord2) - 1 && memcmp(pszWord1, szWord2, sizeof(szWord2) - 1) == 0 )
180 if (WORD_CMP(psz, cchWord0, "EXPORTS"))
181 {
182 fInExports = true;
183
184 /* In case there is an export on the same line. (Really allowed?) */
185 psz = leftStrip(psz + sizeof("EXPORTS") - 1);
186 if (!*psz)
187 continue;
188 }
189 /* Directives that we don't care about, but need to catch in order to
190 terminate the EXPORTS section in a timely manner. */
191 else if ( WORD_CMP(psz, cchWord0, "NAME")
192 || WORD_CMP(psz, cchWord0, "LIBRARY")
193 || WORD_CMP(psz, cchWord0, "DESCRIPTION")
194 || WORD_CMP(psz, cchWord0, "STACKSIZE")
195 || WORD_CMP(psz, cchWord0, "SECTIONS")
196 || WORD_CMP(psz, cchWord0, "SEGMENTS")
197 || WORD_CMP(psz, cchWord0, "VERSION")
198 )
199 {
200 fInExports = false;
201 }
202
203 /*
204 * Process exports:
205 * entryname[=internalname] [@ordinal[ ][NONAME]] [DATA] [PRIVATE]
206 */
207 if (fInExports)
208 {
209 const char *pchName = psz;
210 unsigned cchName = wordLength(psz);
211
212 psz = leftStrip(psz + cchName);
213 if (*psz == '=')
214 {
215 psz = leftStrip(psz + 1);
216 psz = leftStrip(psz + wordLength(psz));
217 }
218
219 bool fNoName = false;
220 unsigned uOrdinal = ~0U;
221 if (*psz == '@')
222 {
223 psz++;
224 if (!isdigit(*psz))
225 {
226 fprintf(stderr, "%s:%u: error: Invalid ordinal spec.\n", pszInput, iLine);
227 return RTEXITCODE_FAILURE;
228 }
229 uOrdinal = *psz++ - '0';
230 while (isdigit(*psz))
231 {
232 uOrdinal *= 10;
233 uOrdinal += *psz++ - '0';
234 }
235 psz = leftStrip(psz);
236 cch = wordLength(psz);
237 if (WORD_CMP(psz, cch, "NONAME"))
238 {
239 fNoName = true;
240 psz = leftStrip(psz + cch);
241 }
242 }
243
244 bool fData = false;
245 while (*psz)
246 {
247 cch = wordLength(psz);
248 if (WORD_CMP(psz, cch, "DATA"))
249 {
250 fData = true;
251 if (!g_fIgnoreData)
252 {
253 fprintf(stderr, "%s:%u: error: Cannot process DATA export '%.*s'.\n",
254 pszInput, iLine, cchName, pchName);
255 return RTEXITCODE_SUCCESS;
256 }
257 }
258 else if (WORD_CMP(psz, cch, "PRIVATE"))
259 {
260 fprintf(stderr, "%s:%u: error: Cannot process PRIVATE export '%.*s'.\n",
261 pszInput, iLine, cchName, pchName);
262 return RTEXITCODE_SUCCESS;
263 }
264 else
265 {
266 fprintf(stderr, "%s:%u: error: Unknown keyword: %.*s.\n", pszInput, iLine, cch, psz);
267 return RTEXITCODE_FAILURE;
268 }
269 psz = leftStrip(psz + cch);
270 }
271
272 /*
273 * Check for stdcall mangling.
274 */
275 size_t cbExp = sizeof(MYEXPORT) + cchName;
276 unsigned cchStdcall = 0;
277 if (cchName > 3 && *pchName == '_' && isdigit(pchName[cchName - 1]))
278 {
279 if (cchName > 3 && pchName[cchName - 2] == '@')
280 cchStdcall = 2;
281 else if (cchName > 4 && pchName[cchName - 3] == '@' && isdigit(pchName[cchName - 2]))
282 cchStdcall = 3;
283 if (cchStdcall)
284 cbExp += cchName - 1 - cchStdcall;
285 }
286
287 /*
288 * Add the export.
289 */
290 PMYEXPORT pExp = (PMYEXPORT)malloc(cbExp);
291 if (!pExp)
292 {
293 fprintf(stderr, "%s:%u: error: Out of memory.\n", pszInput, iLine);
294 return RTEXITCODE_FAILURE;
295 }
296 memcpy(pExp->szName, pchName, cchName);
297 pExp->szName[cchName] = '\0';
298 if (!cchStdcall)
299 {
300 pExp->pszUnstdcallName = NULL;
301 pExp->pszExportedNm = pExp->szName;
302 }
303 else
304 {
305 pExp->pszUnstdcallName = &pExp->szName[cchName + 1];
306 memcpy(pExp->pszUnstdcallName, pchName + 1, cchName - 1 - cchStdcall);
307 pExp->pszUnstdcallName[cchName - 1 - cchStdcall] = '\0';
308 pExp->pszExportedNm = pExp->pszUnstdcallName;
309 }
310 pExp->uOrdinal = uOrdinal;
311 pExp->fNoName = fNoName;
312 pExp->fData = fData;
313 pExp->pNext = NULL;
314 *g_ppExpNext = pExp;
315 g_ppExpNext = &pExp->pNext;
316 }
317 }
318
319 /*
320 * Why did we quit the loop, EOF or error?
321 */
322 if (feof(pInput))
323 return RTEXITCODE_SUCCESS;
324 fprintf(stderr, "error: Incompletely read '%s' (iLine=%u).\n", pszInput, iLine);
325 return RTEXITCODE_FAILURE;
326}
327
328
329/**
330 * Parses a_apszInputs, populating the list pointed to by g_pExpHead.
331 *
332 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
333 * details has been displayed.
334 */
335static RTEXITCODE parseInputs(void)
336{
337 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
338 for (unsigned i = 0; i < g_cInputs; i++)
339 {
340 FILE *pInput = fopen(g_apszInputs[i], "r");
341 if (pInput)
342 {
343 RTEXITCODE rcExit2 = parseInputInner(pInput, g_apszInputs[i]);
344 fclose(pInput);
345 if (rcExit2 == RTEXITCODE_SUCCESS && !g_pExpHead)
346 {
347 fprintf(stderr, "error: Found no exports in '%s'.\n", g_apszInputs[i]);
348 rcExit2 = RTEXITCODE_FAILURE;
349 }
350 if (rcExit2 != RTEXITCODE_SUCCESS)
351 rcExit = rcExit2;
352 }
353 else
354 {
355 fprintf(stderr, "error: Failed to open '%s' for reading.\n", g_apszInputs[i]);
356 rcExit = RTEXITCODE_FAILURE;
357 }
358 }
359 return rcExit;
360}
361
362
363/**
364 * Generates the assembly source code for AMD64 and x86, writing it
365 * to @a pOutput.
366 *
367 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
368 * details has been displayed.
369 * @param pOutput The output stream (caller checks it for errors
370 * when closing).
371 */
372static RTEXITCODE generateOutputInnerX86AndAMD64(FILE *pOutput)
373{
374 fprintf(pOutput, ";;\n");
375 for (unsigned i = 0; i < g_cInputs; i++)
376 fprintf(pOutput, ";; Autogenerated from '%s'.\n", g_apszInputs[i]);
377
378 fprintf(pOutput,
379 ";; DO NOT EDIT!\n"
380 ";;\n"
381 "\n"
382 "\n"
383 "%%include \"iprt/asmdefs.mac\"\n"
384 "\n"
385 "\n");
386
387 /*
388 * Put the thunks first for alignment and other reasons. It's the hot part of the code.
389 */
390 fprintf(pOutput,
391 ";\n"
392 "; Thunks.\n"
393 ";\n"
394 "BEGINCODE\n");
395 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
396 if (pExp->fData)
397 fprintf(pOutput,
398 "BEGINPROC LazyGetPtr_%s\n"
399 " mov xAX, [NAME(g_LazyPtr_%s) xWrtRIP]\n"
400 " test xAX, xAX\n"
401 " jz ___LazyLoad___%s\n"
402 " ret\n"
403 "ENDPROC LazyGetPtr_%s\n",
404 pExp->szName, pExp->szName, pExp->szName, pExp->szName);
405 else if (!pExp->pszUnstdcallName)
406 fprintf(pOutput,
407 "BEGINPROC %s\n"
408 " jmp RTCCPTR_PRE [NAME(g_pfn%s) xWrtRIP]\n"
409 "ENDPROC %s\n",
410 pExp->szName, pExp->szName, pExp->szName);
411 else
412 fprintf(pOutput,
413 "%%ifdef RT_ARCH_X86\n"
414 "global %s\n"
415 "%s:\n"
416 " jmp RTCCPTR_PRE [NAME(g_pfn%s) xWrtRIP]\n"
417 "%%else\n"
418 "BEGINPROC %s\n"
419 " jmp RTCCPTR_PRE [NAME(g_pfn%s) xWrtRIP]\n"
420 "ENDPROC %s\n"
421 "%%endif\n",
422 pExp->szName, pExp->szName, pExp->pszUnstdcallName,
423 pExp->pszUnstdcallName, pExp->pszUnstdcallName, pExp->pszUnstdcallName);
424
425 fprintf(pOutput,
426 "\n"
427 "\n");
428
429 /*
430 * Import pointers
431 */
432 fprintf(pOutput,
433 ";\n"
434 "; Import pointers. Initialized to point to lazy loading stubs.\n"
435 ";\n"
436 "BEGINDATA\n"
437 "g_apfnImports:\n");
438 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
439 if (pExp->fData)
440 fprintf(pOutput,
441 "%%ifdef ASM_FORMAT_PE\n"
442 ";@todo\n"
443 "%%endif\n"
444 "global NAME(g_LazyPtr_%s)\n"
445 "NAME(g_LazyPtr_%s): RTCCPTR_DEF 0\n",
446 pExp->pszExportedNm, pExp->pszExportedNm);
447 else if (pExp->pszUnstdcallName)
448 fprintf(pOutput,
449 "%%ifdef ASM_FORMAT_PE\n"
450 " %%ifdef RT_ARCH_X86\n"
451 "global __imp_%s\n"
452 "__imp_%s:\n"
453 " %%else\n"
454 "global __imp_%s\n"
455 "__imp_%s:\n"
456 " %%endif\n"
457 "%%endif\n"
458 "NAME(g_pfn%s) RTCCPTR_DEF ___LazyLoad___%s\n"
459 "\n",
460 pExp->szName,
461 pExp->szName,
462 pExp->pszUnstdcallName,
463 pExp->pszUnstdcallName,
464 pExp->pszExportedNm,
465 pExp->pszExportedNm);
466 else
467 fprintf(pOutput,
468 "%%ifdef ASM_FORMAT_PE\n"
469 "global __imp_%s\n"
470 "__imp_%s:\n"
471 "%%endif\n"
472 "NAME(g_pfn%s) RTCCPTR_DEF ___LazyLoad___%s\n"
473 "\n",
474 pExp->szName,
475 pExp->szName,
476 pExp->pszExportedNm,
477 pExp->pszExportedNm);
478 fprintf(pOutput,
479 "RTCCPTR_DEF 0 ; Terminator entry for traversal.\n"
480 "\n"
481 "\n");
482
483 /*
484 * Now for the less important stuff, starting with the names.
485 *
486 * We keep the names separate so we can traverse them in parallel to
487 * g_apfnImports in the load-everything routine further down.
488 */
489 fprintf(pOutput,
490 ";\n"
491 "; Imported names.\n"
492 ";\n"
493 "BEGINCODE\n"
494 "g_szLibrary: db '%s',0\n"
495 "\n"
496 "g_szzNames:\n",
497 g_pszLibrary);
498 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
499 if (!pExp->fNoName)
500 fprintf(pOutput, " g_sz%s:\n db '%s',0\n", pExp->pszExportedNm, pExp->pszExportedNm);
501 else
502 fprintf(pOutput, " g_sz%s:\n db '#%u',0\n", pExp->pszExportedNm, pExp->uOrdinal);
503 fprintf(pOutput,
504 "g_EndOfNames: db 0\n"
505 "\n"
506 "g_szFailLoadFmt: db 'Lazy loader failed to load \"%%s\": %%Rrc', 10, 0\n"
507 "g_szFailResolveFmt: db 'Lazy loader failed to resolve symbol \"%%s\" in \"%%s\": %%Rrc', 10, 0\n"
508 "\n"
509 "\n");
510
511 /*
512 * The per import lazy load code.
513 */
514 fprintf(pOutput,
515 ";\n"
516 "; Lazy load+resolve stubs.\n"
517 ";\n"
518 "BEGINCODE\n");
519 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
520 {
521 if (!pExp->fNoName)
522 fprintf(pOutput,
523 "___LazyLoad___%s:\n"
524 /* "int3\n" */
525 "%%ifdef RT_ARCH_AMD64\n"
526 " lea rax, [g_sz%s wrt rip]\n"
527 " lea r10, [NAME(%s%s) wrt rip]\n"
528 " call LazyLoadResolver\n"
529 "%%elifdef RT_ARCH_X86\n"
530 " push g_sz%s\n"
531 " push NAME(%s%s)\n"
532 " call LazyLoadResolver\n"
533 " add esp, 8h\n"
534 "%%else\n"
535 " %%error \"Unsupported architecture\"\n"
536 "%%endif\n"
537 ,
538 pExp->pszExportedNm,
539 pExp->pszExportedNm,
540 !pExp->fData ? "g_pfn" : "g_LazyPtr_", pExp->pszExportedNm,
541 pExp->pszExportedNm,
542 !pExp->fData ? "g_pfn" : "g_LazyPtr_", pExp->pszExportedNm);
543 else
544 fprintf(pOutput,
545 "___LazyLoad___%s:\n"
546 /* "int3\n" */
547 "%%ifdef RT_ARCH_AMD64\n"
548 " mov eax, %u\n"
549 " lea r10, [NAME(%s%s) wrt rip]\n"
550 " call LazyLoadResolver\n"
551 "%%elifdef RT_ARCH_X86\n"
552 " push %u\n"
553 " push NAME(%s%s)\n"
554 " call LazyLoadResolver\n"
555 " add esp, 8h\n"
556 "%%else\n"
557 " %%error \"Unsupported architecture\"\n"
558 "%%endif\n"
559 ,
560 pExp->pszExportedNm,
561 pExp->uOrdinal,
562 !pExp->fData ? "g_pfn" : "g_LazyPtr_", pExp->pszExportedNm,
563 pExp->uOrdinal,
564 !pExp->fData ? "g_pfn" : "g_LazyPtr_", pExp->pszExportedNm);
565 if (pExp->fData)
566 fprintf(pOutput, " jmp NAME(LazyGetPtr_%s)\n", pExp->szName);
567 else if (!pExp->pszUnstdcallName)
568 fprintf(pOutput, " jmp NAME(%s)\n", pExp->szName);
569 else
570 fprintf(pOutput,
571 "%%ifdef RT_ARCH_X86\n"
572 " jmp %s\n"
573 "%%else\n"
574 " jmp NAME(%s)\n"
575 "%%endif\n"
576 ,
577 pExp->szName, pExp->pszUnstdcallName);
578 fprintf(pOutput, "\n");
579 }
580 fprintf(pOutput,
581 "\n"
582 "\n"
583 "\n");
584
585 /*
586 * The code that does the loading and resolving.
587 */
588 fprintf(pOutput,
589 ";\n"
590 "; The module handle.\n"
591 ";\n"
592 "BEGINDATA\n"
593 "g_hMod RTCCPTR_DEF 0\n"
594 "\n"
595 "\n"
596 "\n");
597
598 /*
599 * How we load the module needs to be selectable later on.
600 *
601 * The LazyLoading routine returns the module handle in RCX/ECX, caller
602 * saved all necessary registers.
603 */
604 if (!g_fSystemLibrary)
605 fprintf(pOutput,
606 ";\n"
607 ";SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod,\n"
608 "; uint32_t fFlags, PRTERRINFO pErrInfo);\n"
609 ";\n"
610 "EXTERN_IMP2 SUPR3HardenedLdrLoadAppPriv\n"
611 "%%ifdef IN_RT_R3\n"
612 "extern NAME(RTAssertMsg2Weak)\n"
613 "%%else\n"
614 "EXTERN_IMP2 RTAssertMsg2Weak\n"
615 "%%endif\n"
616 "BEGINCODE\n"
617 "\n"
618 "LazyLoading:\n"
619 " mov xCX, [g_hMod xWrtRIP]\n"
620 " or xCX, xCX\n"
621 " jnz .return\n"
622 "\n"
623 "%%ifdef ASM_CALL64_GCC\n"
624 " xor rcx, rcx ; pErrInfo\n"
625 " xor rdx, rdx ; fFlags (local load)\n"
626 " lea rsi, [g_hMod wrt rip] ; phLdrMod\n"
627 " lea rdi, [g_szLibrary wrt rip] ; pszFilename\n"
628 " sub rsp, 08h\n"
629 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
630 " add rsp, 08h\n"
631 "\n"
632 "%%elifdef ASM_CALL64_MSC\n"
633 " xor r9, r9 ; pErrInfo\n"
634 " xor r8, r8 ; fFlags (local load)\n"
635 " lea rdx, [g_hMod wrt rip] ; phLdrMod\n"
636 " lea rcx, [g_szLibrary wrt rip] ; pszFilename\n"
637 " sub rsp, 28h\n"
638 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
639 " add rsp, 28h\n"
640 "\n"
641 "%%elifdef RT_ARCH_X86\n"
642 " sub xSP, 0ch\n"
643 " push 0 ; pErrInfo\n"
644 " push 0 ; fFlags (local load)\n"
645 " push g_hMod ; phLdrMod\n"
646 " push g_szLibrary ; pszFilename\n"
647 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
648 " add esp, 1ch\n"
649 "%%else\n"
650 " %%error \"Unsupported architecture\"\n"
651 "%%endif\n");
652 else
653 fprintf(pOutput,
654 ";\n"
655 "; RTDECL(int) RTLdrLoadSystem(const char *pszFilename, bool fNoUnload, PRTLDRMOD phLdrMod);\n"
656 ";\n"
657 "%%ifdef IN_RT_R3\n"
658 "extern NAME(RTLdrLoadSystem)\n"
659 "extern NAME(RTAssertMsg2Weak)\n"
660 "%%else\n"
661 "EXTERN_IMP2 RTLdrLoadSystem\n"
662 "EXTERN_IMP2 RTAssertMsg2Weak\n"
663 "%%endif\n"
664 "BEGINCODE\n"
665 "\n"
666 "LazyLoading:\n"
667 " mov xCX, [g_hMod xWrtRIP]\n"
668 " or xCX, xCX\n"
669 " jnz .return\n"
670 "\n"
671 "%%ifdef ASM_CALL64_GCC\n"
672 " lea rdx, [g_hMod wrt rip] ; phLdrMod\n"
673 " mov esi, 1 ; fNoUnload=true\n"
674 " lea rdi, [g_szLibrary wrt rip] ; pszFilename\n"
675 " sub rsp, 08h\n"
676 " %%ifdef IN_RT_R3\n"
677 " call NAME(RTLdrLoadSystem)\n"
678 " %%else\n"
679 " call IMP2(RTLdrLoadSystem)\n"
680 " %%endif\n"
681 " add rsp, 08h\n"
682 "\n"
683 "%%elifdef ASM_CALL64_MSC\n"
684 " lea r8, [g_hMod wrt rip] ; phLdrMod\n"
685 " mov edx, 1 ; fNoUnload=true\n"
686 " lea rcx, [g_szLibrary wrt rip] ; pszFilename\n"
687 " sub rsp, 28h\n"
688 " %%ifdef IN_RT_R3\n"
689 " call NAME(RTLdrLoadSystem)\n"
690 " %%else\n"
691 " call IMP2(RTLdrLoadSystem)\n"
692 " %%endif\n"
693 " add rsp, 28h\n"
694 "\n"
695 "%%elifdef RT_ARCH_X86\n"
696 " push g_hMod ; phLdrMod\n"
697 " push 1 ; fNoUnload=true\n"
698 " push g_szLibrary ; pszFilename\n"
699 " %%ifdef IN_RT_R3\n"
700 " call NAME(RTLdrLoadSystem)\n"
701 " %%else\n"
702 " call IMP2(RTLdrLoadSystem)\n"
703 " %%endif\n"
704 " add esp, 0ch\n"
705 "%%else\n"
706 " %%error \"Unsupported architecture\"\n"
707 "%%endif\n");
708 fprintf(pOutput,
709 " or eax, eax\n"
710 " jnz .badload\n"
711 " mov xCX, [g_hMod xWrtRIP]\n"
712 ".return:\n"
713 " ret\n"
714 "\n"
715 ".badload:\n"
716 "%%ifdef ASM_CALL64_GCC\n"
717 " mov edx, eax\n"
718 " lea rsi, [g_szLibrary wrt rip]\n"
719 " lea rdi, [g_szFailLoadFmt wrt rip]\n"
720 " sub rsp, 08h\n"
721 "%%elifdef ASM_CALL64_MSC\n"
722 " mov r8d, eax\n"
723 " lea rdx, [g_szLibrary wrt rip]\n"
724 " lea rcx, [g_szFailLoadFmt wrt rip]\n"
725 " sub rsp, 28h\n"
726 "%%elifdef RT_ARCH_X86\n"
727 " push eax\n"
728 " push g_szLibrary\n"
729 " push g_szFailLoadFmt\n"
730 "%%endif\n"
731 "%%ifdef IN_RT_R3\n"
732 " call NAME(RTAssertMsg2Weak)\n"
733 "%%else\n"
734 " call IMP2(RTAssertMsg2Weak)\n"
735 "%%endif\n"
736 ".badloadloop:\n"
737 " int3\n"
738 " jmp .badloadloop\n"
739 "LazyLoading_End:\n"
740 "\n"
741 "\n");
742
743
744 fprintf(pOutput,
745 ";\n"
746 ";RTDECL(int) RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvValue);\n"
747 ";\n"
748 "%%ifdef IN_RT_R3\n"
749 "extern NAME(RTLdrGetSymbol)\n"
750 "%%else\n"
751 "EXTERN_IMP2 RTLdrGetSymbol\n"
752 "%%endif\n"
753 "BEGINCODE\n"
754 "LazyLoadResolver:\n"
755 "%%ifdef RT_ARCH_AMD64\n"
756 " push rbp\n"
757 " mov rbp, rsp\n"
758 " push r15\n"
759 " push r14\n"
760 " mov r15, rax ; name\n"
761 " mov r14, r10 ; ppfn\n"
762 " push r9\n"
763 " push r8\n"
764 " push rcx\n"
765 " push rdx\n"
766 " push r12\n"
767 " %%ifdef ASM_CALL64_GCC\n"
768 " push rsi\n"
769 " push rdi\n"
770 " mov r12, rsp\n"
771 " %%else\n"
772 " mov r12, rsp\n"
773 " sub rsp, 20h\n"
774 " %%endif\n"
775 " and rsp, 0fffffff0h ; Try make sure the stack is aligned\n"
776 "\n"
777 " call LazyLoading ; returns handle in rcx\n"
778 " %%ifdef ASM_CALL64_GCC\n"
779 " mov rdi, rcx ; hLdrMod\n"
780 " mov rsi, r15 ; pszSymbol\n"
781 " mov rdx, r14 ; ppvValue\n"
782 " %%else\n"
783 " mov rdx, r15 ; pszSymbol\n"
784 " mov r8, r14 ; ppvValue\n"
785 " %%endif\n"
786 " %%ifdef IN_RT_R3\n"
787 " call NAME(RTLdrGetSymbol)\n"
788 " %%else\n"
789 " call IMP2(RTLdrGetSymbol)\n"
790 " %%endif\n"
791 " or eax, eax\n"
792 " jnz .badsym\n"
793 "\n"
794 " mov rsp, r12\n"
795 " %%ifdef ASM_CALL64_GCC\n"
796 " pop rdi\n"
797 " pop rsi\n"
798 " %%endif\n"
799 " pop r12\n"
800 " pop rdx\n"
801 " pop rcx\n"
802 " pop r8\n"
803 " pop r9\n"
804 " pop r14\n"
805 " pop r15\n"
806 " leave\n"
807 "\n"
808 "%%elifdef RT_ARCH_X86\n"
809 " push ebp\n"
810 " mov ebp, esp\n"
811 " push eax\n"
812 " push ecx\n"
813 " push edx\n"
814 " and esp, 0fffffff0h\n"
815 "\n"
816 ".loaded:\n"
817 " call LazyLoading ; returns handle in ecx\n"
818 " push dword [ebp + 8] ; value addr\n"
819 " push dword [ebp + 12] ; symbol name\n"
820 " push ecx\n"
821 " %%ifdef IN_RT_R3\n"
822 " call NAME(RTLdrGetSymbol)\n"
823 " %%else\n"
824 " call IMP2(RTLdrGetSymbol)\n"
825 " %%endif\n"
826 " or eax, eax\n"
827 " jnz .badsym\n"
828 " lea esp, [ebp - 0ch]\n"
829 " pop edx\n"
830 " pop ecx\n"
831 " pop eax\n"
832 " leave\n"
833 "%%else\n"
834 " %%error \"Unsupported architecture\"\n"
835 "%%endif\n"
836 " ret\n"
837 "\n"
838 ".badsym:\n"
839 "%%ifdef ASM_CALL64_GCC\n"
840 " mov ecx, eax\n"
841 " lea rdx, [g_szLibrary wrt rip]\n"
842 " mov rsi, r15\n"
843 " lea rdi, [g_szFailResolveFmt wrt rip]\n"
844 " sub rsp, 08h\n"
845 "%%elifdef ASM_CALL64_MSC\n"
846 " mov r9d, eax\n"
847 " mov r8, r15\n"
848 " lea rdx, [g_szLibrary wrt rip]\n"
849 " lea rcx, [g_szFailResolveFmt wrt rip]\n"
850 " sub rsp, 28h\n"
851 "%%elifdef RT_ARCH_X86\n"
852 " push eax\n"
853 " push dword [ebp + 12]\n"
854 " push g_szLibrary\n"
855 " push g_szFailResolveFmt\n"
856 "%%endif\n"
857 "%%ifdef IN_RT_R3\n"
858 " call NAME(RTAssertMsg2Weak)\n"
859 "%%else\n"
860 " call IMP2(RTAssertMsg2Weak)\n"
861 "%%endif\n"
862 ".badsymloop:\n"
863 " int3\n"
864 " jmp .badsymloop\n"
865 "\n"
866 "LazyLoadResolver_End:\n"
867 "\n"
868 "\n"
869 );
870
871
872
873 /*
874 * C callable method for explicitly loading the library and optionally
875 * resolving all the imports.
876 */
877 if (g_fWithExplictLoadFunction)
878 {
879 int cchLibBaseName = (int)(strchr(g_pszLibrary, '.') ? strchr(g_pszLibrary, '.') - g_pszLibrary : strlen(g_pszLibrary));
880 fprintf(pOutput,
881 ";;\n"
882 "; ExplicitlyLoad%.*s(bool fResolveAllImports, pErrInfo);\n"
883 ";\n"
884 "%%ifdef IN_RT_R3\n"
885 "extern NAME(RTErrInfoSet)\n"
886 "%%else\n"
887 "EXTERN_IMP2 RTErrInfoSet\n"
888 "%%endif\n"
889 "BEGINCODE\n"
890 "BEGINPROC ExplicitlyLoad%.*s\n"
891 " push xBP\n"
892 " mov xBP, xSP\n"
893 " push xBX\n"
894 "%%ifdef ASM_CALL64_GCC\n"
895 " %%define pszCurStr r14\n"
896 " push r14\n"
897 "%%else\n"
898 " %%define pszCurStr xDI\n"
899 " push xDI\n"
900 "%%endif\n"
901 " sub xSP, 40h\n"
902 "\n"
903 " ;\n"
904 " ; Save parameters on stack (64-bit only).\n"
905 " ;\n"
906 "%%ifdef ASM_CALL64_GCC\n"
907 " mov [xBP - xCB * 3], rdi ; fResolveAllImports\n"
908 " mov [xBP - xCB * 4], rsi ; pErrInfo\n"
909 "%%elifdef ASM_CALL64_MSC\n"
910 " mov [xBP - xCB * 3], rcx ; fResolveAllImports\n"
911 " mov [xBP - xCB * 4], rdx ; pErrInfo\n"
912 "%%endif\n"
913 "\n"
914 " ;\n"
915 " ; Is the module already loaded?\n"
916 " ;\n"
917 " cmp RTCCPTR_PRE [g_hMod xWrtRIP], 0\n"
918 " jnz .loaded\n"
919 "\n"
920 " ;\n"
921 " ; Load the module.\n"
922 " ;\n"
923 ,
924 cchLibBaseName, g_pszLibrary,
925 cchLibBaseName, g_pszLibrary);
926 if (!g_fSystemLibrary)
927 fprintf(pOutput,
928 "%%ifdef ASM_CALL64_GCC\n"
929 " mov rcx, [xBP - xCB * 4] ; pErrInfo\n"
930 " xor rdx, rdx ; fFlags (local load)\n"
931 " lea rsi, [g_hMod wrt rip] ; phLdrMod\n"
932 " lea rdi, [g_szLibrary wrt rip] ; pszFilename\n"
933 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
934 "\n"
935 "%%elifdef ASM_CALL64_MSC\n"
936 " mov r9, [xBP - xCB * 4] ; pErrInfo\n"
937 " xor r8, r8 ; fFlags (local load)\n"
938 " lea rdx, [g_hMod wrt rip] ; phLdrMod\n"
939 " lea rcx, [g_szLibrary wrt rip] ; pszFilename\n"
940 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
941 "\n"
942 "%%elifdef RT_ARCH_X86\n"
943 " sub xSP, 0ch\n"
944 " push dword [xBP + 12] ; pErrInfo\n"
945 " push 0 ; fFlags (local load)\n"
946 " push g_hMod ; phLdrMod\n"
947 " push g_szLibrary ; pszFilename\n"
948 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
949 " add esp, 1ch\n"
950 "%%else\n"
951 " %%error \"Unsupported architecture\"\n"
952 "%%endif\n");
953 else
954 fprintf(pOutput,
955 "%%ifdef ASM_CALL64_GCC\n"
956 " lea rdx, [g_hMod wrt rip] ; phLdrMod\n"
957 " mov esi, 1 ; fNoUnload=true\n"
958 " lea rdi, [g_szLibrary wrt rip] ; pszFilename\n"
959 " %%ifdef IN_RT_R3\n"
960 " call NAME(RTLdrLoadSystem)\n"
961 " %%else\n"
962 " call IMP2(RTLdrLoadSystem)\n"
963 " %%endif\n"
964 "\n"
965 "%%elifdef ASM_CALL64_MSC\n"
966 " lea r8, [g_hMod wrt rip] ; phLdrMod\n"
967 " mov edx, 1 ; fNoUnload=true\n"
968 " lea rcx, [g_szLibrary wrt rip] ; pszFilename\n"
969 " %%ifdef IN_RT_R3\n"
970 " call NAME(RTLdrLoadSystem)\n"
971 " %%else\n"
972 " call IMP2(RTLdrLoadSystem)\n"
973 " %%endif\n"
974 "\n"
975 "%%elifdef RT_ARCH_X86\n"
976 " push g_hMod ; phLdrMod\n"
977 " push 1 ; fNoUnload=true\n"
978 " push g_szLibrary ; pszFilename\n"
979 " %%ifdef IN_RT_R3\n"
980 " call NAME(RTLdrLoadSystem)\n"
981 " %%else\n"
982 " call IMP2(RTLdrLoadSystem)\n"
983 " %%endif\n"
984 " add esp, 0ch\n"
985 "%%else\n"
986 " %%error \"Unsupported architecture\"\n"
987 "%%endif\n");
988 fprintf(pOutput,
989 " or eax, eax\n"
990 " jnz .return\n"
991 "\n"
992 " ;\n"
993 " ; Resolve the imports too if requested to do so.\n"
994 " ;\n"
995 ".loaded:\n"
996 "%%ifdef ASM_ARCH_X86\n"
997 " cmp byte [xBP + 8], 0\n"
998 "%%else\n"
999 " cmp byte [xBP - xCB * 3], 0\n"
1000 "%%endif\n"
1001 " je .return\n"
1002 "\n"
1003 " lea pszCurStr, [g_szzNames xWrtRIP]\n"
1004 " lea xBX, [g_apfnImports xWrtRIP]\n"
1005 ".next_import:\n"
1006 " cmp RTCCPTR_PRE [xBX], 0\n"
1007 " je .return\n"
1008 "%%ifdef ASM_CALL64_GCC\n"
1009 " mov rdx, xBX ; ppvValue\n"
1010 " mov rsi, pszCurStr ; pszSymbol\n"
1011 " mov rdi, [g_hMod wrt rip] ; hLdrMod\n"
1012 " %%ifdef IN_RT_R3\n"
1013 " call NAME(RTLdrGetSymbol)\n"
1014 " %%else\n"
1015 " call IMP2(RTLdrGetSymbol)\n"
1016 " %%endif\n"
1017 "%%elifdef ASM_CALL64_MSC\n"
1018 " mov r8, xBX ; ppvValue\n"
1019 " mov rdx, pszCurStr ; pszSymbol\n"
1020 " mov rcx, [g_hMod wrt rip] ; pszSymbol\n"
1021 " %%ifdef IN_RT_R3\n"
1022 " call NAME(RTLdrGetSymbol)\n"
1023 " %%else\n"
1024 " call IMP2(RTLdrGetSymbol)\n"
1025 " %%endif\n"
1026 "%%else\n"
1027 " push xBX ; ppvValue\n"
1028 " push pszCurStr ; pszSymbol\n"
1029 " push RTCCPTR_PRE [g_hMod] ; hLdrMod\n"
1030 " %%ifdef IN_RT_R3\n"
1031 " call NAME(RTLdrGetSymbol)\n"
1032 " %%else\n"
1033 " call IMP2(RTLdrGetSymbol)\n"
1034 " %%endif\n"
1035 " add xSP, 0ch\n"
1036 "%%endif\n"
1037 " or eax, eax\n"
1038 " jnz .symbol_error\n"
1039 "\n"
1040 " ; Advance.\n"
1041 " add xBX, RTCCPTR_CB\n"
1042 " xor eax, eax\n"
1043 " mov xCX, 0ffffffffh\n"
1044 "%%ifdef ASM_CALL64_GCC\n"
1045 " mov xDI, pszCurStr\n"
1046 " repne scasb\n"
1047 " mov pszCurStr, xDI\n"
1048 "%%else\n"
1049 " repne scasb\n"
1050 "%%endif\n"
1051 " jmp .next_import\n"
1052 "\n"
1053 " ;\n"
1054 " ; Error loading a symbol. Call RTErrInfoSet on pErrInfo (preserves eax).\n"
1055 " ;\n"
1056 ".symbol_error:\n"
1057 "%%ifdef ASM_CALL64_GCC\n"
1058 " mov rdx, pszCurStr ; pszMsg\n"
1059 " mov esi, eax ; rc\n"
1060 " mov rdi, [xBP - xCB * 4] ; pErrInfo\n"
1061 " %%ifdef IN_RT_R3\n"
1062 " call NAME(RTErrInfoSet)\n"
1063 " %%else\n"
1064 " call IMP2(RTErrInfoSet)\n"
1065 " %%endif\n"
1066 "%%elifdef ASM_CALL64_MSC\n"
1067 " mov r8, pszCurStr ; pszMsg\n"
1068 " mov edx, eax ; rc\n"
1069 " mov rcx, [xBP - xCB * 4] ; pErrInfo\n"
1070 " %%ifdef IN_RT_R3\n"
1071 " call NAME(RTErrInfoSet)\n"
1072 " %%else\n"
1073 " call IMP2(RTErrInfoSet)\n"
1074 " %%endif\n"
1075 "%%else\n"
1076 " push pszCurStr ; pszMsg\n"
1077 " push eax ; pszSymbol\n"
1078 " push dword [xBP + 0ch] ; pErrInfo\n"
1079 " %%ifdef IN_RT_R3\n"
1080 " call NAME(RTErrInfoSet)\n"
1081 " %%else\n"
1082 " call IMP2(RTErrInfoSet)\n"
1083 " %%endif\n"
1084 " add xSP, 0ch\n"
1085 "%%endif\n"
1086 " "
1087 "\n"
1088 ".return:\n"
1089 " mov pszCurStr, [xBP - xCB * 2]\n"
1090 " mov xBX, [xBP - xCB * 1]\n"
1091 " leave\n"
1092 " ret\n"
1093 "ENDPROC ExplicitlyLoad%.*s\n"
1094 "\n"
1095 "\n"
1096 ,
1097 cchLibBaseName, g_pszLibrary);
1098 }
1099
1100
1101 return RTEXITCODE_SUCCESS;
1102}
1103
1104
1105/**
1106 * Generates the assembly source code for ARM64, writing it
1107 * to @a pOutput.
1108 *
1109 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
1110 * details has been displayed.
1111 * @param pOutput The output stream (caller checks it for errors
1112 * when closing).
1113 */
1114static RTEXITCODE generateOutputInnerArm64(FILE *pOutput)
1115{
1116 const char *pszNmPfx = g_enmLdrFmt == RTLDRFMT_ELF ? "" : "_";
1117
1118 fprintf(pOutput, "/*\n");
1119 for (unsigned i = 0; i < g_cInputs; i++)
1120 fprintf(pOutput, " * Autogenerated from '%s'.\n", g_apszInputs[i]);
1121
1122 fprintf(pOutput,
1123 " * DO NOT EDIT!\n"
1124 " */\n"
1125 "\n"
1126 "\n"
1127 "#include \"iprt/asmdefs-arm.h\"\n"
1128 "\n"
1129 "\n");
1130
1131 /*
1132 * Put the thunks first for alignment and other reasons. It's the hot part of the code.
1133 */
1134 fprintf(pOutput,
1135 "/*\n"
1136 " * Thunks.\n"
1137 " */\n"
1138 "BEGINCODE\n");
1139 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
1140 if (!pExp->fData)
1141 fprintf(pOutput,
1142 ".p2align 3\n"
1143 ".globl %s%s\n"
1144 "%s%s:\n"
1145 " adrp x9, PAGE(%sg_pfn%s)\n"
1146 " ldr x9, [x9, PAGEOFF(%sg_pfn%s)]\n"
1147 " br x9\n",
1148 pszNmPfx, pExp->szName, pszNmPfx, pExp->szName, pszNmPfx, pExp->szName, pszNmPfx, pExp->szName);
1149 else
1150 fprintf(pOutput,
1151 ".p2align 3\n"
1152 ".globl %sLazyGetPtr_%s\n"
1153 "%sLazyGetPtr_%s:\n"
1154 " adrp x9, PAGE(%sg_LazyPtr_%s)\n"
1155 " ldr x9, [x9, PAGEOFF(%sg_LazyPtr_%s)]\n"
1156 " cmp x9, #0\n"
1157 " b.eq ___LazyLoad___%s\n"
1158 " mov x0, x9\n"
1159 " ret\n",
1160 pszNmPfx, pExp->szName, pszNmPfx, pExp->szName, pszNmPfx, pExp->szName, pszNmPfx, pExp->szName, pExp->pszExportedNm);
1161 fprintf(pOutput,
1162 "ENDCODE\n"
1163 "\n"
1164 "\n");
1165
1166 /*
1167 * Import pointers
1168 */
1169 fprintf(pOutput,
1170 "/*\n"
1171 " * Import pointers. Initialized to point to lazy loading stubs.\n"
1172 " */\n"
1173 "BEGINDATA\n"
1174 ".p2align 3\n"
1175 "g_apfnImports:\n");
1176 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
1177 if (!pExp->fData)
1178 fprintf(pOutput,
1179 ".globl __imp_%s\n"
1180 "__imp_%s:\n"
1181 ".globl %sg_pfn%s\n"
1182 "%sg_pfn%s:\n"
1183 " .quad ___LazyLoad___%s\n"
1184 "\n",
1185 pExp->szName, pExp->szName,
1186 pszNmPfx, pExp->szName, pszNmPfx, pExp->szName,
1187 pExp->pszExportedNm);
1188 else
1189 fprintf(pOutput,
1190 ".globl %sg_LazyPtr_%s\n"
1191 "%sg_LazyPtr_%s:\n"
1192 " .quad 0\n"
1193 "\n",
1194 pszNmPfx, pExp->szName, pszNmPfx, pExp->szName);
1195 fprintf(pOutput,
1196 " .quad 0 /* Terminator entry for traversal. */\n"
1197 "ENDDATA\n"
1198 "\n"
1199 "\n");
1200
1201 /*
1202 * Now for the less important stuff, starting with the names.
1203 *
1204 * We keep the names separate so we can traverse them in parallel to
1205 * g_apfnImports in the load-everything routine further down.
1206 */
1207 fprintf(pOutput,
1208 "/*\n"
1209 " * Imported names.\n"
1210 " */\n"
1211 "BEGINCONSTSTRINGS\n"
1212 "g_szLibrary:\n"
1213 " .asciz \"%s\"\n"
1214 "\n"
1215 "g_szzNames:\n",
1216 g_pszLibrary);
1217 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
1218 if (!pExp->fNoName)
1219 fprintf(pOutput, " g_sz%s:\n .asciz \"%s\"\n", pExp->pszExportedNm, pExp->pszExportedNm);
1220 else
1221 fprintf(pOutput, " g_sz%s:\n .asciz \"#%u\"\n", pExp->pszExportedNm, pExp->uOrdinal);
1222 fprintf(pOutput,
1223 "g_EndOfNames: .byte 0\n"
1224 "\n"
1225 "g_szFailLoadFmt: .asciz \"Lazy loader failed to load \\\"%%s\\\": %%Rrc\\n\"\n"
1226 "g_szFailResolveFmt: .asciz \"Lazy loader failed to resolve symbol \\\"%%s\\\" in \\\"%%s\\\": %%Rrc\\n\"\n"
1227 "ENDCONSTSTRINGS\n"
1228 "\n"
1229 "\n");
1230
1231 /*
1232 * The per import lazy load code.
1233 */
1234 fprintf(pOutput,
1235 "/*\n"
1236 " * Lazy load+resolve stubs.\n"
1237 " */\n"
1238 "BEGINCODE\n"
1239 ".p2align 3\n");
1240 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
1241 {
1242 if (!pExp->fNoName)
1243 fprintf(pOutput,
1244 "___LazyLoad___%s:\n"
1245 " adrp x9, PAGE(g_sz%s)\n"
1246 " add x9, x9, PAGEOFF(g_sz%s)\n"
1247 " adrp x10, PAGE(%s%s%s)\n"
1248 " add x10, x10, PAGEOFF(%s%s%s)\n"
1249 " mov x16, x30\n"
1250 " bl LazyLoadResolver\n"
1251 " mov x30, x16\n"
1252 , pExp->pszExportedNm,
1253 pExp->pszExportedNm, pExp->pszExportedNm,
1254 pszNmPfx, !pExp->fData ? "g_pfn" : "g_LazyPtr_", pExp->pszExportedNm,
1255 pszNmPfx, !pExp->fData ? "g_pfn" : "g_LazyPtr_", pExp->pszExportedNm);
1256 else
1257 fprintf(pOutput,
1258 "___LazyLoad___%s:\n"
1259 " movk w9, #%u\n"
1260 " adrp x10, PAGE(%s%s%s)\n"
1261 " add x10, x10, PAGEOFF(%s%s%s)\n"
1262 , pExp->pszExportedNm,
1263 pExp->uOrdinal,
1264 pszNmPfx, !pExp->fData ? "g_pfn" : "g_LazyPtr_", pExp->pszExportedNm,
1265 pszNmPfx, !pExp->fData ? "g_pfn" : "g_LazyPtr_", pExp->pszExportedNm);
1266 if (!pExp->fData)
1267 fprintf(pOutput, " b %s%s\n", pszNmPfx, pExp->szName);
1268 else
1269 fprintf(pOutput, " b %sLazyGetPtr_%s\n", pszNmPfx, pExp->szName);
1270 fprintf(pOutput, "\n");
1271 }
1272 fprintf(pOutput,
1273 "ENDCODE\n"
1274 "\n"
1275 "\n"
1276 "\n");
1277
1278 /*
1279 * The code that does the loading and resolving.
1280 */
1281 fprintf(pOutput,
1282 "/*\n"
1283 " * The module handle.\n"
1284 " */\n"
1285 "BEGINDATA\n"
1286 "g_hMod:\n"
1287 " .quad 0\n"
1288 "ENDDATA\n"
1289 "\n"
1290 "\n"
1291 "\n");
1292
1293 /*
1294 * Common lazy loader and resolved.
1295 */
1296 fprintf(pOutput,
1297 "/*\n"
1298 " * The resolver code.\n"
1299 " */\n"
1300 "BEGINCODE\n"
1301 ".p2align 3\n"
1302 "LazyLoadResolver:\n"
1303 " .cfi_startproc\n"
1304 " /* Create frame. */\n"
1305 " sub sp, sp, #(16 + 192)\n"
1306 " stp x29, x30, [sp, #192]\n"
1307 " add x29, sp, #192\n"
1308 " .cfi_def_cfa x29, 16\n"
1309 " .cfi_offset x30, -8\n"
1310 " .cfi_offset x29, -16\n"
1311 " /* Save all argument registers and a handful of preserved ones. */\n"
1312 " stp x0, x1, [sp, #(192 - 16)]\n"
1313 " .cfi_offset x0, -32\n"
1314 " .cfi_offset x1, -24\n"
1315 " stp x2, x3, [sp, #(192 - 32)]\n"
1316 " .cfi_offset x3, -40\n"
1317 " .cfi_offset x2, -48\n"
1318 " stp x4, x5, [sp, #(192 - 48)]\n"
1319 " .cfi_offset x6, -56\n"
1320 " .cfi_offset x5, -64\n"
1321 " stp x6, x7, [sp, #(192 - 64)]\n"
1322 " .cfi_offset x7, -72\n"
1323 " .cfi_offset x6, -80\n"
1324 " stp x16, x17, [sp, #(192 - 80)]\n"
1325 " .cfi_offset x17, -88\n"
1326 " .cfi_offset x16, -96\n"
1327 " stp x18, x19, [sp, #(192 - 96)]\n"
1328 " .cfi_offset x19, -104\n"
1329 " .cfi_offset x18, -112\n"
1330 " stp x20, x21, [sp, #(192 - 112)]\n"
1331 " .cfi_offset x21, -120\n"
1332 " .cfi_offset x20, -128\n"
1333 " stp x22, x23, [sp, #(192 - 128)]\n"
1334 " .cfi_offset x23, -136\n"
1335 " .cfi_offset x22, -144\n"
1336 " str x8, [sp, #(192 - 144)]\n"
1337 "\n"
1338 " /* Shift the symbol name to x19 and g_pfnXXXX pointer to x20 as these are preserved registers\n"
1339 " * (in case we need to call LazyLoadModule/RTLdrLoad) */\n"
1340 " mov x19, x9\n"
1341 " mov x20, x10\n"
1342 "\n"
1343 " /* Get the module handle and call RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvValue) */\n"
1344 " adrp x0, PAGE(g_hMod)\n"
1345 " ldr x0, [x0, PAGEOFF(g_hMod)]\n"
1346 " cmp x0, #0\n"
1347 " b.ne Lloaded\n"
1348 " bl LazyLoading\n"
1349 "Lloaded:\n"
1350 " mov x1, x19\n"
1351 " mov x2, x20\n"
1352 " bl %sRTLdrGetSymbol\n"
1353 "\n"
1354 " cmp w0, #0\n"
1355 " b.eq Lreturn\n"
1356 "\n"
1357 "Lbadsym: /* Call sRTAssertMsg2Weak. Variadic (...) arguments are passed on the stack it seems. */\n"
1358 " mov x3, x0\n"
1359 " adrp x2, PAGE(g_szLibrary)\n"
1360 " add x2, x2, PAGEOFF(g_szLibrary)\n"
1361 " mov x1, x19\n"
1362 " adrp x0, PAGE(g_szFailLoadFmt)\n"
1363 " add x0, x0, PAGEOFF(g_szFailLoadFmt)\n"
1364 " stp x1, x2, [sp]\n"
1365 " str x3, [sp, #16]\n"
1366 " bl %sRTAssertMsg2Weak\n"
1367 "Lbadsymloop:\n"
1368 " brk #0x1\n"
1369 " b Lbadsymloop\n"
1370
1371 "Lreturn:\n"
1372 " /* Restore saved register */\n"
1373 " ldr x8, [sp, #(192 - 144)]\n"
1374 " .cfi_restore x8\n"
1375 " ldp x22, x23, [sp, #(192 - 128)]\n"
1376 " .cfi_restore x23\n"
1377 " .cfi_restore x22\n"
1378 " ldp x20, x21, [sp, #(192 - 112)]\n"
1379 " .cfi_restore x21\n"
1380 " .cfi_restore x20\n"
1381 " ldp x18, x19, [sp, #(192 - 96)]\n"
1382 " .cfi_restore x19\n"
1383 " .cfi_restore x18\n"
1384 " ldp x16, x17, [sp, #(192 - 80)]\n"
1385 " .cfi_restore x17\n"
1386 " .cfi_restore x18\n"
1387 " ldp x6, x7, [sp, #(192 - 64)]\n"
1388 " .cfi_restore x7\n"
1389 " .cfi_restore x6\n"
1390 " ldp x4, x5, [sp, #(192 - 48)]\n"
1391 " .cfi_restore x5\n"
1392 " .cfi_restore x4\n"
1393 " ldp x2, x3, [sp, #(192 - 32)]\n"
1394 " .cfi_restore x3\n"
1395 " .cfi_restore x2\n"
1396 " ldp x0, x1, [sp, #(192 - 16)]\n"
1397 " .cfi_restore x1\n"
1398 " .cfi_restore x0\n"
1399 "\n"
1400 " ldp x29, x30, [sp, #192]\n"
1401 " .cfi_restore x29\n"
1402 " .cfi_restore x30\n"
1403 " add sp, sp, #(16 + 192)\n"
1404 " ret\n"
1405 " .cfi_endproc\n"
1406 "\n"
1407 "\n"
1408 , pszNmPfx, pszNmPfx);
1409
1410 fprintf(pOutput,
1411 "/*\n"
1412 " * Loads the module.\n"
1413 " * ASSUMES called from LazyLoadResolver where all relevant registers are already saved.\n"
1414 " */\n"
1415 "LazyLoading:\n"
1416 " .cfi_startproc\n"
1417 " /* Create frame. */\n"
1418 " sub sp, sp, #(16 + 48)\n"
1419 " stp x29, x30, [sp, #48]\n"
1420 " add x29, sp, #48\n"
1421 " .cfi_def_cfa x29, 16\n"
1422 " .cfi_offset x30, -8\n"
1423 " .cfi_offset x29, -16\n"
1424 "\n");
1425
1426 if (!g_fSystemLibrary)
1427 fprintf(pOutput,
1428 " /* Call SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo); */\n"
1429 " mov x3, #0\n"
1430 " mov x2, #0\n"
1431 " adrp x1, PAGE(g_hMod)\n"
1432 " add x1, x1, PAGEOFF(g_hMod)\n"
1433 " adrp x0, PAGE(g_szLibrary)\n"
1434 " add x0, x0, PAGEOFF(g_szLibrary)\n"
1435 " bl %sSUPR3HardenedLdrLoadAppPriv\n"
1436 , pszNmPfx);
1437 else
1438 fprintf(pOutput,
1439 " /* Call RTLdrLoadSystem(const char *pszFilename, bool fNoUnload, PRTLDRMOD phLdrMod); */\n"
1440 " adrp x2, PAGE(g_hMod)\n"
1441 " add x2, x2, PAGEOFF(g_hMod)\n"
1442 " mov x1, #1\n"
1443 " adrp x0, PAGE(g_szLibrary)\n"
1444 " add x0, x0, PAGEOFF(g_szLibrary)\n"
1445 " bl %sRTLdrLoadSystem\n"
1446 , pszNmPfx);
1447
1448 fprintf(pOutput,
1449 " cmp w0, #0\n"
1450 " b.eq Lload_return\n"
1451 "\n"
1452 "Lbadload: /* Call sRTAssertMsg2Weak. Variadic (...) arguments are passed on the stack it seems. */\n"
1453 " mov x2, x0\n"
1454 " adrp x1, PAGE(g_szLibrary)\n"
1455 " add x1, x1, PAGEOFF(g_szLibrary)\n"
1456 " adrp x0, PAGE(g_szFailResolveFmt)\n"
1457 " add x0, x0, PAGEOFF(g_szFailResolveFmt)\n"
1458 " stp x1, x2, [sp]\n"
1459 " bl %sRTAssertMsg2Weak\n"
1460 "Lbadloadloop:\n"
1461 " brk #0x1\n"
1462 " b Lbadloadloop\n"
1463 "Lload_return:\n"
1464 " adrp x0, PAGE(g_hMod)\n"
1465 " ldr x0, [x0, PAGEOFF(g_hMod)]\n"
1466 " ldp x29, x30, [sp, #48]\n"
1467 " .cfi_restore x29\n"
1468 " .cfi_restore x30\n"
1469 " add sp, sp, #(16 + 48)\n"
1470 " ret\n"
1471 " .cfi_endproc\n"
1472 "ENDCODE\n"
1473 "\n"
1474 "\n"
1475 , pszNmPfx);
1476
1477 /*
1478 * C callable method for explicitly loading the library and optionally
1479 * resolving all the imports.
1480 */
1481 if (g_fWithExplictLoadFunction)
1482 {
1483 int cchLibBaseName = (int)(strchr(g_pszLibrary, '.') ? strchr(g_pszLibrary, '.') - g_pszLibrary : strlen(g_pszLibrary));
1484 fprintf(pOutput,
1485 "/**\n"
1486 " * ExplicitlyLoad%.*s(bool fResolveAllImports, pErrInfo);\n"
1487 " */\n"
1488 "BEGINCODE\n"
1489 ".p2align 3\n"
1490 ".globl %sExplicitlyLoad%.*s\n"
1491 "%sExplicitlyLoad%.*s:\n"
1492 " .cfi_startproc\n"
1493 " /* Create frame. */\n"
1494 " sub sp, sp, #(16 + 96)\n"
1495 " stp x29, x30, [sp, #96]\n"
1496 " add x29, sp, #96\n"
1497 " .cfi_def_cfa x29, 16\n"
1498 " .cfi_offset x30, -8\n"
1499 " .cfi_offset x29, -16\n"
1500 "\n"
1501 " stp x20, x21, [sp, #(96 - 16)]\n"
1502 " .cfi_offset x21, -24\n"
1503 " .cfi_offset x20, -32\n"
1504 " stp x22, x23, [sp, #(96 - 32)]\n"
1505 " .cfi_offset x23, -40\n"
1506 " .cfi_offset x22, -48\n"
1507
1508 " /* Save the input parameters. */\n"
1509 " mov x20, x0\n"
1510 " mov x21, x1\n"
1511 "\n"
1512 " /*\n"
1513 " * Is the module already loaded?\n"
1514 " */\n"
1515 " adrp x0, PAGE(g_hMod)\n"
1516 " ldr x0, [x0, PAGEOFF(g_hMod)]\n"
1517 " cmp x0, #0\n"
1518 " b.ne Lexplicit_loaded_module\n"
1519 "\n"
1520 ,
1521 cchLibBaseName, g_pszLibrary,
1522 pszNmPfx, cchLibBaseName, g_pszLibrary,
1523 pszNmPfx, cchLibBaseName, g_pszLibrary);
1524 fprintf(pOutput,
1525 "Lexplicit_load_module:\n");
1526 if (!g_fSystemLibrary)
1527 fprintf(pOutput,
1528 " /* Call SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo); */\n"
1529 " mov x3, x21\n"
1530 " mov x2, #0\n"
1531 " adrp x1, PAGE(g_hMod)\n"
1532 " add x1, x1, PAGEOFF(g_hMod)\n"
1533 " adrp x0, PAGE(g_szLibrary)\n"
1534 " add x0, x0, PAGEOFF(g_szLibrary)\n"
1535 " bl %sSUPR3HardenedLdrLoadAppPriv\n"
1536 , pszNmPfx);
1537 else
1538 fprintf(pOutput,
1539 " /* Call RTLdrLoadSystem(const char *pszFilename, bool fNoUnload, PRTLDRMOD phLdrMod); */\n"
1540 " adrp x2, PAGE(g_hMod)\n"
1541 " add x2, x2, PAGEOFF(g_hMod)\n"
1542 " mov x1, #1\n"
1543 " adrp x0, PAGE(g_szLibrary)\n"
1544 " add x0, x0, PAGEOFF(g_szLibrary)\n"
1545 " bl %sRTLdrLoadSystem\n"
1546 , pszNmPfx);
1547 fprintf(pOutput,
1548 " cmp x0, #0\n"
1549 " b.ne Lexplicit_load_return\n"
1550 "\n");
1551
1552 fprintf(pOutput,
1553 " /*\n"
1554 " * Resolve the imports too if requested to do so.\n"
1555 " */\n"
1556 "Lexplicit_loaded_module:\n"
1557 " cmp w20, #0\n"
1558 " b.eq Lexplicit_load_return\n"
1559 "\n"
1560 " adrp x22, PAGE(g_szzNames)\n"
1561 " add x22, x22, PAGEOFF(g_szzNames)\n"
1562 " adrp x23, PAGE(g_apfnImports)\n"
1563 " add x23, x23, PAGEOFF(g_apfnImports)\n"
1564 "Lexplicit_load_next_import:\n"
1565 " ldr x0, [x23]\n"
1566 " cmp x0, #0\n"
1567 " b.eq Lexplicit_load_return\n"
1568 "\n"
1569 " /* Get the module handle and call RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvValue) */\n"
1570 " adrp x0, PAGE(g_hMod)\n"
1571 " ldr x0, [x0, PAGEOFF(g_hMod)]\n"
1572 " mov x1, x22\n"
1573 " mov x2, x23\n"
1574 " bl %sRTLdrGetSymbol\n"
1575 " cmp x0, #0\n"
1576 " b.ne Lexplicit_load_symbol_error\n"
1577 "\n"
1578 " /* Advance. */\n"
1579 " add x23, x23, #8\n"
1580 "Lexplict_load_advance_string:\n"
1581 " ldrb w0, [x22]\n"
1582 " add x22, x22, #1\n"
1583 " cmp w0, #0\n"
1584 " b.ne Lexplict_load_advance_string\n"
1585 " b Lexplicit_load_next_import\n"
1586 "\n"
1587 " /*\n"
1588 " * Error loading a symbol. Call RTErrInfoSet(PRTERRINFO pErrInfo, int rc, const char *pszMsg) on pErrInfo (preserves x0).\n"
1589 " */\n"
1590 "Lexplicit_load_symbol_error:\n"
1591 " mov x2, x22\n"
1592 " mov x1, x0\n"
1593 " mov x0, x21\n"
1594 " bl %sRTErrInfoSet\n"
1595 " b Lexplicit_load_return"
1596 " "
1597 "\n"
1598 "Lexplicit_load_return:\n"
1599 " ldp x22, x23, [sp, #(96 - 32)]\n"
1600 " .cfi_restore x23\n"
1601 " .cfi_restore x22\n"
1602 " ldp x20, x21, [sp, #(96 - 16)]\n"
1603 " .cfi_restore x21\n"
1604 " .cfi_restore x20\n"
1605 "\n"
1606 " ldp x29, x30, [sp, #96]\n"
1607 " .cfi_restore x29\n"
1608 " .cfi_restore x30\n"
1609 " add sp, sp, #(16 + 96)\n"
1610 " ret\n"
1611 " .cfi_endproc\n"
1612 "ENDCODE\n"
1613 "\n"
1614 "\n"
1615 , pszNmPfx, pszNmPfx);
1616 }
1617
1618 return RTEXITCODE_SUCCESS;
1619}
1620
1621
1622/**
1623 * Generates the assembly source code, writing it to g_pszOutput.
1624 *
1625 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
1626 * details has been displayed.
1627 */
1628static RTEXITCODE generateOutput(void)
1629{
1630 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
1631 FILE *pOutput = fopen(g_pszOutput, "w");
1632 if (pOutput)
1633 {
1634 switch (g_enmTarget)
1635 {
1636 case RTLDRARCH_AMD64:
1637 case RTLDRARCH_X86_32:
1638 rcExit = generateOutputInnerX86AndAMD64(pOutput);
1639 break;
1640 case RTLDRARCH_ARM64:
1641 rcExit = generateOutputInnerArm64(pOutput);
1642 break;
1643 default:
1644 rcExit = RTEXITCODE_FAILURE;
1645 break;
1646 }
1647 if (fclose(pOutput))
1648 {
1649 fprintf(stderr, "error: Error closing '%s'.\n", g_pszOutput);
1650 rcExit = RTEXITCODE_FAILURE;
1651 }
1652 }
1653 else
1654 fprintf(stderr, "error: Failed to open '%s' for writing.\n", g_pszOutput);
1655 return rcExit;
1656}
1657
1658
1659/**
1660 * Displays usage information.
1661 *
1662 * @returns RTEXITCODE_SUCCESS.
1663 * @param pszArgv0 The argv[0] string.
1664 */
1665static int usage(const char *pszArgv0)
1666{
1667 const char *pszTmp = strrchr(pszArgv0, '/');
1668 if (pszTmp)
1669 pszArgv0 = pszTmp + 1;
1670 pszTmp = strrchr(pszArgv0, '\\');
1671 if (pszTmp)
1672 pszArgv0 = pszTmp + 1;
1673
1674 /* 0 1 2 3 4 5 6 7 8
1675 012345678901234567890123456789012345678901234567890123456789012345678901234567890 */
1676 printf("VBoxDef2LazyLoad - Lazy DLL/SO/DYLIB loader code generator.\n"
1677 "Copyright (C) 2013-2016 Oracle Corporation\n"
1678 "\n"
1679 "Description:\n"
1680 "------------\n"
1681 "\n"
1682 "Takes a Microsoft-style linker definition file for a library (DLL/SO/DYLIB) and\n"
1683 "generates assembly code which defines stub functions that lazily loads and\n"
1684 "resolves the real symbols before calling them. This is entirely transparent when\n"
1685 "used with functions.\n"
1686 "\n"
1687 "With data symbols it's more messy since the compiler will not invoke code when\n"
1688 "using them, but access them directly (ELF executables) or indirectly (ELF SOs,\n"
1689 "PE, ++). For data symbols use the DATA keyword after the symbol name in the\n"
1690 "def-file and modify the header definition from 'extern type symbol;' to:\n"
1691 "\n"
1692 " DECLASM(type *) LazyGetPtr_<symbol>(void);\n"
1693 " #define <symbol> (*LazyGetPtr_<symbol>())\n"
1694 "\n"
1695 "or, if using --explict-load-function this will work as well:\n"
1696 "\n"
1697 " extern type *g_LazyPtr_<symbol>;\n"
1698 " #define <symbol> (*g_LazyPtr_)\n"
1699 "\n"
1700 "Usage:\n"
1701 "------\n"
1702 "%s [options] --libary <loadname> --output <lazyload.asm> <input.def>\n"
1703 "\n"
1704 "Options:\n"
1705 "--------\n"
1706 " --library <loadname>, -l <loadname>\n"
1707 " The name of the library. This is what will be passed to RTLdrLoadSystem\n"
1708 " or SUPR3HardenedLdrLoadAppPriv.\n"
1709 " --output <filename>, -o <filename>\n"
1710 " The assembly output file.\n"
1711 " --explicit-load-function, --no-explicit-load-function\n"
1712 " Whether to include the explicit load function:\n"
1713 " DECLASM(int) ExplicitlyLoad<basename>(bool fResolveAllImports, pErrInfo);\n"
1714 " The default is not to include it.\n"
1715 " --system\n"
1716 " The library is a system DLL to be loaded using RTLdrLoadSystem.\n"
1717 " The default is to use SUPR3HardenedLdrLoadAppPriv to load it.\n"
1718 "\n"
1719 , pszArgv0);
1720
1721 return RTEXITCODE_SUCCESS;
1722}
1723
1724
1725int main(int argc, char **argv)
1726{
1727 /*
1728 * Parse options.
1729 */
1730 for (int i = 1; i < argc; i++)
1731 {
1732 const char *psz = argv[i];
1733 if (*psz == '-')
1734 {
1735 if (!strcmp(psz, "--output") || !strcmp(psz, "-o"))
1736 {
1737 if (++i >= argc)
1738 {
1739 fprintf(stderr, "syntax error: File name expected after '%s'.\n", psz);
1740 return RTEXITCODE_SYNTAX;
1741 }
1742 g_pszOutput = argv[i];
1743 }
1744 else if (!strcmp(psz, "--library") || !strcmp(psz, "-l"))
1745 {
1746 if (++i >= argc)
1747 {
1748 fprintf(stderr, "syntax error: Library name expected after '%s'.\n", psz);
1749 return RTEXITCODE_SYNTAX;
1750 }
1751 g_pszLibrary = argv[i];
1752 }
1753 else if (!strcmp(psz, "--explicit-load-function"))
1754 g_fWithExplictLoadFunction = true;
1755 else if (!strcmp(psz, "--no-explicit-load-function"))
1756 g_fWithExplictLoadFunction = false;
1757 else if (!strcmp(psz, "--system"))
1758 g_fSystemLibrary = true;
1759 /** @todo Support different load methods so this can be used on system libs and
1760 * such if we like. */
1761 else if ( !strcmp(psz, "--help")
1762 || !strcmp(psz, "-help")
1763 || !strcmp(psz, "-h")
1764 || !strcmp(psz, "-?") )
1765 return usage(argv[0]);
1766 else if ( !strcmp(psz, "--version")
1767 || !strcmp(psz, "-V"))
1768 {
1769 printf("$Revision: 100273 $\n");
1770 return RTEXITCODE_SUCCESS;
1771 }
1772 else
1773 {
1774 fprintf(stderr, "syntax error: Unknown option '%s'.\n", psz);
1775 return RTEXITCODE_SYNTAX;
1776 }
1777 }
1778 else
1779 {
1780 if (g_cInputs >= RT_ELEMENTS(g_apszInputs))
1781 {
1782 fprintf(stderr, "syntax error: Too many input files, max is %d.\n", (int)RT_ELEMENTS(g_apszInputs));
1783 return RTEXITCODE_SYNTAX;
1784 }
1785 g_apszInputs[g_cInputs++] = argv[i];
1786 }
1787 }
1788 if (g_cInputs == 0)
1789 {
1790 fprintf(stderr, "syntax error: No input file specified.\n");
1791 return RTEXITCODE_SYNTAX;
1792 }
1793 if (!g_pszOutput)
1794 {
1795 fprintf(stderr, "syntax error: No output file specified.\n");
1796 return RTEXITCODE_SYNTAX;
1797 }
1798 if (!g_pszLibrary)
1799 {
1800 fprintf(stderr, "syntax error: No library name specified.\n");
1801 return RTEXITCODE_SYNTAX;
1802 }
1803
1804 /*
1805 * Do the job.
1806 */
1807 RTEXITCODE rcExit = parseInputs();
1808 if (rcExit == RTEXITCODE_SUCCESS)
1809 rcExit = generateOutput();
1810 return rcExit;
1811}
1812
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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