VirtualBox

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

Last change on this file since 108509 was 108509, checked in by vboxsync, 2 months ago

bldprogs/VBoxEditElf: Experiment with creating stub linker libraries, bugref:10874

The tool parses a given shared library (.so), extracts the information relevant for linking
and writes the result into a new file which acts as a stub. This way .so files can get much smaller
and be distributed in an SDK style tools package without requiring a lot of disk space.

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

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