VirtualBox

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

Last change on this file since 87282 was 87282, checked in by vboxsync, 4 years ago

VBoxDef2LazyLoad.cpp: Untested arm64 code generator. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.3 KB
Line 
1/* $Id: VBoxDef2LazyLoad.cpp 87282 2021-01-15 20:38:06Z 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-2020 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;
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 ".p2align 2\n");
1031 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
1032 fprintf(pOutput,
1033 ".globl %s%s\n"
1034 "%s%s:\n"
1035 " ldr x9, =g_pfn%s\n"
1036 " blr x9\n",
1037 pszNmPfx, pExp->szName, pszNmPfx, pExp->szName, pExp->szName);
1038 fprintf(pOutput,
1039 "\n"
1040 "\n");
1041
1042 /*
1043 * Import pointers
1044 */
1045 fprintf(pOutput,
1046 ";\n"
1047 "; Import pointers. Initialized to point a lazy loading stubs.\n"
1048 ";\n"
1049 ".section __DATA,__data\n"
1050 ".p2align 2\n"
1051 "g_apfnImports:\n");
1052 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
1053 fprintf(pOutput,
1054 ".globl __imp_%s\n"
1055 "__imp_%s:\n"
1056 ".globl %sg_pfn%s\n"
1057 "%sg_pfn%s:\n"
1058 " .quad ___LazyLoad___%s\n"
1059 "\n",
1060 pExp->szName, pExp->szName,
1061 pszNmPfx, pExp->szName, pszNmPfx, pExp->szName,
1062 pExp->pszExportedNm);
1063 fprintf(pOutput,
1064 " .quad 0 ; Terminator entry for traversal.\n"
1065 "\n"
1066 "\n");
1067
1068 /*
1069 * Now for the less important stuff, starting with the names.
1070 *
1071 * We keep the names separate so we can traverse them in parallel to
1072 * g_apfnImports in the load-everything routine further down.
1073 */
1074 fprintf(pOutput,
1075 ";\n"
1076 "; Imported names.\n"
1077 ";\n"
1078 ".section __TEXT,__cstring,cstring_literals\n"
1079 "g_szLibrary:\n"
1080 " .asciz \"%s\"\n"
1081 "\n"
1082 "g_szzNames:\n",
1083 g_pszLibrary);
1084 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
1085 if (!pExp->fNoName)
1086 fprintf(pOutput, " g_sz%s:\n .asciz \"%s\"\n", pExp->pszExportedNm, pExp->pszExportedNm);
1087 else
1088 fprintf(pOutput, " g_sz%s:\n .asciz \"#%u\"\n", pExp->pszExportedNm, pExp->uOrdinal);
1089 fprintf(pOutput,
1090 "g_EndOfNames: .byte 0\n"
1091 "\n"
1092 "g_szFailLoadFmt: .asciz \"Lazy loader failed to load \\\"%%s\\\": %%Rrc\\n\"\n"
1093 "g_szFailResolveFmt: .asciz \"Lazy loader failed to resolve symbol \\\"%%s\\\" in \\\"%%s\\\": %%Rrc\\n\"\n"
1094 "\n"
1095 "\n");
1096
1097 /*
1098 * The per import lazy load code.
1099 */
1100 fprintf(pOutput,
1101 ";\n"
1102 "; Lazy load+resolve stubs.\n"
1103 ";\n"
1104 ".section __TEXT,__text,regular,pure_instructions\n"
1105 ".p2align 2\n");
1106 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
1107 {
1108 if (!pExp->fNoName)
1109 fprintf(pOutput,
1110 "___LazyLoad___%s:\n"
1111 " ldr x9, =g_sz%s\n"
1112 " ldr x10, =g_pfn%s\n"
1113 " bl LazyLoadResolver\n"
1114 , pExp->pszExportedNm, pExp->pszExportedNm, pExp->pszExportedNm);
1115 else
1116 fprintf(pOutput,
1117 "___LazyLoad___%s:\n"
1118 " movk w9, #%u\n"
1119 " ldr x10, =g_pfn%s\n"
1120 " bl LazyLoadResolver\n"
1121 , pExp->pszExportedNm, pExp->uOrdinal, pExp->pszExportedNm);
1122 fprintf(pOutput, " b %s%s\n", pszNmPfx, pExp->szName);
1123 fprintf(pOutput, "\n");
1124 }
1125 fprintf(pOutput,
1126 "\n"
1127 "\n"
1128 "\n");
1129
1130 /*
1131 * The code that does the loading and resolving.
1132 */
1133 fprintf(pOutput,
1134 ";\n"
1135 "; The module handle.\n"
1136 ";\n"
1137 ".section __DATA,__data\n"
1138 "g_hMod:\n"
1139 " .quad 0\n"
1140 "\n"
1141 "\n"
1142 "\n");
1143
1144 /*
1145 * Common lazy loader and resolved.
1146 */
1147 fprintf(pOutput,
1148 ";\n"
1149 "; The resolver code.\n"
1150 ";\n"
1151 ".section __TEXT,__text,regular,pure_instructions\n"
1152 ".p2align 2\n"
1153 "LazyLoadResolver:\n"
1154 " .cfi_startproc\n"
1155 " ; Create frame.\n"
1156 " sub sp, sp, #(16 + 192)\n"
1157 " stp x29, x30, [sp, #192]\n"
1158 " add x29, sp, #192\n"
1159 " .cfi_def_cfa x29, 16\n"
1160 " .cfi_offset x30, -8\n"
1161 " .cfi_offset x29, -16\n"
1162 " ; Save all argument registers and a handful of preserved ones.\n"
1163 " stp x0, x1, [sp, #(192 - 16)]\n"
1164 " .cfi_offset x0, -32\n"
1165 " .cfi_offset x1, -24\n"
1166 " stp x2, x3, [sp, #(192 - 32)]\n"
1167 " .cfi_offset x3, -40\n"
1168 " .cfi_offset x2, -48\n"
1169 " stp x4, x5, [sp, #(192 - 48)]\n"
1170 " .cfi_offset x6, -56\n"
1171 " .cfi_offset x5, -64\n"
1172 " stp x6, x7, [sp, #(192 - 64)]\n"
1173 " .cfi_offset x7, -72\n"
1174 " .cfi_offset x6, -80\n"
1175 " stp x16, x17, [sp, #(192 - 80)]\n"
1176 " .cfi_offset x17, -88\n"
1177 " .cfi_offset x16, -96\n"
1178 " stp x18, x19, [sp, #(192 - 96)]\n"
1179 " .cfi_offset x19, -104\n"
1180 " .cfi_offset x18, -112\n"
1181 " stp x20, x21, [sp, #(192 - 112)]\n"
1182 " .cfi_offset x21, -120\n"
1183 " .cfi_offset x20, -128\n"
1184 " stp x22, x23, [sp, #(192 - 128)]\n"
1185 " .cfi_offset x23, -136\n"
1186 " .cfi_offset x22, -144\n"
1187 " str x8, [sp, #(192 - 144)]\n"
1188 "\n"
1189 " ; Shift the symbol name to x19 and g_pfnXXXX pointer to x20 as these are preserved registers\n"
1190 " ; (in case we need to call LazyLoadModule/RTLdrLoad)\n"
1191 " mov x19, x9\n"
1192 " mov x20, x10\n"
1193 "\n"
1194 " ; Get the module handle and call RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvValue)\n"
1195 " ldr x0, =g_hMod\n"
1196 " ldr x0, [x0]\n"
1197 " cmp x0, #0\n"
1198 " b.eq LazyLoading\n"
1199 " mov x1, x19\n"
1200 " mov x2, x20\n"
1201 " bl %sRTLdrGetSymbol\n"
1202 "\n"
1203 " cmp w0, #0\n"
1204 " b.eq Lreturn\n"
1205 "\n"
1206 "Lbadsym: ; Call sRTAssertMsg2Weak. Variadic (...) arguments are passed on the stack it seems.\n"
1207 " mov x3, x0\n"
1208 " ldr x2, =g_szLibrary\n"
1209 " mov x1, x19\n"
1210 " ldr x0, =g_szFailLoadFmt\n"
1211 " stp x1, x2, [sp]\n"
1212 " str x3, [sp, #16]\n"
1213 " bl %sRTAssertMsg2Weak\n"
1214 "Lbadsymloop:\n"
1215 " brk #0x1\n"
1216 " b Lbadsymloop\n"
1217
1218 "Lreturn:\n"
1219 " ; Restore saved register\n"
1220 " ldr x8, [sp, #(192 - 144)]\n"
1221 " .cfi_restore x8\n"
1222 " ldp x22, x23, [sp, #(192 - 128)]\n"
1223 " .cfi_restore x23\n"
1224 " .cfi_restore x22\n"
1225 " ldp x20, x21, [sp, #(192 - 112)]\n"
1226 " .cfi_restore x21\n"
1227 " .cfi_restore x20\n"
1228 " ldp x18, x19, [sp, #(192 - 96)]\n"
1229 " .cfi_restore x19\n"
1230 " .cfi_restore x18\n"
1231 " ldp x16, x17, [sp, #(192 - 80)]\n"
1232 " .cfi_restore x17\n"
1233 " .cfi_restore x18\n"
1234 " ldp x6, x7, [sp, #(192 - 64)]\n"
1235 " .cfi_restore x7\n"
1236 " .cfi_restore x6\n"
1237 " ldp x4, x5, [sp, #(192 - 48)]\n"
1238 " .cfi_restore x5\n"
1239 " .cfi_restore x4\n"
1240 " ldp x2, x3, [sp, #(192 - 32)]\n"
1241 " .cfi_restore x3\n"
1242 " .cfi_restore x2\n"
1243 " ldp x0, x1, [sp, #(192 - 16)]\n"
1244 " .cfi_restore x1\n"
1245 " .cfi_restore x0\n"
1246 "\n"
1247 " ldp x29, x30, [sp, #192]\n"
1248 " .cfi_restore x29\n"
1249 " .cfi_restore x30\n"
1250 " add sp, sp, #(16 + 192)\n"
1251 " ret\n"
1252 " .cfi_endproc\n"
1253 "\n"
1254 "\n"
1255 , pszNmPfx, pszNmPfx);
1256
1257 fprintf(pOutput,
1258 ";\n"
1259 "; Loads the module.\n"
1260 "; ASSUMES called from LazyLoadResolver where all relevant registers are already saved.\n"
1261 ";\n"
1262 "LazyLoading:\n"
1263 " .cfi_startproc\n"
1264 " ; Create frame.\n"
1265 " sub sp, sp, #(16 + 48)\n"
1266 " stp x29, x30, [sp, #48]\n"
1267 " add x29, sp, #48\n"
1268 " .cfi_def_cfa x29, 16\n"
1269 " .cfi_offset x30, -8\n"
1270 " .cfi_offset x29, -16\n"
1271 "\n");
1272
1273 if (!g_fSystemLibrary)
1274 fprintf(pOutput,
1275 " ; Call SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo);\n"
1276 " mov x3, #0\n"
1277 " mov x2, #0\n"
1278 " ldr x1, =g_hMod\n"
1279 " ldr x0, =g_szLibrary\n"
1280 " bl %sSUPR3HardenedLdrLoadAppPriv\n"
1281 , pszNmPfx);
1282 else
1283 fprintf(pOutput,
1284 " ; Call RTLdrLoadSystem(const char *pszFilename, bool fNoUnload, PRTLDRMOD phLdrMod);\n"
1285 " ldr x2, =g_hMod\n"
1286 " mov x1, #1\n"
1287 " ldr x0, =g_szLibrary\n"
1288 " bl %sRTLdrLoadSystem\n"
1289 , pszNmPfx);
1290
1291 fprintf(pOutput,
1292 " cmp w0, #0\n"
1293 " b.eq Lload_return\n"
1294 "\n"
1295 "Lbadload: ; Call sRTAssertMsg2Weak. Variadic (...) arguments are passed on the stack it seems.\n"
1296 " mov x2, x0\n"
1297 " ldr x1, =g_szLibrary\n"
1298 " ldr x0, =g_szFailResolveFmt\n"
1299 " stp x1, x2, [sp]\n"
1300 " bl %sRTAssertMsg2Weak\n"
1301 "Lbadloadloop:\n"
1302 " brk #0x1\n"
1303 " b Lbadloadloop\n"
1304 "Lload_return:\n"
1305 " ldr x0, =g_hMod\n"
1306 " ldr x0, [x0]\n"
1307 " ldp x29, x30, [sp, #48]\n"
1308 " .cfi_restore x29\n"
1309 " .cfi_restore x30\n"
1310 " add sp, sp, #(16 + 48)\n"
1311 " ret\n"
1312 " .cfi_endproc\n"
1313 "\n"
1314 "\n"
1315 , pszNmPfx);
1316
1317 /*
1318 * C callable method for explicitly loading the library and optionally
1319 * resolving all the imports.
1320 */
1321 if (g_fWithExplictLoadFunction)
1322 {
1323 if (g_fSystemLibrary) /* Lazy bird. */
1324 {
1325 fprintf(stderr, "error: cannot use --system with --explicit-load-function, sorry\n");
1326 return RTEXITCODE_FAILURE;
1327 }
1328
1329 int cchLibBaseName = (int)(strchr(g_pszLibrary, '.') ? strchr(g_pszLibrary, '.') - g_pszLibrary : strlen(g_pszLibrary));
1330 fprintf(pOutput,
1331 ";;\n"
1332 "; ExplicitlyLoad%.*s(bool fResolveAllImports, pErrInfo);\n"
1333 ";\n"
1334 ".section __TEXT,__text,regular,pure_instructions\n"
1335 ".p2align 2\n"
1336 ".globl ExplicitlyLoad%.*s\n"
1337 "ExplicitlyLoad%.*s:\n"
1338 " .cfi_startproc\n"
1339 " ; Create frame.\n"
1340 " sub sp, sp, #(16 + #96)\n"
1341 " stp x29, x30, [sp, #96]\n"
1342 " add x29, sp, #96\n"
1343 " .cfi_def_cfa x29, 16\n"
1344 " .cfi_offset x30, -8\n"
1345 " .cfi_offset x29, -16\n"
1346 "\n"
1347 " stp x20, x21, [sp, #(96 - 16)]\n"
1348 " .cfi_offset x21, -24\n"
1349 " .cfi_offset x20, -32\n"
1350 " stp x22, x23, [sp, #(96 - 32)]\n"
1351 " .cfi_offset x23, -40\n"
1352 " .cfi_offset x22, -48\n"
1353
1354 " ; Save the input parameters.\n"
1355 " mov x20, x0\n"
1356 " mov x21, x1\n"
1357 "\n"
1358 " ;\n"
1359 " ; Is the module already loaded?\n"
1360 " ;\n"
1361 " ldr x0, =g_hMod\n"
1362 " ldr x0, [x0]\n"
1363 " cmp x0, #0\n"
1364 " b.ne Lexplicit_loaded_module\n"
1365 "\n"
1366 ,
1367 cchLibBaseName, g_pszLibrary,
1368 cchLibBaseName, g_pszLibrary,
1369 cchLibBaseName, g_pszLibrary);
1370 fprintf(pOutput,
1371 "Lexplicit_load_module:\n"
1372 " ; Call SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo);\n"
1373 " mov x3, #0\n"
1374 " mov x2, #0\n"
1375 " ldr x1, =g_hMod\n"
1376 " ldr x0, =g_szLibrary\n"
1377 " bl %sSUPR3HardenedLdrLoadAppPriv\n"
1378 " cmp x0, #0\n"
1379 " b.ne Lexplicit_load_return\n"
1380 "\n"
1381 , pszNmPfx);
1382
1383 fprintf(pOutput,
1384 " ;\n"
1385 " ; Resolve the imports too if requested to do so.\n"
1386 " ;\n"
1387 "Lexplicit_loaded_module:\n"
1388 " cmp w20, #0\n"
1389 " b.eq Lexplicit_load_return\n"
1390 "\n"
1391 " ldr x22, =g_szzNames\n"
1392 " ldr x23, =g_apfnImports\n"
1393 "Lexplicit_load_next_import:\n"
1394 " ldr x0, [x23]\n"
1395 " cmp x0, #0\n"
1396 " b.eq Lexplicit_load_return\n"
1397 "\n"
1398 " ; Get the module handle and call RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvValue)\n"
1399 " ldr x0, =g_hMod\n"
1400 " ldr x0, [x0]\n"
1401 " mov x1, x22\n"
1402 " mov x2, x23\n"
1403 " bl %sRTLdrGetSymbol\n"
1404 " cmp x0, #0\n"
1405 " b.ne Lexplicit_load_symbol_error\n"
1406 "\n"
1407 " ; Advance.\n"
1408 " add x23, x23, #8\n"
1409 "Lexplict_load_advance_string:\n"
1410 " ldrb w0, [x22]\n"
1411 " add x22, x22, #1\n"
1412 " cmp w0, #0\n"
1413 " b.ne Lexplict_load_advance_string\n"
1414 " b Lexplicit_load_next_import\n"
1415 "\n"
1416 " ;\n"
1417 " ; Error loading a symbol. Call RTErrInfoSet(PRTERRINFO pErrInfo, int rc, const char *pszMsg) on pErrInfo (preserves x0).\n"
1418 " ;\n"
1419 "Lexplicit_load_symbol_error:\n"
1420 " mov x2, x22\n"
1421 " mov x1, x0\n"
1422 " mov x0, x21\n"
1423 " bl %sRTErrInfoSet\n"
1424 " b Lexplicit_load_return"
1425 " "
1426 "\n"
1427 "Lexplicit_load_return:\n"
1428 " ldp x22, x23, [sp, #(96 - 32)]\n"
1429 " .cfi_restore x23\n"
1430 " .cfi_restore x22\n"
1431 " ldp x20, x21, [sp, #(96 - 16)]\n"
1432 " .cfi_restore x21\n"
1433 " .cfi_restore x20\n"
1434 "\n"
1435 " ldp x29, x30, [sp, #96]\n"
1436 " .cfi_restore x29\n"
1437 " .cfi_restore x30\n"
1438 " add sp, sp, #(16 + 96)\n"
1439 " ret\n"
1440 " .cfi_endproc\n"
1441 "\n"
1442 "\n"
1443 , pszNmPfx, pszNmPfx);
1444 }
1445
1446 return RTEXITCODE_SUCCESS;
1447}
1448
1449
1450/**
1451 * Generates the assembly source code, writing it to g_pszOutput.
1452 *
1453 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
1454 * details has been displayed.
1455 */
1456static RTEXITCODE generateOutput(void)
1457{
1458 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
1459 FILE *pOutput = fopen(g_pszOutput, "w");
1460 if (pOutput)
1461 {
1462 switch (g_enmTarget)
1463 {
1464 case RTLDRARCH_AMD64:
1465 case RTLDRARCH_X86_32:
1466 rcExit = generateOutputInnerX86AndAMD64(pOutput);
1467 break;
1468 case RTLDRARCH_ARM64:
1469 rcExit = generateOutputInnerArm64(pOutput);
1470 break;
1471 default:
1472 rcExit = RTEXITCODE_FAILURE;
1473 break;
1474 }
1475 if (fclose(pOutput))
1476 {
1477 fprintf(stderr, "error: Error closing '%s'.\n", g_pszOutput);
1478 rcExit = RTEXITCODE_FAILURE;
1479 }
1480 }
1481 else
1482 fprintf(stderr, "error: Failed to open '%s' for writing.\n", g_pszOutput);
1483 return rcExit;
1484}
1485
1486
1487/**
1488 * Displays usage information.
1489 *
1490 * @returns RTEXITCODE_SUCCESS.
1491 * @param pszArgv0 The argv[0] string.
1492 */
1493static int usage(const char *pszArgv0)
1494{
1495 printf("usage: %s [options] --libary <loadname> --output <lazyload.asm> <input.def>\n"
1496 "\n"
1497 "Options:\n"
1498 " --explicit-load-function, --no-explicit-load-function\n"
1499 " Whether to include the explicit load function, default is not to.\n"
1500 "\n"
1501 "Copyright (C) 2013-2016 Oracle Corporation\n"
1502 , pszArgv0);
1503
1504 return RTEXITCODE_SUCCESS;
1505}
1506
1507
1508int main(int argc, char **argv)
1509{
1510 /*
1511 * Parse options.
1512 */
1513 for (int i = 1; i < argc; i++)
1514 {
1515 const char *psz = argv[i];
1516 if (*psz == '-')
1517 {
1518 if (!strcmp(psz, "--output") || !strcmp(psz, "-o"))
1519 {
1520 if (++i >= argc)
1521 {
1522 fprintf(stderr, "syntax error: File name expected after '%s'.\n", psz);
1523 return RTEXITCODE_SYNTAX;
1524 }
1525 g_pszOutput = argv[i];
1526 }
1527 else if (!strcmp(psz, "--library") || !strcmp(psz, "-l"))
1528 {
1529 if (++i >= argc)
1530 {
1531 fprintf(stderr, "syntax error: Library name expected after '%s'.\n", psz);
1532 return RTEXITCODE_SYNTAX;
1533 }
1534 g_pszLibrary = argv[i];
1535 }
1536 else if (!strcmp(psz, "--explicit-load-function"))
1537 g_fWithExplictLoadFunction = true;
1538 else if (!strcmp(psz, "--no-explicit-load-function"))
1539 g_fWithExplictLoadFunction = false;
1540 else if (!strcmp(psz, "--system"))
1541 g_fSystemLibrary = true;
1542 /** @todo Support different load methods so this can be used on system libs and
1543 * such if we like. */
1544 else if ( !strcmp(psz, "--help")
1545 || !strcmp(psz, "-help")
1546 || !strcmp(psz, "-h")
1547 || !strcmp(psz, "-?") )
1548 return usage(argv[0]);
1549 else if ( !strcmp(psz, "--version")
1550 || !strcmp(psz, "-V"))
1551 {
1552 printf("$Revision: 87282 $\n");
1553 return RTEXITCODE_SUCCESS;
1554 }
1555 else
1556 {
1557 fprintf(stderr, "syntax error: Unknown option '%s'.\n", psz);
1558 return RTEXITCODE_SYNTAX;
1559 }
1560 }
1561 else
1562 {
1563 if (g_cInputs >= RT_ELEMENTS(g_apszInputs))
1564 {
1565 fprintf(stderr, "syntax error: Too many input files, max is %d.\n", (int)RT_ELEMENTS(g_apszInputs));
1566 return RTEXITCODE_SYNTAX;
1567 }
1568 g_apszInputs[g_cInputs++] = argv[i];
1569 }
1570 }
1571 if (g_cInputs == 0)
1572 {
1573 fprintf(stderr, "syntax error: No input file specified.\n");
1574 return RTEXITCODE_SYNTAX;
1575 }
1576 if (!g_pszOutput)
1577 {
1578 fprintf(stderr, "syntax error: No output file specified.\n");
1579 return RTEXITCODE_SYNTAX;
1580 }
1581 if (!g_pszLibrary)
1582 {
1583 fprintf(stderr, "syntax error: No library name specified.\n");
1584 return RTEXITCODE_SYNTAX;
1585 }
1586
1587 /*
1588 * Do the job.
1589 */
1590 RTEXITCODE rcExit = parseInputs();
1591 if (rcExit == RTEXITCODE_SUCCESS)
1592 rcExit = generateOutput();
1593 return rcExit;
1594}
1595
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