VirtualBox

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

Last change on this file since 93484 was 93484, checked in by vboxsync, 3 years ago

VBoxDef2LazyLoad.cpp: More arm64 tweaks. bugref:9898

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