VirtualBox

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

Last change on this file was 104213, checked in by vboxsync, 6 weeks ago

bldprogs/VBoxDef2LazyLoad: Get it working on linux.arm64/ELF, bugref:10391

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

© 2023 Oracle
ContactPrivacy policyTerms of Use