VirtualBox

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

Last change on this file since 99030 was 98660, checked in by vboxsync, 19 months ago

VBoxDef2LazyLoad.cpp: Improve a few error messages and comments.

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

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