]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFw/Elf64Convert.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
CommitLineData
f51461c8 1/** @file\r
97fa0ee9 2Elf64 convert solution\r
f51461c8 3\r
251f9b39 4Copyright (c) 2010 - 2021, Intel Corporation. All rights reserved.<BR>\r
1ee16228 5Portions copyright (c) 2013-2022, ARM Ltd. All rights reserved.<BR>\r
ad1db975 6Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>\r
1aa311d1 7Portions Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR>\r
f51461c8 8\r
2e351cbe 9SPDX-License-Identifier: BSD-2-Clause-Patent\r
f51461c8
LG
10\r
11**/\r
12\r
13#include "WinNtInclude.h"\r
14\r
15#ifndef __GNUC__\r
16#include <windows.h>\r
17#include <io.h>\r
18#endif\r
19#include <assert.h>\r
20#include <stdio.h>\r
21#include <stdlib.h>\r
22#include <string.h>\r
23#include <time.h>\r
24#include <ctype.h>\r
25\r
26#include <Common/UefiBaseTypes.h>\r
27#include <IndustryStandard/PeImage.h>\r
28\r
29#include "PeCoffLib.h"\r
30#include "EfiUtilityMsgs.h"\r
31\r
32#include "GenFw.h"\r
33#include "ElfConvert.h"\r
34#include "Elf64Convert.h"\r
35\r
36STATIC\r
37VOID\r
38ScanSections64 (\r
39 VOID\r
40 );\r
41\r
42STATIC\r
43BOOLEAN\r
44WriteSections64 (\r
45 SECTION_FILTER_TYPES FilterType\r
46 );\r
47\r
48STATIC\r
49VOID\r
50WriteRelocations64 (\r
51 VOID\r
52 );\r
53\r
54STATIC\r
55VOID\r
56WriteDebug64 (\r
57 VOID\r
58 );\r
59\r
414cd2a4
HLX
60STATIC\r
61VOID\r
62WriteExport64 (\r
63 VOID\r
64 );\r
65\r
f51461c8
LG
66STATIC\r
67VOID\r
68SetImageSize64 (\r
69 VOID\r
70 );\r
71\r
72STATIC\r
73VOID\r
74CleanUp64 (\r
75 VOID\r
76 );\r
77\r
78//\r
fb0b35e0 79// Rename ELF32 structures to common names to help when porting to ELF64.\r
f51461c8
LG
80//\r
81typedef Elf64_Shdr Elf_Shdr;\r
82typedef Elf64_Ehdr Elf_Ehdr;\r
83typedef Elf64_Rel Elf_Rel;\r
84typedef Elf64_Rela Elf_Rela;\r
85typedef Elf64_Sym Elf_Sym;\r
86typedef Elf64_Phdr Elf_Phdr;\r
87typedef Elf64_Dyn Elf_Dyn;\r
88#define ELFCLASS ELFCLASS64\r
89#define ELF_R_TYPE(r) ELF64_R_TYPE(r)\r
90#define ELF_R_SYM(r) ELF64_R_SYM(r)\r
91\r
92//\r
93// Well known ELF structures.\r
94//\r
95STATIC Elf_Ehdr *mEhdr;\r
96STATIC Elf_Shdr *mShdrBase;\r
97STATIC Elf_Phdr *mPhdrBase;\r
98\r
ecbaa856
Z
99//\r
100// GOT information\r
101//\r
102STATIC Elf_Shdr *mGOTShdr = NULL;\r
103STATIC UINT32 mGOTShindex = 0;\r
104STATIC UINT32 *mGOTCoffEntries = NULL;\r
105STATIC UINT32 mGOTMaxCoffEntries = 0;\r
106STATIC UINT32 mGOTNumCoffEntries = 0;\r
107\r
f51461c8
LG
108//\r
109// Coff information\r
110//\r
54b1b57a 111STATIC UINT32 mCoffAlignment = 0x20;\r
f51461c8
LG
112\r
113//\r
114// PE section alignment.\r
115//\r
414cd2a4 116STATIC UINT16 mCoffNbrSections = 4;\r
f51461c8
LG
117\r
118//\r
119// ELF sections to offset in Coff file.\r
120//\r
121STATIC UINT32 *mCoffSectionsOffset = NULL;\r
122\r
123//\r
124// Offsets in COFF file\r
125//\r
126STATIC UINT32 mNtHdrOffset;\r
127STATIC UINT32 mTextOffset;\r
128STATIC UINT32 mDataOffset;\r
129STATIC UINT32 mHiiRsrcOffset;\r
130STATIC UINT32 mRelocOffset;\r
0192b71c 131STATIC UINT32 mDebugOffset;\r
414cd2a4 132STATIC UINT32 mExportOffset;\r
ad1db975
AC
133//\r
134// Used for RISC-V relocations.\r
135//\r
136STATIC UINT8 *mRiscVPass1Targ = NULL;\r
137STATIC Elf_Shdr *mRiscVPass1Sym = NULL;\r
138STATIC Elf64_Half mRiscVPass1SymSecIndex = 0;\r
abfff7c4
S
139STATIC INT32 mRiscVPass1Offset;\r
140STATIC INT32 mRiscVPass1GotFixup;\r
ad1db975 141\r
414cd2a4
HLX
142//\r
143// Used for Export section.\r
144//\r
145STATIC UINT32 mExportSize;\r
146STATIC UINT32 mExportRVA[PRM_MODULE_EXPORT_SYMBOL_NUM];\r
147STATIC UINT32 mExportSymNum;\r
148STATIC CHAR8 mExportSymName[PRM_MODULE_EXPORT_SYMBOL_NUM][PRM_HANDLER_NAME_MAXIMUM_LENGTH];\r
149\r
f51461c8
LG
150//\r
151// Initialization Function\r
152//\r
153BOOLEAN\r
154InitializeElf64 (\r
155 UINT8 *FileBuffer,\r
156 ELF_FUNCTION_TABLE *ElfFunctions\r
157 )\r
158{\r
159 //\r
160 // Initialize data pointer and structures.\r
161 //\r
162 VerboseMsg ("Set EHDR");\r
163 mEhdr = (Elf_Ehdr*) FileBuffer;\r
164\r
165 //\r
166 // Check the ELF64 specific header information.\r
167 //\r
168 VerboseMsg ("Check ELF64 Header Information");\r
169 if (mEhdr->e_ident[EI_CLASS] != ELFCLASS64) {\r
170 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFCLASS64");\r
171 return FALSE;\r
172 }\r
173 if (mEhdr->e_ident[EI_DATA] != ELFDATA2LSB) {\r
174 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB");\r
175 return FALSE;\r
176 }\r
177 if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) {\r
178 Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN");\r
179 return FALSE;\r
180 }\r
1aa311d1 181 if (!((mEhdr->e_machine == EM_X86_64) || (mEhdr->e_machine == EM_AARCH64) || (mEhdr->e_machine == EM_RISCV64) || (mEhdr->e_machine == EM_LOONGARCH))) {\r
251f9b39 182 Warning (NULL, 0, 3000, "Unsupported", "ELF e_machine is not Elf64 machine.");\r
f51461c8
LG
183 }\r
184 if (mEhdr->e_version != EV_CURRENT) {\r
185 Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT);\r
186 return FALSE;\r
187 }\r
188\r
414cd2a4 189 if (mExportFlag) {\r
1ee16228
JM
190 if ((mEhdr->e_machine != EM_X86_64) && (mEhdr->e_machine != EM_AARCH64)) {\r
191 Error (NULL, 0, 3000, "Unsupported", "--prm option currently only supports X64 and AArch64 archs.");\r
414cd2a4
HLX
192 return FALSE;\r
193 }\r
194 }\r
195\r
f51461c8
LG
196 //\r
197 // Update section header pointers\r
198 //\r
199 VerboseMsg ("Update Header Pointers");\r
200 mShdrBase = (Elf_Shdr *)((UINT8 *)mEhdr + mEhdr->e_shoff);\r
201 mPhdrBase = (Elf_Phdr *)((UINT8 *)mEhdr + mEhdr->e_phoff);\r
202\r
203 //\r
204 // Create COFF Section offset buffer and zero.\r
205 //\r
206 VerboseMsg ("Create COFF Section Offset Buffer");\r
207 mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32));\r
06b45735
HW
208 if (mCoffSectionsOffset == NULL) {\r
209 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
210 return FALSE;\r
211 }\r
f51461c8
LG
212 memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32));\r
213\r
214 //\r
215 // Fill in function pointers.\r
216 //\r
217 VerboseMsg ("Fill in Function Pointers");\r
218 ElfFunctions->ScanSections = ScanSections64;\r
219 ElfFunctions->WriteSections = WriteSections64;\r
220 ElfFunctions->WriteRelocations = WriteRelocations64;\r
221 ElfFunctions->WriteDebug = WriteDebug64;\r
222 ElfFunctions->SetImageSize = SetImageSize64;\r
223 ElfFunctions->CleanUp = CleanUp64;\r
224\r
414cd2a4
HLX
225 if (mExportFlag) {\r
226 mCoffNbrSections ++;\r
227 ElfFunctions->WriteExport = WriteExport64;\r
228 }\r
229\r
f51461c8
LG
230 return TRUE;\r
231}\r
232\r
233\r
234//\r
235// Header by Index functions\r
236//\r
237STATIC\r
238Elf_Shdr*\r
239GetShdrByIndex (\r
240 UINT32 Num\r
241 )\r
242{\r
17751c5f
ML
243 if (Num >= mEhdr->e_shnum) {\r
244 Error (NULL, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num);\r
245 exit(EXIT_FAILURE);\r
246 }\r
247\r
f51461c8
LG
248 return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);\r
249}\r
250\r
251STATIC\r
252UINT32\r
253CoffAlign (\r
254 UINT32 Offset\r
255 )\r
256{\r
257 return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);\r
258}\r
259\r
4f7d5c67
AB
260STATIC\r
261UINT32\r
262DebugRvaAlign (\r
263 UINT32 Offset\r
264 )\r
265{\r
266 return (Offset + 3) & ~3;\r
267}\r
268\r
f51461c8
LG
269//\r
270// filter functions\r
271//\r
272STATIC\r
273BOOLEAN\r
274IsTextShdr (\r
275 Elf_Shdr *Shdr\r
276 )\r
277{\r
1b380aa6
LG
278 return (BOOLEAN) (((Shdr->sh_flags & (SHF_EXECINSTR | SHF_ALLOC)) == (SHF_EXECINSTR | SHF_ALLOC)) ||\r
279 ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC));\r
f51461c8
LG
280}\r
281\r
282STATIC\r
283BOOLEAN\r
284IsHiiRsrcShdr (\r
285 Elf_Shdr *Shdr\r
286 )\r
287{\r
288 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
289\r
290 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);\r
291}\r
292\r
414cd2a4
HLX
293STATIC\r
294BOOLEAN\r
295IsSymbolShdr (\r
296 Elf_Shdr *Shdr\r
297 )\r
298{\r
299 Elf_Shdr *Namehdr = GetShdrByIndex(mEhdr->e_shstrndx);\r
300\r
301 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namehdr->sh_offset + Shdr->sh_name, ELF_SYMBOL_SECTION_NAME) == 0);\r
302}\r
303\r
f51461c8
LG
304STATIC\r
305BOOLEAN\r
306IsDataShdr (\r
307 Elf_Shdr *Shdr\r
308 )\r
309{\r
310 if (IsHiiRsrcShdr(Shdr)) {\r
311 return FALSE;\r
312 }\r
c6b872c6 313 return (BOOLEAN) (Shdr->sh_flags & (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);\r
f51461c8
LG
314}\r
315\r
621bb723
ML
316STATIC\r
317BOOLEAN\r
318IsStrtabShdr (\r
319 Elf_Shdr *Shdr\r
320 )\r
321{\r
322 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
323\r
324 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_STRTAB_SECTION_NAME) == 0);\r
325}\r
326\r
327STATIC\r
328Elf_Shdr *\r
329FindStrtabShdr (\r
330 VOID\r
331 )\r
332{\r
333 UINT32 i;\r
334 for (i = 0; i < mEhdr->e_shnum; i++) {\r
335 Elf_Shdr *shdr = GetShdrByIndex(i);\r
336 if (IsStrtabShdr(shdr)) {\r
337 return shdr;\r
338 }\r
339 }\r
340 return NULL;\r
341}\r
342\r
343STATIC\r
344const UINT8 *\r
345GetSymName (\r
346 Elf_Sym *Sym\r
347 )\r
348{\r
7be7b25d
HW
349 Elf_Shdr *StrtabShdr;\r
350 UINT8 *StrtabContents;\r
351 BOOLEAN foundEnd;\r
352 UINT32 i;\r
353\r
621bb723
ML
354 if (Sym->st_name == 0) {\r
355 return NULL;\r
356 }\r
357\r
7be7b25d 358 StrtabShdr = FindStrtabShdr();\r
621bb723
ML
359 if (StrtabShdr == NULL) {\r
360 return NULL;\r
361 }\r
362\r
363 assert(Sym->st_name < StrtabShdr->sh_size);\r
364\r
7be7b25d 365 StrtabContents = (UINT8*)mEhdr + StrtabShdr->sh_offset;\r
ea3e924a 366\r
7be7b25d 367 foundEnd = FALSE;\r
a754c70c 368 for (i= Sym->st_name; (i < StrtabShdr->sh_size) && !foundEnd; i++) {\r
7be7b25d 369 foundEnd = (BOOLEAN)(StrtabContents[i] == 0);\r
ea3e924a
ML
370 }\r
371 assert(foundEnd);\r
372\r
373 return StrtabContents + Sym->st_name;\r
621bb723
ML
374}\r
375\r
414cd2a4
HLX
376//\r
377// Get Prm Handler number and name\r
378//\r
379STATIC\r
380VOID\r
381FindPrmHandler (\r
382 UINT64 Offset\r
383 )\r
384{\r
385 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER *PrmExport;\r
386 PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT *PrmHandler;\r
387 UINT32 HandlerNum;\r
388\r
389 PrmExport = (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER*)((UINT8*)mEhdr + Offset);\r
390 PrmHandler = (PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT *)(PrmExport + 1);\r
391\r
392 for (HandlerNum = 0; HandlerNum < PrmExport->NumberPrmHandlers; HandlerNum++) {\r
393 strcpy(mExportSymName[mExportSymNum], PrmHandler->PrmHandlerName);\r
394 mExportSymNum ++;\r
395 PrmHandler += 1;\r
396\r
397 //\r
398 // Check if PRM handler number is larger than (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)\r
399 //\r
400 if (mExportSymNum >= (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)) {\r
401 Error (NULL, 0, 3000, "Invalid", "FindPrmHandler: Number %u is too high.", mExportSymNum);\r
402 exit(EXIT_FAILURE);\r
403 }\r
404 }\r
405}\r
406\r
ecbaa856
Z
407//\r
408// Find the ELF section hosting the GOT from an ELF Rva\r
409// of a single GOT entry. Normally, GOT is placed in\r
410// ELF .text section, so assume once we find in which\r
411// section the GOT is, all GOT entries are there, and\r
412// just verify this.\r
413//\r
414STATIC\r
415VOID\r
416FindElfGOTSectionFromGOTEntryElfRva (\r
417 Elf64_Addr GOTEntryElfRva\r
418 )\r
419{\r
420 UINT32 i;\r
421 if (mGOTShdr != NULL) {\r
422 if (GOTEntryElfRva >= mGOTShdr->sh_addr &&\r
423 GOTEntryElfRva < mGOTShdr->sh_addr + mGOTShdr->sh_size) {\r
424 return;\r
425 }\r
426 Error (NULL, 0, 3000, "Unsupported", "FindElfGOTSectionFromGOTEntryElfRva: GOT entries found in multiple sections.");\r
427 exit(EXIT_FAILURE);\r
428 }\r
429 for (i = 0; i < mEhdr->e_shnum; i++) {\r
430 Elf_Shdr *shdr = GetShdrByIndex(i);\r
431 if (GOTEntryElfRva >= shdr->sh_addr &&\r
432 GOTEntryElfRva < shdr->sh_addr + shdr->sh_size) {\r
433 mGOTShdr = shdr;\r
434 mGOTShindex = i;\r
435 return;\r
436 }\r
437 }\r
438 Error (NULL, 0, 3000, "Invalid", "FindElfGOTSectionFromGOTEntryElfRva: ElfRva 0x%016LX for GOT entry not found in any section.", GOTEntryElfRva);\r
439 exit(EXIT_FAILURE);\r
440}\r
441\r
442//\r
443// Stores locations of GOT entries in COFF image.\r
444// Returns TRUE if GOT entry is new.\r
445// Simple implementation as number of GOT\r
446// entries is expected to be low.\r
447//\r
448\r
449STATIC\r
450BOOLEAN\r
451AccumulateCoffGOTEntries (\r
452 UINT32 GOTCoffEntry\r
453 )\r
454{\r
455 UINT32 i;\r
456 if (mGOTCoffEntries != NULL) {\r
457 for (i = 0; i < mGOTNumCoffEntries; i++) {\r
458 if (mGOTCoffEntries[i] == GOTCoffEntry) {\r
459 return FALSE;\r
460 }\r
461 }\r
462 }\r
463 if (mGOTCoffEntries == NULL) {\r
464 mGOTCoffEntries = (UINT32*)malloc(5 * sizeof *mGOTCoffEntries);\r
465 if (mGOTCoffEntries == NULL) {\r
466 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
467 }\r
468 assert (mGOTCoffEntries != NULL);\r
469 mGOTMaxCoffEntries = 5;\r
470 mGOTNumCoffEntries = 0;\r
471 } else if (mGOTNumCoffEntries == mGOTMaxCoffEntries) {\r
472 mGOTCoffEntries = (UINT32*)realloc(mGOTCoffEntries, 2 * mGOTMaxCoffEntries * sizeof *mGOTCoffEntries);\r
473 if (mGOTCoffEntries == NULL) {\r
474 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
475 }\r
476 assert (mGOTCoffEntries != NULL);\r
477 mGOTMaxCoffEntries += mGOTMaxCoffEntries;\r
478 }\r
479 mGOTCoffEntries[mGOTNumCoffEntries++] = GOTCoffEntry;\r
480 return TRUE;\r
481}\r
482\r
483//\r
484// 32-bit Unsigned integer comparator for qsort.\r
485//\r
486STATIC\r
487int\r
488UINT32Comparator (\r
489 const void* lhs,\r
490 const void* rhs\r
491 )\r
492{\r
493 if (*(const UINT32*)lhs < *(const UINT32*)rhs) {\r
494 return -1;\r
495 }\r
496 return *(const UINT32*)lhs > *(const UINT32*)rhs;\r
497}\r
498\r
499//\r
500// Emit accumulated Coff GOT entry relocations into\r
501// Coff image. This function performs its job\r
502// once and then releases the entry list, so\r
503// it can safely be called multiple times.\r
504//\r
505STATIC\r
506VOID\r
507EmitGOTRelocations (\r
508 VOID\r
509 )\r
510{\r
511 UINT32 i;\r
512 if (mGOTCoffEntries == NULL) {\r
513 return;\r
514 }\r
515 //\r
516 // Emit Coff relocations with Rvas ordered.\r
517 //\r
518 qsort(\r
519 mGOTCoffEntries,\r
520 mGOTNumCoffEntries,\r
521 sizeof *mGOTCoffEntries,\r
522 UINT32Comparator);\r
523 for (i = 0; i < mGOTNumCoffEntries; i++) {\r
524 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", mGOTCoffEntries[i]);\r
525 CoffAddFixup(\r
526 mGOTCoffEntries[i],\r
527 EFI_IMAGE_REL_BASED_DIR64);\r
528 }\r
529 free(mGOTCoffEntries);\r
530 mGOTCoffEntries = NULL;\r
531 mGOTMaxCoffEntries = 0;\r
532 mGOTNumCoffEntries = 0;\r
533}\r
ad1db975
AC
534//\r
535// RISC-V 64 specific Elf WriteSection function.\r
536//\r
537STATIC\r
538VOID\r
539WriteSectionRiscV64 (\r
540 Elf_Rela *Rel,\r
541 UINT8 *Targ,\r
542 Elf_Shdr *SymShdr,\r
543 Elf_Sym *Sym\r
544 )\r
545{\r
546 UINT32 Value;\r
547 UINT32 Value2;\r
abfff7c4 548 Elf64_Addr GOTEntryRva;\r
ad1db975
AC
549\r
550 switch (ELF_R_TYPE(Rel->r_info)) {\r
551 case R_RISCV_NONE:\r
552 break;\r
553\r
554 case R_RISCV_32:\r
abfff7c4 555 *(UINT64 *)Targ = Sym->st_value + Rel->r_addend;\r
ad1db975
AC
556 break;\r
557\r
558 case R_RISCV_64:\r
abfff7c4 559 *(UINT64 *)Targ = Sym->st_value + Rel->r_addend;\r
ad1db975
AC
560 break;\r
561\r
562 case R_RISCV_HI20:\r
563 mRiscVPass1Targ = Targ;\r
564 mRiscVPass1Sym = SymShdr;\r
565 mRiscVPass1SymSecIndex = Sym->st_shndx;\r
566 break;\r
567\r
568 case R_RISCV_LO12_I:\r
569 if (mRiscVPass1Sym == SymShdr && mRiscVPass1Targ != NULL && mRiscVPass1SymSecIndex == Sym->st_shndx && mRiscVPass1SymSecIndex != 0) {\r
570 Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20) << 12);\r
571 Value2 = (UINT32)(RV_X(*(UINT32 *)Targ, 20, 12));\r
572 if (Value2 & (RISCV_IMM_REACH/2)) {\r
573 Value2 |= ~(RISCV_IMM_REACH-1);\r
574 }\r
575 Value += Value2;\r
576 Value = Value - (UINT32)SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
577 Value2 = RISCV_CONST_HIGH_PART (Value);\r
578 *(UINT32 *)mRiscVPass1Targ = (RV_X (Value2, 12, 20) << 12) | \\r
579 (RV_X (*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
580 *(UINT32 *)Targ = (RV_X (Value, 0, 12) << 20) | \\r
581 (RV_X (*(UINT32 *)Targ, 0, 20));\r
582 }\r
583 mRiscVPass1Sym = NULL;\r
584 mRiscVPass1Targ = NULL;\r
585 mRiscVPass1SymSecIndex = 0;\r
586 break;\r
587\r
588 case R_RISCV_LO12_S:\r
589 if (mRiscVPass1Sym == SymShdr && mRiscVPass1Targ != NULL && mRiscVPass1SymSecIndex == Sym->st_shndx && mRiscVPass1SymSecIndex != 0) {\r
590 Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20) << 12);\r
591 Value2 = (UINT32)(RV_X(*(UINT32 *)Targ, 7, 5) | (RV_X(*(UINT32 *)Targ, 25, 7) << 5));\r
592 if (Value2 & (RISCV_IMM_REACH/2)) {\r
593 Value2 |= ~(RISCV_IMM_REACH-1);\r
594 }\r
595 Value += Value2;\r
596 Value = Value - (UINT32)SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
597 Value2 = RISCV_CONST_HIGH_PART (Value);\r
598 *(UINT32 *)mRiscVPass1Targ = (RV_X (Value2, 12, 20) << 12) | \\r
599 (RV_X (*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
600 Value2 = *(UINT32 *)Targ & 0x01fff07f;\r
601 Value &= RISCV_IMM_REACH - 1;\r
602 *(UINT32 *)Targ = Value2 | (UINT32)(((RV_X(Value, 0, 5) << 7) | (RV_X(Value, 5, 7) << 25)));\r
603 }\r
604 mRiscVPass1Sym = NULL;\r
605 mRiscVPass1Targ = NULL;\r
606 mRiscVPass1SymSecIndex = 0;\r
607 break;\r
608\r
abfff7c4
S
609 case R_RISCV_GOT_HI20:\r
610 GOTEntryRva = (Sym->st_value - Rel->r_offset);\r
611 mRiscVPass1Offset = RV_X(GOTEntryRva, 0, 12);\r
612 Value = (UINT32)RV_X(GOTEntryRva, 12, 20);\r
613 *(UINT32 *)Targ = (Value << 12) | (RV_X(*(UINT32*)Targ, 0, 12));\r
614\r
615 mRiscVPass1Targ = Targ;\r
616 mRiscVPass1Sym = SymShdr;\r
617 mRiscVPass1SymSecIndex = Sym->st_shndx;\r
618 mRiscVPass1GotFixup = 1;\r
619 break;\r
620\r
ad1db975
AC
621 case R_RISCV_PCREL_HI20:\r
622 mRiscVPass1Targ = Targ;\r
623 mRiscVPass1Sym = SymShdr;\r
624 mRiscVPass1SymSecIndex = Sym->st_shndx;\r
625\r
626 Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20));\r
627 break;\r
628\r
c32c5911
S
629 case R_RISCV_PCREL_LO12_S:\r
630 if (mRiscVPass1Targ != NULL && mRiscVPass1Sym != NULL && mRiscVPass1SymSecIndex != 0) {\r
631 int i;\r
632 Value2 = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20));\r
633\r
634 Value = ((UINT32)(RV_X(*(UINT32 *)Targ, 25, 7)) << 5);\r
635 Value = (Value | (UINT32)(RV_X(*(UINT32 *)Targ, 7, 5)));\r
636\r
637 if(Value & (RISCV_IMM_REACH/2)) {\r
638 Value |= ~(RISCV_IMM_REACH-1);\r
639 }\r
640 Value = Value - (UINT32)mRiscVPass1Sym->sh_addr + mCoffSectionsOffset[mRiscVPass1SymSecIndex];\r
641\r
642 if(-2048 > (INT32)Value) {\r
643 i = (((INT32)Value * -1) / 4096);\r
644 Value2 -= i;\r
645 Value += 4096 * i;\r
646 if(-2048 > (INT32)Value) {\r
647 Value2 -= 1;\r
648 Value += 4096;\r
649 }\r
650 }\r
651 else if( 2047 < (INT32)Value) {\r
652 i = (Value / 4096);\r
653 Value2 += i;\r
654 Value -= 4096 * i;\r
655 if(2047 < (INT32)Value) {\r
656 Value2 += 1;\r
657 Value -= 4096;\r
658 }\r
659 }\r
660\r
661 // Update the IMM of SD instruction\r
662 //\r
663 // |31 25|24 20|19 15|14 12 |11 7|6 0|\r
664 // |-------------------------------------------|-------|\r
665 // |imm[11:5] | rs2 | rs1 | funct3 |imm[4:0] | opcode|\r
666 // ---------------------------------------------------\r
667\r
668 // First Zero out current IMM\r
669 *(UINT32 *)Targ &= ~0xfe000f80;\r
670\r
671 // Update with new IMM\r
672 *(UINT32 *)Targ |= (RV_X(Value, 5, 7) << 25);\r
673 *(UINT32 *)Targ |= (RV_X(Value, 0, 5) << 7);\r
674\r
675 // Update previous instruction\r
676 *(UINT32 *)mRiscVPass1Targ = (RV_X(Value2, 0, 20)<<12) | (RV_X(*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
677 }\r
678 mRiscVPass1Sym = NULL;\r
679 mRiscVPass1Targ = NULL;\r
680 mRiscVPass1SymSecIndex = 0;\r
681 break;\r
682\r
ad1db975
AC
683 case R_RISCV_PCREL_LO12_I:\r
684 if (mRiscVPass1Targ != NULL && mRiscVPass1Sym != NULL && mRiscVPass1SymSecIndex != 0) {\r
685 int i;\r
686 Value2 = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20));\r
abfff7c4
S
687\r
688 if(mRiscVPass1GotFixup) {\r
689 Value = (UINT32)(mRiscVPass1Offset);\r
690 } else {\r
691 Value = (UINT32)(RV_X(*(UINT32 *)Targ, 20, 12));\r
692 if(Value & (RISCV_IMM_REACH/2)) {\r
693 Value |= ~(RISCV_IMM_REACH-1);\r
694 }\r
ad1db975
AC
695 }\r
696 Value = Value - (UINT32)mRiscVPass1Sym->sh_addr + mCoffSectionsOffset[mRiscVPass1SymSecIndex];\r
abfff7c4 697\r
ad1db975
AC
698 if(-2048 > (INT32)Value) {\r
699 i = (((INT32)Value * -1) / 4096);\r
700 Value2 -= i;\r
701 Value += 4096 * i;\r
702 if(-2048 > (INT32)Value) {\r
703 Value2 -= 1;\r
704 Value += 4096;\r
705 }\r
706 }\r
707 else if( 2047 < (INT32)Value) {\r
708 i = (Value / 4096);\r
709 Value2 += i;\r
710 Value -= 4096 * i;\r
711 if(2047 < (INT32)Value) {\r
712 Value2 += 1;\r
713 Value -= 4096;\r
714 }\r
715 }\r
716\r
abfff7c4
S
717 if(mRiscVPass1GotFixup) {\r
718 *(UINT32 *)Targ = (RV_X((UINT32)Value, 0, 12) << 20)\r
719 | (RV_X(*(UINT32*)Targ, 0, 20));\r
720 // Convert LD instruction to ADDI\r
721 //\r
722 // |31 20|19 15|14 12|11 7|6 0|\r
723 // |-----------------------------------------|\r
724 // |imm[11:0] | rs1 | 011 | rd | 0000011 | LD\r
725 // -----------------------------------------\r
726\r
727 // |-----------------------------------------|\r
728 // |imm[11:0] | rs1 | 000 | rd | 0010011 | ADDI\r
729 // -----------------------------------------\r
730\r
731 // To convert, let's first reset bits 12-14 and 0-6 using ~0x707f\r
732 // Then modify the opcode to ADDI (0010011)\r
733 // All other fields will remain same.\r
734\r
735 *(UINT32 *)Targ = ((*(UINT32 *)Targ & ~0x707f) | 0x13);\r
736 } else {\r
737 *(UINT32 *)Targ = (RV_X(Value, 0, 12) << 20) | (RV_X(*(UINT32*)Targ, 0, 20));\r
738 }\r
ad1db975
AC
739 *(UINT32 *)mRiscVPass1Targ = (RV_X(Value2, 0, 20)<<12) | (RV_X(*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
740 }\r
741 mRiscVPass1Sym = NULL;\r
742 mRiscVPass1Targ = NULL;\r
743 mRiscVPass1SymSecIndex = 0;\r
abfff7c4
S
744 mRiscVPass1Offset = 0;\r
745 mRiscVPass1GotFixup = 0;\r
ad1db975
AC
746 break;\r
747\r
748 case R_RISCV_ADD64:\r
749 case R_RISCV_SUB64:\r
750 case R_RISCV_ADD32:\r
751 case R_RISCV_SUB32:\r
752 case R_RISCV_BRANCH:\r
753 case R_RISCV_JAL:\r
754 case R_RISCV_GPREL_I:\r
755 case R_RISCV_GPREL_S:\r
756 case R_RISCV_CALL:\r
abfff7c4 757 case R_RISCV_CALL_PLT:\r
ad1db975
AC
758 case R_RISCV_RVC_BRANCH:\r
759 case R_RISCV_RVC_JUMP:\r
760 case R_RISCV_RELAX:\r
761 case R_RISCV_SUB6:\r
762 case R_RISCV_SET6:\r
763 case R_RISCV_SET8:\r
764 case R_RISCV_SET16:\r
765 case R_RISCV_SET32:\r
766 break;\r
767\r
768 default:\r
769 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_RISCV64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
770 }\r
771}\r
ecbaa856 772\r
f51461c8
LG
773//\r
774// Elf functions interface implementation\r
775//\r
776\r
777STATIC\r
778VOID\r
779ScanSections64 (\r
780 VOID\r
781 )\r
782{\r
783 UINT32 i;\r
784 EFI_IMAGE_DOS_HEADER *DosHdr;\r
785 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
786 UINT32 CoffEntry;\r
787 UINT32 SectionCount;\r
234f9ff9 788 BOOLEAN FoundSection;\r
414cd2a4 789 UINT32 Offset;\r
f51461c8
LG
790\r
791 CoffEntry = 0;\r
792 mCoffOffset = 0;\r
f51461c8
LG
793\r
794 //\r
795 // Coff file start with a DOS header.\r
796 //\r
797 mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;\r
798 mNtHdrOffset = mCoffOffset;\r
799 switch (mEhdr->e_machine) {\r
800 case EM_X86_64:\r
f51461c8 801 case EM_AARCH64:\r
ad1db975 802 case EM_RISCV64:\r
1aa311d1 803 case EM_LOONGARCH:\r
f51461c8
LG
804 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
805 break;\r
806 default:\r
ea3e924a 807 VerboseMsg ("%s unknown e_machine type %hu. Assume X64", mInImageName, mEhdr->e_machine);\r
f51461c8
LG
808 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
809 break;\r
810 }\r
811\r
812 mTableOffset = mCoffOffset;\r
813 mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);\r
814\r
54b1b57a
AB
815 //\r
816 // Set mCoffAlignment to the maximum alignment of the input sections\r
817 // we care about\r
818 //\r
819 for (i = 0; i < mEhdr->e_shnum; i++) {\r
820 Elf_Shdr *shdr = GetShdrByIndex(i);\r
821 if (shdr->sh_addralign <= mCoffAlignment) {\r
822 continue;\r
823 }\r
824 if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) {\r
825 mCoffAlignment = (UINT32)shdr->sh_addralign;\r
826 }\r
827 }\r
828\r
3f021800
YF
829 //\r
830 // Check if mCoffAlignment is larger than MAX_COFF_ALIGNMENT\r
831 //\r
832 if (mCoffAlignment > MAX_COFF_ALIGNMENT) {\r
833 Error (NULL, 0, 3000, "Invalid", "Section alignment is larger than MAX_COFF_ALIGNMENT.");\r
834 assert (FALSE);\r
835 }\r
836\r
837\r
02a5421f
AB
838 //\r
839 // Move the PE/COFF header right before the first section. This will help us\r
840 // save space when converting to TE.\r
841 //\r
842 if (mCoffAlignment > mCoffOffset) {\r
843 mNtHdrOffset += mCoffAlignment - mCoffOffset;\r
844 mTableOffset += mCoffAlignment - mCoffOffset;\r
845 mCoffOffset = mCoffAlignment;\r
846 }\r
847\r
f51461c8
LG
848 //\r
849 // First text sections.\r
850 //\r
851 mCoffOffset = CoffAlign(mCoffOffset);\r
234f9ff9
EB
852 mTextOffset = mCoffOffset;\r
853 FoundSection = FALSE;\r
f51461c8
LG
854 SectionCount = 0;\r
855 for (i = 0; i < mEhdr->e_shnum; i++) {\r
856 Elf_Shdr *shdr = GetShdrByIndex(i);\r
857 if (IsTextShdr(shdr)) {\r
858 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
859 // the alignment field is valid\r
860 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
861 // if the section address is aligned we must align PE/COFF\r
862 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
0c960e86
AB
863 } else {\r
864 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
f51461c8
LG
865 }\r
866 }\r
867\r
868 /* Relocate entry. */\r
869 if ((mEhdr->e_entry >= shdr->sh_addr) &&\r
870 (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {\r
871 CoffEntry = (UINT32) (mCoffOffset + mEhdr->e_entry - shdr->sh_addr);\r
872 }\r
873\r
874 //\r
875 // Set mTextOffset with the offset of the first '.text' section\r
876 //\r
234f9ff9 877 if (!FoundSection) {\r
f51461c8 878 mTextOffset = mCoffOffset;\r
234f9ff9 879 FoundSection = TRUE;\r
f51461c8
LG
880 }\r
881\r
882 mCoffSectionsOffset[i] = mCoffOffset;\r
883 mCoffOffset += (UINT32) shdr->sh_size;\r
884 SectionCount ++;\r
885 }\r
886 }\r
887\r
ddb3fdbe 888 if (!FoundSection && mOutImageType != FW_ACPI_IMAGE) {\r
f51461c8
LG
889 Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");\r
890 assert (FALSE);\r
891 }\r
892\r
4f7d5c67 893 mDebugOffset = DebugRvaAlign(mCoffOffset);\r
0c960e86 894 mCoffOffset = CoffAlign(mCoffOffset);\r
f51461c8
LG
895\r
896 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
fb0b35e0 897 Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);\r
f51461c8
LG
898 }\r
899\r
900 //\r
901 // Then data sections.\r
902 //\r
903 mDataOffset = mCoffOffset;\r
234f9ff9 904 FoundSection = FALSE;\r
f51461c8
LG
905 SectionCount = 0;\r
906 for (i = 0; i < mEhdr->e_shnum; i++) {\r
907 Elf_Shdr *shdr = GetShdrByIndex(i);\r
908 if (IsDataShdr(shdr)) {\r
909 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
910 // the alignment field is valid\r
911 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
912 // if the section address is aligned we must align PE/COFF\r
913 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
0c960e86
AB
914 } else {\r
915 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
f51461c8
LG
916 }\r
917 }\r
234f9ff9
EB
918\r
919 //\r
920 // Set mDataOffset with the offset of the first '.data' section\r
921 //\r
922 if (!FoundSection) {\r
923 mDataOffset = mCoffOffset;\r
924 FoundSection = TRUE;\r
925 }\r
f51461c8
LG
926 mCoffSectionsOffset[i] = mCoffOffset;\r
927 mCoffOffset += (UINT32) shdr->sh_size;\r
928 SectionCount ++;\r
929 }\r
930 }\r
0192b71c
AB
931\r
932 //\r
933 // Make room for .debug data in .data (or .text if .data is empty) instead of\r
934 // putting it in a section of its own. This is explicitly allowed by the\r
935 // PE/COFF spec, and prevents bloat in the binary when using large values for\r
936 // section alignment.\r
937 //\r
938 if (SectionCount > 0) {\r
4f7d5c67 939 mDebugOffset = DebugRvaAlign(mCoffOffset);\r
0192b71c
AB
940 }\r
941 mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) +\r
942 sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) +\r
943 strlen(mInImageName) + 1;\r
944\r
f51461c8 945 mCoffOffset = CoffAlign(mCoffOffset);\r
0192b71c
AB
946 if (SectionCount == 0) {\r
947 mDataOffset = mCoffOffset;\r
948 }\r
f51461c8
LG
949\r
950 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
fb0b35e0 951 Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
f51461c8
LG
952 }\r
953\r
414cd2a4
HLX
954 //\r
955 // The Symbol sections.\r
956 //\r
957 if (mExportFlag) {\r
958 UINT32 SymIndex;\r
959 Elf_Sym *Sym;\r
960 UINT64 SymNum;\r
961 const UINT8 *SymName;\r
962\r
963 mExportOffset = mCoffOffset;\r
964 mExportSize = sizeof(EFI_IMAGE_EXPORT_DIRECTORY) + strlen(mInImageName) + 1;\r
965\r
966 for (i = 0; i < mEhdr->e_shnum; i++) {\r
967\r
968 //\r
969 // Determine if this is a symbol section.\r
970 //\r
971 Elf_Shdr *shdr = GetShdrByIndex(i);\r
972 if (!IsSymbolShdr(shdr)) {\r
973 continue;\r
974 }\r
975\r
976 UINT8 *Symtab = (UINT8*)mEhdr + shdr->sh_offset;\r
977 SymNum = (shdr->sh_size) / (shdr->sh_entsize);\r
978\r
979 //\r
980 // First Get PrmModuleExportDescriptor\r
981 //\r
982 for (SymIndex = 0; SymIndex < SymNum; SymIndex++) {\r
983 Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize);\r
984 SymName = GetSymName(Sym);\r
985 if (SymName == NULL) {\r
986 continue;\r
987 }\r
988\r
989 if (strcmp((CHAR8*)SymName, PRM_MODULE_EXPORT_DESCRIPTOR_NAME) == 0) {\r
990 //\r
991 // Find PrmHandler Number and Name\r
992 //\r
993 FindPrmHandler(Sym->st_value);\r
994\r
995 strcpy(mExportSymName[mExportSymNum], (CHAR8*)SymName);\r
996 mExportRVA[mExportSymNum] = (UINT32)(Sym->st_value);\r
997 mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1;\r
998 mExportSymNum ++;\r
999 break;\r
1000 }\r
1001 }\r
1002\r
1003 //\r
1004 // Second Get PrmHandler\r
1005 //\r
1006 for (SymIndex = 0; SymIndex < SymNum; SymIndex++) {\r
1007 UINT32 ExpIndex;\r
1008 Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize);\r
1009 SymName = GetSymName(Sym);\r
1010 if (SymName == NULL) {\r
1011 continue;\r
1012 }\r
1013\r
1014 for (ExpIndex = 0; ExpIndex < (mExportSymNum -1); ExpIndex++) {\r
1015 if (strcmp((CHAR8*)SymName, mExportSymName[ExpIndex]) != 0) {\r
1016 continue;\r
1017 }\r
1018 mExportRVA[ExpIndex] = (UINT32)(Sym->st_value);\r
1019 mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1;\r
1020 }\r
1021 }\r
1022\r
1023 break;\r
1024 }\r
1025\r
1026 mCoffOffset += mExportSize;\r
1027 mCoffOffset = CoffAlign(mCoffOffset);\r
1028 }\r
1029\r
f51461c8
LG
1030 //\r
1031 // The HII resource sections.\r
1032 //\r
1033 mHiiRsrcOffset = mCoffOffset;\r
1034 for (i = 0; i < mEhdr->e_shnum; i++) {\r
1035 Elf_Shdr *shdr = GetShdrByIndex(i);\r
1036 if (IsHiiRsrcShdr(shdr)) {\r
1037 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
1038 // the alignment field is valid\r
1039 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
1040 // if the section address is aligned we must align PE/COFF\r
1041 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
0c960e86
AB
1042 } else {\r
1043 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
f51461c8
LG
1044 }\r
1045 }\r
1046 if (shdr->sh_size != 0) {\r
234f9ff9 1047 mHiiRsrcOffset = mCoffOffset;\r
f51461c8
LG
1048 mCoffSectionsOffset[i] = mCoffOffset;\r
1049 mCoffOffset += (UINT32) shdr->sh_size;\r
1050 mCoffOffset = CoffAlign(mCoffOffset);\r
1051 SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);\r
1052 }\r
1053 break;\r
1054 }\r
1055 }\r
1056\r
1057 mRelocOffset = mCoffOffset;\r
1058\r
1059 //\r
1060 // Allocate base Coff file. Will be expanded later for relocations.\r
1061 //\r
1062 mCoffFile = (UINT8 *)malloc(mCoffOffset);\r
06b45735
HW
1063 if (mCoffFile == NULL) {\r
1064 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
1065 }\r
1066 assert (mCoffFile != NULL);\r
f51461c8
LG
1067 memset(mCoffFile, 0, mCoffOffset);\r
1068\r
1069 //\r
1070 // Fill headers.\r
1071 //\r
1072 DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;\r
1073 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;\r
1074 DosHdr->e_lfanew = mNtHdrOffset;\r
1075\r
1076 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);\r
1077\r
1078 NtHdr->Pe32Plus.Signature = EFI_IMAGE_NT_SIGNATURE;\r
1079\r
1080 switch (mEhdr->e_machine) {\r
1081 case EM_X86_64:\r
1082 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
1083 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1084 break;\r
f51461c8
LG
1085 case EM_AARCH64:\r
1086 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_AARCH64;\r
1087 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1088 break;\r
ad1db975
AC
1089 case EM_RISCV64:\r
1090 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_RISCV64;\r
1091 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1092 break;\r
1aa311d1
CL
1093 case EM_LOONGARCH:\r
1094 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_LOONGARCH64;\r
1095 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1096 break;\r
ad1db975 1097\r
f51461c8 1098 default:\r
179efe5d 1099 VerboseMsg ("%u unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
f51461c8
LG
1100 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
1101 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1102 }\r
1103\r
1104 NtHdr->Pe32Plus.FileHeader.NumberOfSections = mCoffNbrSections;\r
1105 NtHdr->Pe32Plus.FileHeader.TimeDateStamp = (UINT32) time(NULL);\r
1106 mImageTimeStamp = NtHdr->Pe32Plus.FileHeader.TimeDateStamp;\r
1107 NtHdr->Pe32Plus.FileHeader.PointerToSymbolTable = 0;\r
1108 NtHdr->Pe32Plus.FileHeader.NumberOfSymbols = 0;\r
1109 NtHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32Plus.OptionalHeader);\r
1110 NtHdr->Pe32Plus.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE\r
1111 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED\r
1112 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED\r
1113 | EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE;\r
1114\r
1115 NtHdr->Pe32Plus.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;\r
1116 NtHdr->Pe32Plus.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;\r
1117 NtHdr->Pe32Plus.OptionalHeader.SizeOfUninitializedData = 0;\r
1118 NtHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint = CoffEntry;\r
1119\r
1120 NtHdr->Pe32Plus.OptionalHeader.BaseOfCode = mTextOffset;\r
1121\r
1122 NtHdr->Pe32Plus.OptionalHeader.ImageBase = 0;\r
1123 NtHdr->Pe32Plus.OptionalHeader.SectionAlignment = mCoffAlignment;\r
1124 NtHdr->Pe32Plus.OptionalHeader.FileAlignment = mCoffAlignment;\r
1125 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = 0;\r
1126\r
1127 NtHdr->Pe32Plus.OptionalHeader.SizeOfHeaders = mTextOffset;\r
1128 NtHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
1129\r
1130 //\r
1131 // Section headers.\r
1132 //\r
1133 if ((mDataOffset - mTextOffset) > 0) {\r
1134 CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,\r
1135 EFI_IMAGE_SCN_CNT_CODE\r
1136 | EFI_IMAGE_SCN_MEM_EXECUTE\r
1137 | EFI_IMAGE_SCN_MEM_READ);\r
1138 } else {\r
1139 // Don't make a section of size 0.\r
1140 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
1141 }\r
1142\r
414cd2a4
HLX
1143 //\r
1144 // If found symbol, add edata section between data and rsrc section\r
1145 //\r
1146 if(mExportFlag) {\r
1147 Offset = mExportOffset;\r
1148 } else {\r
1149 Offset = mHiiRsrcOffset;\r
1150 }\r
1151\r
f51461c8 1152 if ((mHiiRsrcOffset - mDataOffset) > 0) {\r
414cd2a4 1153 CreateSectionHeader (".data", mDataOffset, Offset - mDataOffset,\r
f51461c8
LG
1154 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
1155 | EFI_IMAGE_SCN_MEM_WRITE\r
1156 | EFI_IMAGE_SCN_MEM_READ);\r
1157 } else {\r
1158 // Don't make a section of size 0.\r
1159 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
1160 }\r
1161\r
414cd2a4
HLX
1162 if(mExportFlag) {\r
1163 if ((mHiiRsrcOffset - mExportOffset) > 0) {\r
1164 CreateSectionHeader (".edata", mExportOffset, mHiiRsrcOffset - mExportOffset,\r
1165 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
1166 | EFI_IMAGE_SCN_MEM_READ);\r
1167 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size = mHiiRsrcOffset - mExportOffset;\r
1168 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = mExportOffset;\r
1169\r
1170 } else {\r
1171 // Don't make a section of size 0.\r
1172 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
1173 }\r
1174 }\r
1175\r
f51461c8
LG
1176 if ((mRelocOffset - mHiiRsrcOffset) > 0) {\r
1177 CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,\r
1178 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
1179 | EFI_IMAGE_SCN_MEM_READ);\r
1180\r
1181 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;\r
1182 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;\r
1183 } else {\r
1184 // Don't make a section of size 0.\r
1185 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
1186 }\r
1187\r
1188}\r
1189\r
1190STATIC\r
1191BOOLEAN\r
1192WriteSections64 (\r
1193 SECTION_FILTER_TYPES FilterType\r
1194 )\r
1195{\r
1196 UINT32 Idx;\r
1197 Elf_Shdr *SecShdr;\r
1198 UINT32 SecOffset;\r
1199 BOOLEAN (*Filter)(Elf_Shdr *);\r
ecbaa856 1200 Elf64_Addr GOTEntryRva;\r
f51461c8
LG
1201\r
1202 //\r
1203 // Initialize filter pointer\r
1204 //\r
1205 switch (FilterType) {\r
1206 case SECTION_TEXT:\r
1207 Filter = IsTextShdr;\r
1208 break;\r
1209 case SECTION_HII:\r
1210 Filter = IsHiiRsrcShdr;\r
1211 break;\r
1212 case SECTION_DATA:\r
1213 Filter = IsDataShdr;\r
1214 break;\r
1215 default:\r
1216 return FALSE;\r
1217 }\r
1218\r
1219 //\r
1220 // First: copy sections.\r
1221 //\r
1222 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
1223 Elf_Shdr *Shdr = GetShdrByIndex(Idx);\r
1224 if ((*Filter)(Shdr)) {\r
1225 switch (Shdr->sh_type) {\r
1226 case SHT_PROGBITS:\r
1227 /* Copy. */\r
d78675d1
YF
1228 if (Shdr->sh_offset + Shdr->sh_size > mFileBufferSize) {\r
1229 return FALSE;\r
1230 }\r
f51461c8
LG
1231 memcpy(mCoffFile + mCoffSectionsOffset[Idx],\r
1232 (UINT8*)mEhdr + Shdr->sh_offset,\r
1233 (size_t) Shdr->sh_size);\r
1234 break;\r
1235\r
1236 case SHT_NOBITS:\r
1237 memset(mCoffFile + mCoffSectionsOffset[Idx], 0, (size_t) Shdr->sh_size);\r
1238 break;\r
1239\r
1240 default:\r
1241 //\r
fb0b35e0 1242 // Ignore for unknown section type.\r
f51461c8 1243 //\r
1794b98f 1244 VerboseMsg ("%s unknown section type %x. We ignore this unknown section type.", mInImageName, (unsigned)Shdr->sh_type);\r
f51461c8
LG
1245 break;\r
1246 }\r
1247 }\r
1248 }\r
1249\r
1250 //\r
1251 // Second: apply relocations.\r
1252 //\r
1253 VerboseMsg ("Applying Relocations...");\r
1254 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
1255 //\r
1256 // Determine if this is a relocation section.\r
1257 //\r
1258 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);\r
1259 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {\r
1260 continue;\r
1261 }\r
1262\r
4962fcfa
AB
1263 //\r
1264 // If this is a ET_DYN (PIE) executable, we will encounter a dynamic SHT_RELA\r
1265 // section that applies to the entire binary, and which will have its section\r
1266 // index set to #0 (which is a NULL section with the SHF_ALLOC bit cleared).\r
1267 //\r
ecbaa856 1268 // In the absence of GOT based relocations,\r
4962fcfa
AB
1269 // this RELA section will contain redundant R_xxx_RELATIVE relocations, one\r
1270 // for every R_xxx_xx64 relocation appearing in the per-section RELA sections.\r
1271 // (i.e., .rela.text and .rela.data)\r
1272 //\r
1273 if (RelShdr->sh_info == 0) {\r
1274 continue;\r
1275 }\r
1276\r
f51461c8
LG
1277 //\r
1278 // Relocation section found. Now extract section information that the relocations\r
1279 // apply to in the ELF data and the new COFF data.\r
1280 //\r
1281 SecShdr = GetShdrByIndex(RelShdr->sh_info);\r
1282 SecOffset = mCoffSectionsOffset[RelShdr->sh_info];\r
1283\r
1284 //\r
1285 // Only process relocations for the current filter type.\r
1286 //\r
1287 if (RelShdr->sh_type == SHT_RELA && (*Filter)(SecShdr)) {\r
1288 UINT64 RelIdx;\r
1289\r
1290 //\r
1291 // Determine the symbol table referenced by the relocation data.\r
1292 //\r
1293 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);\r
1294 UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;\r
1295\r
1296 //\r
1297 // Process all relocation entries for this section.\r
1298 //\r
1299 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINT32) RelShdr->sh_entsize) {\r
1300\r
1301 //\r
1302 // Set pointer to relocation entry\r
1303 //\r
1304 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
1305\r
1306 //\r
1307 // Set pointer to symbol table entry associated with the relocation entry.\r
1308 //\r
1309 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);\r
1310\r
1311 Elf_Shdr *SymShdr;\r
1312 UINT8 *Targ;\r
1313\r
7b8f69d7
AB
1314 //\r
1315 // The _GLOBAL_OFFSET_TABLE_ symbol is not actually an absolute symbol,\r
1316 // but carries the SHN_ABS section index for historical reasons.\r
1317 // It must be accompanied by a R_*_GOT_* type relocation on a\r
1318 // subsequent instruction, which we handle below, specifically to avoid\r
1319 // the GOT indirection, and to refer to the symbol directly. This means\r
1320 // we can simply disregard direct references to the GOT symbol itself,\r
1321 // as the resulting value will never be used.\r
1322 //\r
1323 if (Sym->st_shndx == SHN_ABS) {\r
1324 const UINT8 *SymName = GetSymName (Sym);\r
1325 if (strcmp ((CHAR8 *)SymName, "_GLOBAL_OFFSET_TABLE_") == 0) {\r
1326 continue;\r
1327 }\r
1328 }\r
1329\r
f51461c8
LG
1330 //\r
1331 // Check section header index found in symbol table and get the section\r
1332 // header location.\r
1333 //\r
1334 if (Sym->st_shndx == SHN_UNDEF\r
621bb723
ML
1335 || Sym->st_shndx >= mEhdr->e_shnum) {\r
1336 const UINT8 *SymName = GetSymName(Sym);\r
1337 if (SymName == NULL) {\r
1338 SymName = (const UINT8 *)"<unknown>";\r
1339 }\r
1340\r
ad1db975 1341 //\r
1aa311d1
CL
1342 // Skip error on EM_RISCV64 and EM_LOONGARCH because no symbol name is built\r
1343 // from RISC-V and LoongArch toolchain.\r
ad1db975 1344 //\r
1aa311d1 1345 if ((mEhdr->e_machine != EM_RISCV64) && (mEhdr->e_machine != EM_LOONGARCH)) {\r
ad1db975
AC
1346 Error (NULL, 0, 3000, "Invalid",\r
1347 "%s: Bad definition for symbol '%s'@%#llx or unsupported symbol type. "\r
1348 "For example, absolute and undefined symbols are not supported.",\r
1349 mInImageName, SymName, Sym->st_value);\r
621bb723 1350\r
ad1db975
AC
1351 exit(EXIT_FAILURE);\r
1352 }\r
c6b872c6 1353 continue;\r
f51461c8
LG
1354 }\r
1355 SymShdr = GetShdrByIndex(Sym->st_shndx);\r
1356\r
1357 //\r
1358 // Convert the relocation data to a pointer into the coff file.\r
1359 //\r
1360 // Note:\r
1361 // r_offset is the virtual address of the storage unit to be relocated.\r
1362 // sh_addr is the virtual address for the base of the section.\r
1363 //\r
1364 // r_offset in a memory address.\r
1365 // Convert it to a pointer in the coff file.\r
1366 //\r
1367 Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);\r
1368\r
1369 //\r
1370 // Determine how to handle each relocation type based on the machine type.\r
1371 //\r
1372 if (mEhdr->e_machine == EM_X86_64) {\r
1373 switch (ELF_R_TYPE(Rel->r_info)) {\r
1374 case R_X86_64_NONE:\r
1375 break;\r
1376 case R_X86_64_64:\r
1377 //\r
1378 // Absolute relocation.\r
1379 //\r
1380 VerboseMsg ("R_X86_64_64");\r
f7496d71
LG
1381 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX",\r
1382 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
f51461c8
LG
1383 *(UINT64 *)Targ);\r
1384 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
1385 VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ);\r
1386 break;\r
1387 case R_X86_64_32:\r
1388 VerboseMsg ("R_X86_64_32");\r
f7496d71
LG
1389 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
1390 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
f51461c8
LG
1391 *(UINT32 *)Targ);\r
1392 *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
1393 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
1394 break;\r
1395 case R_X86_64_32S:\r
1396 VerboseMsg ("R_X86_64_32S");\r
f7496d71
LG
1397 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
1398 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
f51461c8
LG
1399 *(UINT32 *)Targ);\r
1400 *(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
1401 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
1402 break;\r
c9f29755
AB
1403\r
1404 case R_X86_64_PLT32:\r
1405 //\r
1406 // Treat R_X86_64_PLT32 relocations as R_X86_64_PC32: this is\r
1407 // possible since we know all code symbol references resolve to\r
1408 // definitions in the same module (UEFI has no shared libraries),\r
1409 // and so there is never a reason to jump via a PLT entry,\r
1410 // allowing us to resolve the reference using the symbol directly.\r
1411 //\r
1412 VerboseMsg ("Treating R_X86_64_PLT32 as R_X86_64_PC32 ...");\r
1413 /* fall through */\r
f51461c8
LG
1414 case R_X86_64_PC32:\r
1415 //\r
1416 // Relative relocation: Symbol - Ip + Addend\r
1417 //\r
1418 VerboseMsg ("R_X86_64_PC32");\r
f7496d71
LG
1419 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
1420 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
f51461c8
LG
1421 *(UINT32 *)Targ);\r
1422 *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ\r
1423 + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)\r
1424 - (SecOffset - SecShdr->sh_addr));\r
1425 VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ);\r
1426 break;\r
ecbaa856
Z
1427 case R_X86_64_GOTPCREL:\r
1428 case R_X86_64_GOTPCRELX:\r
1429 case R_X86_64_REX_GOTPCRELX:\r
1430 VerboseMsg ("R_X86_64_GOTPCREL family");\r
1431 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
1432 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
1433 *(UINT32 *)Targ);\r
1434 GOTEntryRva = Rel->r_offset - Rel->r_addend + *(INT32 *)Targ;\r
1435 FindElfGOTSectionFromGOTEntryElfRva(GOTEntryRva);\r
1436 *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ\r
1437 + (mCoffSectionsOffset[mGOTShindex] - mGOTShdr->sh_addr)\r
1438 - (SecOffset - SecShdr->sh_addr));\r
1439 VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ);\r
1440 GOTEntryRva += (mCoffSectionsOffset[mGOTShindex] - mGOTShdr->sh_addr); // ELF Rva -> COFF Rva\r
1441 if (AccumulateCoffGOTEntries((UINT32)GOTEntryRva)) {\r
1442 //\r
1443 // Relocate GOT entry if it's the first time we run into it\r
1444 //\r
1445 Targ = mCoffFile + GOTEntryRva;\r
1446 //\r
1447 // Limitation: The following three statements assume memory\r
1448 // at *Targ is valid because the section containing the GOT\r
1449 // has already been copied from the ELF image to the Coff image.\r
1450 // This pre-condition presently holds because the GOT is placed\r
1451 // in section .text, and the ELF text sections are all copied\r
1452 // prior to reaching this point.\r
1453 // If the pre-condition is violated in the future, this fixup\r
1454 // either needs to be deferred after the GOT section is copied\r
1455 // to the Coff image, or the fixup should be performed on the\r
1456 // source Elf image instead of the destination Coff image.\r
1457 //\r
1458 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX",\r
1459 (UINT32)GOTEntryRva,\r
1460 *(UINT64 *)Targ);\r
1461 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
1462 VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ);\r
1463 }\r
1464 break;\r
f51461c8
LG
1465 default:\r
1466 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
1467 }\r
1468 } else if (mEhdr->e_machine == EM_AARCH64) {\r
1469\r
f51461c8 1470 switch (ELF_R_TYPE(Rel->r_info)) {\r
d2687f23
AB
1471 INT64 Offset;\r
1472\r
7b8f69d7
AB
1473 case R_AARCH64_LD64_GOTOFF_LO15:\r
1474 case R_AARCH64_LD64_GOTPAGE_LO15:\r
1475 //\r
1476 // Convert into an ADR instruction that refers to the symbol directly.\r
1477 //\r
1478 Offset = Sym->st_value - Rel->r_offset;\r
1479\r
1480 *(UINT32 *)Targ &= 0x1000001f;\r
1481 *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | ((Offset & 0x3) << 29);\r
1482\r
1483 if (Offset < -0x100000 || Offset > 0xfffff) {\r
1484 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s failed to relax GOT based symbol reference - image is too big (>1 MiB).",\r
1485 mInImageName);\r
1486 break;\r
1487 }\r
1488 break;\r
1489\r
d2687f23
AB
1490 case R_AARCH64_LD64_GOT_LO12_NC:\r
1491 //\r
1492 // Convert into an ADD instruction - see R_AARCH64_ADR_GOT_PAGE below.\r
1493 //\r
1494 *(UINT32 *)Targ &= 0x3ff;\r
1495 *(UINT32 *)Targ |= 0x91000000 | ((Sym->st_value & 0xfff) << 10);\r
1496 break;\r
1497\r
1498 case R_AARCH64_ADR_GOT_PAGE:\r
1499 //\r
1500 // This relocation points to the GOT entry that contains the absolute\r
1501 // address of the symbol we are referring to. Since EDK2 only uses\r
1502 // fully linked binaries, we can avoid the indirection, and simply\r
1503 // refer to the symbol directly. This implies having to patch the\r
1504 // subsequent LDR instruction (covered by a R_AARCH64_LD64_GOT_LO12_NC\r
1505 // relocation) into an ADD instruction - this is handled above.\r
1506 //\r
1507 Offset = (Sym->st_value - (Rel->r_offset & ~0xfff)) >> 12;\r
1508\r
1509 *(UINT32 *)Targ &= 0x9000001f;\r
1510 *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | ((Offset & 0x3) << 29);\r
1511\r
1512 /* fall through */\r
f51461c8 1513\r
24d610e6 1514 case R_AARCH64_ADR_PREL_PG_HI21:\r
f55c76b3
AB
1515 //\r
1516 // In order to handle Cortex-A53 erratum #843419, the LD linker may\r
1517 // convert ADRP instructions into ADR instructions, but without\r
1518 // updating the static relocation type, and so we may end up here\r
1519 // while the instruction in question is actually ADR. So let's\r
1520 // just disregard it: the section offset check we apply below to\r
1521 // ADR instructions will trigger for its R_AARCH64_xxx_ABS_LO12_NC\r
1522 // companion instruction as well, so it is safe to omit it here.\r
1523 //\r
1524 if ((*(UINT32 *)Targ & BIT31) == 0) {\r
1525 break;\r
1526 }\r
1527\r
24d610e6
AB
1528 //\r
1529 // AArch64 PG_H21 relocations are typically paired with ABS_LO12\r
1530 // relocations, where a PC-relative reference with +/- 4 GB range is\r
1531 // split into a relative high part and an absolute low part. Since\r
1532 // the absolute low part represents the offset into a 4 KB page, we\r
026a82ab
AB
1533 // either have to convert the ADRP into an ADR instruction, or we\r
1534 // need to use a section alignment of at least 4 KB, so that the\r
1535 // binary appears at a correct offset at runtime. In any case, we\r
24d610e6
AB
1536 // have to make sure that the 4 KB relative offsets of both the\r
1537 // section containing the reference as well as the section to which\r
1538 // it refers have not been changed during PE/COFF conversion (i.e.,\r
1539 // in ScanSections64() above).\r
1540 //\r
026a82ab
AB
1541 if (mCoffAlignment < 0x1000) {\r
1542 //\r
1543 // Attempt to convert the ADRP into an ADR instruction.\r
1544 // This is only possible if the symbol is within +/- 1 MB.\r
1545 //\r
026a82ab
AB
1546\r
1547 // Decode the ADRP instruction\r
1548 Offset = (INT32)((*(UINT32 *)Targ & 0xffffe0) << 8);\r
1549 Offset = (Offset << (6 - 5)) | ((*(UINT32 *)Targ & 0x60000000) >> (29 - 12));\r
1550\r
1551 //\r
1552 // ADRP offset is relative to the previous page boundary,\r
1553 // whereas ADR offset is relative to the instruction itself.\r
1554 // So fix up the offset so it points to the page containing\r
1555 // the symbol.\r
1556 //\r
1557 Offset -= (UINTN)(Targ - mCoffFile) & 0xfff;\r
1558\r
1559 if (Offset < -0x100000 || Offset > 0xfffff) {\r
1560 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s due to its size (> 1 MB), this module requires 4 KB section alignment.",\r
1561 mInImageName);\r
1562 break;\r
1563 }\r
1564\r
1565 // Re-encode the offset as an ADR instruction\r
1566 *(UINT32 *)Targ &= 0x1000001f;\r
1567 *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | ((Offset & 0x3) << 29);\r
1568 }\r
1569 /* fall through */\r
1570\r
1571 case R_AARCH64_ADD_ABS_LO12_NC:\r
1572 case R_AARCH64_LDST8_ABS_LO12_NC:\r
1573 case R_AARCH64_LDST16_ABS_LO12_NC:\r
1574 case R_AARCH64_LDST32_ABS_LO12_NC:\r
1575 case R_AARCH64_LDST64_ABS_LO12_NC:\r
1576 case R_AARCH64_LDST128_ABS_LO12_NC:\r
24d610e6 1577 if (((SecShdr->sh_addr ^ SecOffset) & 0xfff) != 0 ||\r
026a82ab
AB
1578 ((SymShdr->sh_addr ^ mCoffSectionsOffset[Sym->st_shndx]) & 0xfff) != 0) {\r
1579 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 small code model requires identical ELF and PE/COFF section offsets modulo 4 KB.",\r
24d610e6
AB
1580 mInImageName);\r
1581 break;\r
87280982 1582 }\r
24d610e6 1583 /* fall through */\r
87280982 1584\r
24d610e6 1585 case R_AARCH64_ADR_PREL_LO21:\r
87280982 1586 case R_AARCH64_CONDBR19:\r
f51461c8 1587 case R_AARCH64_LD_PREL_LO19:\r
f51461c8 1588 case R_AARCH64_CALL26:\r
f51461c8 1589 case R_AARCH64_JUMP26:\r
0b6249f5
AB
1590 case R_AARCH64_PREL64:\r
1591 case R_AARCH64_PREL32:\r
1592 case R_AARCH64_PREL16:\r
24d610e6
AB
1593 //\r
1594 // The GCC toolchains (i.e., binutils) may corrupt section relative\r
1595 // relocations when emitting relocation sections into fully linked\r
1596 // binaries. More specifically, they tend to fail to take into\r
1597 // account the fact that a '.rodata + XXX' relocation needs to have\r
1598 // its addend recalculated once .rodata is merged into the .text\r
1599 // section, and the relocation emitted into the .rela.text section.\r
1600 //\r
1601 // We cannot really recover from this loss of information, so the\r
1602 // only workaround is to prevent having to recalculate any relative\r
1603 // relocations at all, by using a linker script that ensures that\r
1604 // the offset between the Place and the Symbol is the same in both\r
1605 // the ELF and the PE/COFF versions of the binary.\r
1606 //\r
1607 if ((SymShdr->sh_addr - SecShdr->sh_addr) !=\r
1608 (mCoffSectionsOffset[Sym->st_shndx] - SecOffset)) {\r
1609 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 relative relocations require identical ELF and PE/COFF section offsets",\r
1610 mInImageName);\r
f51461c8
LG
1611 }\r
1612 break;\r
1613\r
f51461c8
LG
1614 // Absolute relocations.\r
1615 case R_AARCH64_ABS64:\r
1616 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
1617 break;\r
1618\r
1619 default:\r
1620 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
1621 }\r
ad1db975
AC
1622 } else if (mEhdr->e_machine == EM_RISCV64) {\r
1623 //\r
1624 // Write section for RISC-V 64 architecture.\r
1625 //\r
1626 WriteSectionRiscV64 (Rel, Targ, SymShdr, Sym);\r
1aa311d1
CL
1627 } else if (mEhdr->e_machine == EM_LOONGARCH) {\r
1628 switch (ELF_R_TYPE(Rel->r_info)) {\r
1629 INT64 Offset;\r
1630 INT32 Lo, Hi;\r
1631\r
1632 case R_LARCH_SOP_PUSH_ABSOLUTE:\r
1633 //\r
1634 // Absolute relocation.\r
1635 //\r
1636 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
1637 break;\r
1638\r
1639 case R_LARCH_MARK_LA:\r
1640 case R_LARCH_64:\r
1641 case R_LARCH_NONE:\r
1642 case R_LARCH_32:\r
1643 case R_LARCH_RELATIVE:\r
1644 case R_LARCH_COPY:\r
1645 case R_LARCH_JUMP_SLOT:\r
1646 case R_LARCH_TLS_DTPMOD32:\r
1647 case R_LARCH_TLS_DTPMOD64:\r
1648 case R_LARCH_TLS_DTPREL32:\r
1649 case R_LARCH_TLS_DTPREL64:\r
1650 case R_LARCH_TLS_TPREL32:\r
1651 case R_LARCH_TLS_TPREL64:\r
1652 case R_LARCH_IRELATIVE:\r
1653 case R_LARCH_MARK_PCREL:\r
1654 case R_LARCH_SOP_PUSH_PCREL:\r
1655 case R_LARCH_SOP_PUSH_DUP:\r
1656 case R_LARCH_SOP_PUSH_GPREL:\r
1657 case R_LARCH_SOP_PUSH_TLS_TPREL:\r
1658 case R_LARCH_SOP_PUSH_TLS_GOT:\r
1659 case R_LARCH_SOP_PUSH_TLS_GD:\r
1660 case R_LARCH_SOP_PUSH_PLT_PCREL:\r
1661 case R_LARCH_SOP_ASSERT:\r
1662 case R_LARCH_SOP_NOT:\r
1663 case R_LARCH_SOP_SUB:\r
1664 case R_LARCH_SOP_SL:\r
1665 case R_LARCH_SOP_SR:\r
1666 case R_LARCH_SOP_ADD:\r
1667 case R_LARCH_SOP_AND:\r
1668 case R_LARCH_SOP_IF_ELSE:\r
1669 case R_LARCH_SOP_POP_32_S_10_5:\r
1670 case R_LARCH_SOP_POP_32_U_10_12:\r
1671 case R_LARCH_SOP_POP_32_S_10_12:\r
1672 case R_LARCH_SOP_POP_32_S_10_16:\r
1673 case R_LARCH_SOP_POP_32_S_10_16_S2:\r
1674 case R_LARCH_SOP_POP_32_S_5_20:\r
1675 case R_LARCH_SOP_POP_32_S_0_5_10_16_S2:\r
1676 case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:\r
1677 case R_LARCH_SOP_POP_32_U:\r
1678 case R_LARCH_ADD8:\r
1679 case R_LARCH_ADD16:\r
1680 case R_LARCH_ADD24:\r
1681 case R_LARCH_ADD32:\r
1682 case R_LARCH_ADD64:\r
1683 case R_LARCH_SUB8:\r
1684 case R_LARCH_SUB16:\r
1685 case R_LARCH_SUB24:\r
1686 case R_LARCH_SUB32:\r
1687 case R_LARCH_SUB64:\r
1688 case R_LARCH_GNU_VTINHERIT:\r
1689 case R_LARCH_GNU_VTENTRY:\r
1690 case R_LARCH_B16:\r
1691 case R_LARCH_B21:\r
1692 case R_LARCH_B26:\r
1693 case R_LARCH_ABS_HI20:\r
1694 case R_LARCH_ABS_LO12:\r
1695 case R_LARCH_ABS64_LO20:\r
1696 case R_LARCH_ABS64_HI12:\r
1697 case R_LARCH_PCALA_LO12:\r
1698 case R_LARCH_PCALA64_LO20:\r
1699 case R_LARCH_PCALA64_HI12:\r
1700 case R_LARCH_GOT_PC_LO12:\r
1701 case R_LARCH_GOT64_PC_LO20:\r
1702 case R_LARCH_GOT64_PC_HI12:\r
1703 case R_LARCH_GOT64_HI20:\r
1704 case R_LARCH_GOT64_LO12:\r
1705 case R_LARCH_GOT64_LO20:\r
1706 case R_LARCH_GOT64_HI12:\r
1707 case R_LARCH_TLS_LE_HI20:\r
1708 case R_LARCH_TLS_LE_LO12:\r
1709 case R_LARCH_TLS_LE64_LO20:\r
1710 case R_LARCH_TLS_LE64_HI12:\r
1711 case R_LARCH_TLS_IE_PC_HI20:\r
1712 case R_LARCH_TLS_IE_PC_LO12:\r
1713 case R_LARCH_TLS_IE64_PC_LO20:\r
1714 case R_LARCH_TLS_IE64_PC_HI12:\r
1715 case R_LARCH_TLS_IE64_HI20:\r
1716 case R_LARCH_TLS_IE64_LO12:\r
1717 case R_LARCH_TLS_IE64_LO20:\r
1718 case R_LARCH_TLS_IE64_HI12:\r
1719 case R_LARCH_TLS_LD_PC_HI20:\r
1720 case R_LARCH_TLS_LD64_HI20:\r
1721 case R_LARCH_TLS_GD_PC_HI20:\r
1722 case R_LARCH_TLS_GD64_HI20:\r
1723 case R_LARCH_RELAX:\r
1724 //\r
1725 // These types are not used or do not require fixup.\r
1726 //\r
1727 break;\r
1728\r
1729 case R_LARCH_GOT_PC_HI20:\r
1730 Offset = Sym->st_value - (UINTN)(Targ - mCoffFile);\r
1731 if (Offset < 0) {\r
1732 Offset = (UINTN)(Targ - mCoffFile) - Sym->st_value;\r
1733 Hi = Offset & ~0xfff;\r
1734 Lo = (INT32)((Offset & 0xfff) << 20) >> 20;\r
1735 if ((Lo < 0) && (Lo > -2048)) {\r
1736 Hi += 0x1000;\r
1737 Lo = ~(0x1000 - Lo) + 1;\r
1738 }\r
1739 Hi = ~Hi + 1;\r
1740 Lo = ~Lo + 1;\r
1741 } else {\r
1742 Hi = Offset & ~0xfff;\r
1743 Lo = (INT32)((Offset & 0xfff) << 20) >> 20;\r
1744 if (Lo < 0) {\r
1745 Hi += 0x1000;\r
1746 Lo = ~(0x1000 - Lo) + 1;\r
1747 }\r
1748 }\r
1749 // Re-encode the offset as PCADDU12I + ADDI.D(Convert LD.D) instruction\r
1750 *(UINT32 *)Targ &= 0x1f;\r
1751 *(UINT32 *)Targ |= 0x1c000000;\r
1752 *(UINT32 *)Targ |= (((Hi >> 12) & 0xfffff) << 5);\r
1753 *(UINT32 *)(Targ + 4) &= 0x3ff;\r
1754 *(UINT32 *)(Targ + 4) |= 0x2c00000 | ((Lo & 0xfff) << 10);\r
1755 break;\r
1756\r
1757 //\r
1758 // Attempt to convert instruction.\r
1759 //\r
1760 case R_LARCH_PCALA_HI20:\r
1761 // Decode the PCALAU12I instruction and the instruction that following it.\r
1762 Offset = ((INT32)((*(UINT32 *)Targ & 0x1ffffe0) << 7));\r
1763 Offset += ((INT32)((*(UINT32 *)(Targ + 4) & 0x3ffc00) << 10) >> 20);\r
1764 //\r
1765 // PCALA offset is relative to the previous page boundary,\r
1766 // whereas PCADD offset is relative to the instruction itself.\r
1767 // So fix up the offset so it points to the page containing\r
1768 // the symbol.\r
1769 //\r
1770 Offset -= (UINTN)(Targ - mCoffFile) & 0xfff;\r
1771 if (Offset < 0) {\r
1772 Offset = -Offset;\r
1773 Hi = Offset & ~0xfff;\r
1774 Lo = (INT32)((Offset & 0xfff) << 20) >> 20;\r
1775 if ((Lo < 0) && (Lo > -2048)) {\r
1776 Hi += 0x1000;\r
1777 Lo = ~(0x1000 - Lo) + 1;\r
1778 }\r
1779 Hi = ~Hi + 1;\r
1780 Lo = ~Lo + 1;\r
1781 } else {\r
1782 Hi = Offset & ~0xfff;\r
1783 Lo = (INT32)((Offset & 0xfff) << 20) >> 20;\r
1784 if (Lo < 0) {\r
1785 Hi += 0x1000;\r
1786 Lo = ~(0x1000 - Lo) + 1;\r
1787 }\r
1788 }\r
1789 // Convert the first instruction from PCALAU12I to PCADDU12I and re-encode the offset into them.\r
1790 *(UINT32 *)Targ &= 0x1f;\r
1791 *(UINT32 *)Targ |= 0x1c000000;\r
1792 *(UINT32 *)Targ |= (((Hi >> 12) & 0xfffff) << 5);\r
1793 *(UINT32 *)(Targ + 4) &= 0xffc003ff;\r
1794 *(UINT32 *)(Targ + 4) |= (Lo & 0xfff) << 10;\r
1795 break;\r
1796 default:\r
1797 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_LOONGARCH relocation 0x%x.", mInImageName, (unsigned) ELF64_R_TYPE(Rel->r_info));\r
1798 }\r
f51461c8
LG
1799 } else {\r
1800 Error (NULL, 0, 3000, "Invalid", "Not a supported machine type");\r
1801 }\r
1802 }\r
1803 }\r
1804 }\r
1805\r
1806 return TRUE;\r
1807}\r
1808\r
1809STATIC\r
1810VOID\r
1811WriteRelocations64 (\r
1812 VOID\r
1813 )\r
1814{\r
1815 UINT32 Index;\r
1816 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
1817 EFI_IMAGE_DATA_DIRECTORY *Dir;\r
ad1db975 1818 UINT32 RiscVRelType;\r
f51461c8
LG
1819\r
1820 for (Index = 0; Index < mEhdr->e_shnum; Index++) {\r
1821 Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
1822 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {\r
1823 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);\r
1824 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {\r
1825 UINT64 RelIdx;\r
1826\r
1827 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {\r
1828 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
1829\r
1830 if (mEhdr->e_machine == EM_X86_64) {\r
1831 switch (ELF_R_TYPE(Rel->r_info)) {\r
1832 case R_X86_64_NONE:\r
1833 case R_X86_64_PC32:\r
c9f29755 1834 case R_X86_64_PLT32:\r
ecbaa856
Z
1835 case R_X86_64_GOTPCREL:\r
1836 case R_X86_64_GOTPCRELX:\r
1837 case R_X86_64_REX_GOTPCRELX:\r
f51461c8
LG
1838 break;\r
1839 case R_X86_64_64:\r
179efe5d 1840 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08llX",\r
f51461c8
LG
1841 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
1842 CoffAddFixup(\r
1843 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1844 + (Rel->r_offset - SecShdr->sh_addr)),\r
1845 EFI_IMAGE_REL_BASED_DIR64);\r
1846 break;\r
c6a14de3
Z
1847 //\r
1848 // R_X86_64_32 and R_X86_64_32S are ELF64 relocations emitted when using\r
1849 // the SYSV X64 ABI small non-position-independent code model.\r
1850 // R_X86_64_32 is used for unsigned 32-bit immediates with a 32-bit operand\r
1851 // size. The value is either not extended, or zero-extended to 64 bits.\r
1852 // R_X86_64_32S is used for either signed 32-bit non-rip-relative displacements\r
1853 // or signed 32-bit immediates with a 64-bit operand size. The value is\r
1854 // sign-extended to 64 bits.\r
1855 // EFI_IMAGE_REL_BASED_HIGHLOW is a PE relocation that uses 32-bit arithmetic\r
1856 // for rebasing an image.\r
1857 // EFI PE binaries declare themselves EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE and\r
1858 // may load above 2GB. If an EFI PE binary with a converted R_X86_64_32S\r
1859 // relocation is loaded above 2GB, the value will get sign-extended to the\r
1860 // negative part of the 64-bit address space. The negative part of the 64-bit\r
1861 // address space is unmapped, so accessing such an address page-faults.\r
1862 // In order to support R_X86_64_32S, it is necessary to unset\r
1863 // EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE, and the EFI PE loader must implement\r
1864 // this flag and abstain from loading such a PE binary above 2GB.\r
1865 // Since this feature is not supported, support for R_X86_64_32S (and hence\r
1866 // the small non-position-independent code model) is disabled.\r
1867 //\r
1868 // case R_X86_64_32S:\r
f51461c8 1869 case R_X86_64_32:\r
179efe5d 1870 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08llX",\r
f51461c8
LG
1871 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
1872 CoffAddFixup(\r
1873 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1874 + (Rel->r_offset - SecShdr->sh_addr)),\r
1875 EFI_IMAGE_REL_BASED_HIGHLOW);\r
1876 break;\r
1877 default:\r
1878 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
1879 }\r
1880 } else if (mEhdr->e_machine == EM_AARCH64) {\r
24d610e6 1881\r
f51461c8 1882 switch (ELF_R_TYPE(Rel->r_info)) {\r
87280982 1883 case R_AARCH64_ADR_PREL_LO21:\r
87280982 1884 case R_AARCH64_CONDBR19:\r
f51461c8 1885 case R_AARCH64_LD_PREL_LO19:\r
f51461c8 1886 case R_AARCH64_CALL26:\r
f51461c8 1887 case R_AARCH64_JUMP26:\r
0b6249f5
AB
1888 case R_AARCH64_PREL64:\r
1889 case R_AARCH64_PREL32:\r
1890 case R_AARCH64_PREL16:\r
f51461c8 1891 case R_AARCH64_ADR_PREL_PG_HI21:\r
f51461c8 1892 case R_AARCH64_ADD_ABS_LO12_NC:\r
24d610e6
AB
1893 case R_AARCH64_LDST8_ABS_LO12_NC:\r
1894 case R_AARCH64_LDST16_ABS_LO12_NC:\r
1895 case R_AARCH64_LDST32_ABS_LO12_NC:\r
1896 case R_AARCH64_LDST64_ABS_LO12_NC:\r
1897 case R_AARCH64_LDST128_ABS_LO12_NC:\r
d2687f23
AB
1898 case R_AARCH64_ADR_GOT_PAGE:\r
1899 case R_AARCH64_LD64_GOT_LO12_NC:\r
7b8f69d7
AB
1900 case R_AARCH64_LD64_GOTOFF_LO15:\r
1901 case R_AARCH64_LD64_GOTPAGE_LO15:\r
0b6249f5
AB
1902 //\r
1903 // No fixups are required for relative relocations, provided that\r
1904 // the relative offsets between sections have been preserved in\r
1905 // the ELF to PE/COFF conversion. We have already asserted that\r
1906 // this is the case in WriteSections64 ().\r
1907 //\r
f51461c8
LG
1908 break;\r
1909\r
1910 case R_AARCH64_ABS64:\r
1911 CoffAddFixup(\r
1912 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1913 + (Rel->r_offset - SecShdr->sh_addr)),\r
1914 EFI_IMAGE_REL_BASED_DIR64);\r
1915 break;\r
1916\r
1917 case R_AARCH64_ABS32:\r
1918 CoffAddFixup(\r
1919 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1920 + (Rel->r_offset - SecShdr->sh_addr)),\r
1921 EFI_IMAGE_REL_BASED_HIGHLOW);\r
1922 break;\r
1923\r
1924 default:\r
1925 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
1926 }\r
ad1db975
AC
1927 } else if (mEhdr->e_machine == EM_RISCV64) {\r
1928 RiscVRelType = ELF_R_TYPE(Rel->r_info);\r
1929 switch (RiscVRelType) {\r
1930 case R_RISCV_NONE:\r
1931 break;\r
1932\r
1933 case R_RISCV_32:\r
1934 CoffAddFixup(\r
1935 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1936 + (Rel->r_offset - SecShdr->sh_addr)),\r
1937 EFI_IMAGE_REL_BASED_HIGHLOW);\r
1938 break;\r
1939\r
1940 case R_RISCV_64:\r
1941 CoffAddFixup(\r
1942 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1943 + (Rel->r_offset - SecShdr->sh_addr)),\r
1944 EFI_IMAGE_REL_BASED_DIR64);\r
1945 break;\r
1946\r
1947 case R_RISCV_HI20:\r
1948 CoffAddFixup(\r
1949 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1950 + (Rel->r_offset - SecShdr->sh_addr)),\r
1951 EFI_IMAGE_REL_BASED_RISCV_HI20);\r
1952 break;\r
1953\r
1954 case R_RISCV_LO12_I:\r
1955 CoffAddFixup(\r
1956 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1957 + (Rel->r_offset - SecShdr->sh_addr)),\r
1958 EFI_IMAGE_REL_BASED_RISCV_LOW12I);\r
1959 break;\r
1960\r
1961 case R_RISCV_LO12_S:\r
1962 CoffAddFixup(\r
1963 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1964 + (Rel->r_offset - SecShdr->sh_addr)),\r
1965 EFI_IMAGE_REL_BASED_RISCV_LOW12S);\r
1966 break;\r
1967\r
1968 case R_RISCV_ADD64:\r
1969 CoffAddFixup(\r
1970 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1971 + (Rel->r_offset - SecShdr->sh_addr)),\r
1972 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
1973 break;\r
1974\r
1975 case R_RISCV_SUB64:\r
1976 CoffAddFixup(\r
1977 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1978 + (Rel->r_offset - SecShdr->sh_addr)),\r
1979 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
1980 break;\r
1981\r
1982 case R_RISCV_ADD32:\r
1983 CoffAddFixup(\r
1984 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1985 + (Rel->r_offset - SecShdr->sh_addr)),\r
1986 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
1987 break;\r
1988\r
1989 case R_RISCV_SUB32:\r
1990 CoffAddFixup(\r
1991 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1992 + (Rel->r_offset - SecShdr->sh_addr)),\r
1993 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
1994 break;\r
1995\r
1996 case R_RISCV_BRANCH:\r
1997 CoffAddFixup(\r
1998 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1999 + (Rel->r_offset - SecShdr->sh_addr)),\r
2000 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
2001 break;\r
2002\r
2003 case R_RISCV_JAL:\r
2004 CoffAddFixup(\r
2005 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
2006 + (Rel->r_offset - SecShdr->sh_addr)),\r
2007 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
2008 break;\r
2009\r
2010 case R_RISCV_GPREL_I:\r
2011 case R_RISCV_GPREL_S:\r
2012 case R_RISCV_CALL:\r
abfff7c4 2013 case R_RISCV_CALL_PLT:\r
ad1db975
AC
2014 case R_RISCV_RVC_BRANCH:\r
2015 case R_RISCV_RVC_JUMP:\r
2016 case R_RISCV_RELAX:\r
2017 case R_RISCV_SUB6:\r
2018 case R_RISCV_SET6:\r
2019 case R_RISCV_SET8:\r
2020 case R_RISCV_SET16:\r
2021 case R_RISCV_SET32:\r
2022 case R_RISCV_PCREL_HI20:\r
abfff7c4 2023 case R_RISCV_GOT_HI20:\r
ad1db975 2024 case R_RISCV_PCREL_LO12_I:\r
c32c5911 2025 case R_RISCV_PCREL_LO12_S:\r
ad1db975
AC
2026 break;\r
2027\r
2028 default:\r
2029 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_RISCV64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
2030 }\r
1aa311d1
CL
2031 } else if (mEhdr->e_machine == EM_LOONGARCH) {\r
2032 switch (ELF_R_TYPE(Rel->r_info)) {\r
2033 case R_LARCH_MARK_LA:\r
2034 CoffAddFixup(\r
2035 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
2036 + (Rel->r_offset - SecShdr->sh_addr)),\r
2037 EFI_IMAGE_REL_BASED_LOONGARCH64_MARK_LA);\r
2038 break;\r
2039 case R_LARCH_64:\r
2040 CoffAddFixup(\r
2041 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
2042 + (Rel->r_offset - SecShdr->sh_addr)),\r
2043 EFI_IMAGE_REL_BASED_DIR64);\r
2044 break;\r
2045 case R_LARCH_NONE:\r
2046 case R_LARCH_32:\r
2047 case R_LARCH_RELATIVE:\r
2048 case R_LARCH_COPY:\r
2049 case R_LARCH_JUMP_SLOT:\r
2050 case R_LARCH_TLS_DTPMOD32:\r
2051 case R_LARCH_TLS_DTPMOD64:\r
2052 case R_LARCH_TLS_DTPREL32:\r
2053 case R_LARCH_TLS_DTPREL64:\r
2054 case R_LARCH_TLS_TPREL32:\r
2055 case R_LARCH_TLS_TPREL64:\r
2056 case R_LARCH_IRELATIVE:\r
2057 case R_LARCH_MARK_PCREL:\r
2058 case R_LARCH_SOP_PUSH_PCREL:\r
2059 case R_LARCH_SOP_PUSH_ABSOLUTE:\r
2060 case R_LARCH_SOP_PUSH_DUP:\r
2061 case R_LARCH_SOP_PUSH_GPREL:\r
2062 case R_LARCH_SOP_PUSH_TLS_TPREL:\r
2063 case R_LARCH_SOP_PUSH_TLS_GOT:\r
2064 case R_LARCH_SOP_PUSH_TLS_GD:\r
2065 case R_LARCH_SOP_PUSH_PLT_PCREL:\r
2066 case R_LARCH_SOP_ASSERT:\r
2067 case R_LARCH_SOP_NOT:\r
2068 case R_LARCH_SOP_SUB:\r
2069 case R_LARCH_SOP_SL:\r
2070 case R_LARCH_SOP_SR:\r
2071 case R_LARCH_SOP_ADD:\r
2072 case R_LARCH_SOP_AND:\r
2073 case R_LARCH_SOP_IF_ELSE:\r
2074 case R_LARCH_SOP_POP_32_S_10_5:\r
2075 case R_LARCH_SOP_POP_32_U_10_12:\r
2076 case R_LARCH_SOP_POP_32_S_10_12:\r
2077 case R_LARCH_SOP_POP_32_S_10_16:\r
2078 case R_LARCH_SOP_POP_32_S_10_16_S2:\r
2079 case R_LARCH_SOP_POP_32_S_5_20:\r
2080 case R_LARCH_SOP_POP_32_S_0_5_10_16_S2:\r
2081 case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:\r
2082 case R_LARCH_SOP_POP_32_U:\r
2083 case R_LARCH_ADD8:\r
2084 case R_LARCH_ADD16:\r
2085 case R_LARCH_ADD24:\r
2086 case R_LARCH_ADD32:\r
2087 case R_LARCH_ADD64:\r
2088 case R_LARCH_SUB8:\r
2089 case R_LARCH_SUB16:\r
2090 case R_LARCH_SUB24:\r
2091 case R_LARCH_SUB32:\r
2092 case R_LARCH_SUB64:\r
2093 case R_LARCH_GNU_VTINHERIT:\r
2094 case R_LARCH_GNU_VTENTRY:\r
2095 case R_LARCH_B16:\r
2096 case R_LARCH_B21:\r
2097 case R_LARCH_B26:\r
2098 case R_LARCH_ABS_HI20:\r
2099 case R_LARCH_ABS_LO12:\r
2100 case R_LARCH_ABS64_LO20:\r
2101 case R_LARCH_ABS64_HI12:\r
2102 case R_LARCH_PCALA_HI20:\r
2103 case R_LARCH_PCALA_LO12:\r
2104 case R_LARCH_PCALA64_LO20:\r
2105 case R_LARCH_PCALA64_HI12:\r
2106 case R_LARCH_GOT_PC_HI20:\r
2107 case R_LARCH_GOT_PC_LO12:\r
2108 case R_LARCH_GOT64_PC_LO20:\r
2109 case R_LARCH_GOT64_PC_HI12:\r
2110 case R_LARCH_GOT64_HI20:\r
2111 case R_LARCH_GOT64_LO12:\r
2112 case R_LARCH_GOT64_LO20:\r
2113 case R_LARCH_GOT64_HI12:\r
2114 case R_LARCH_TLS_LE_HI20:\r
2115 case R_LARCH_TLS_LE_LO12:\r
2116 case R_LARCH_TLS_LE64_LO20:\r
2117 case R_LARCH_TLS_LE64_HI12:\r
2118 case R_LARCH_TLS_IE_PC_HI20:\r
2119 case R_LARCH_TLS_IE_PC_LO12:\r
2120 case R_LARCH_TLS_IE64_PC_LO20:\r
2121 case R_LARCH_TLS_IE64_PC_HI12:\r
2122 case R_LARCH_TLS_IE64_HI20:\r
2123 case R_LARCH_TLS_IE64_LO12:\r
2124 case R_LARCH_TLS_IE64_LO20:\r
2125 case R_LARCH_TLS_IE64_HI12:\r
2126 case R_LARCH_TLS_LD_PC_HI20:\r
2127 case R_LARCH_TLS_LD64_HI20:\r
2128 case R_LARCH_TLS_GD_PC_HI20:\r
2129 case R_LARCH_TLS_GD64_HI20:\r
2130 case R_LARCH_RELAX:\r
2131 //\r
2132 // These types are not used or do not require fixup in PE format files.\r
2133 //\r
2134 break;\r
2135 default:\r
2136 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_LOONGARCH relocation 0x%x.", mInImageName, (unsigned) ELF64_R_TYPE(Rel->r_info));\r
2137 }\r
f51461c8
LG
2138 } else {\r
2139 Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);\r
2140 }\r
2141 }\r
ecbaa856
Z
2142 if (mEhdr->e_machine == EM_X86_64 && RelShdr->sh_info == mGOTShindex) {\r
2143 //\r
2144 // Tack relocations for GOT entries after other relocations for\r
2145 // the section the GOT is in, as it's usually found at the end\r
2146 // of the section. This is done in order to maintain Rva order\r
2147 // of Coff relocations.\r
2148 //\r
2149 EmitGOTRelocations();\r
2150 }\r
f51461c8
LG
2151 }\r
2152 }\r
2153 }\r
2154\r
ecbaa856
Z
2155 if (mEhdr->e_machine == EM_X86_64) {\r
2156 //\r
2157 // This is a safety net just in case the GOT is in a section\r
2158 // with no other relocations and the first invocation of\r
2159 // EmitGOTRelocations() above was skipped. This invocation\r
2160 // does not maintain Rva order of Coff relocations.\r
2161 // At present, with a single text section, all references to\r
2162 // the GOT and the GOT itself reside in section .text, so\r
2163 // if there's a GOT at all, the first invocation above\r
2164 // is executed.\r
2165 //\r
2166 EmitGOTRelocations();\r
2167 }\r
f51461c8
LG
2168 //\r
2169 // Pad by adding empty entries.\r
2170 //\r
2171 while (mCoffOffset & (mCoffAlignment - 1)) {\r
2172 CoffAddFixupEntry(0);\r
2173 }\r
2174\r
2175 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
2176 Dir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
2177 Dir->Size = mCoffOffset - mRelocOffset;\r
2178 if (Dir->Size == 0) {\r
2179 // If no relocations, null out the directory entry and don't add the .reloc section\r
2180 Dir->VirtualAddress = 0;\r
2181 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
2182 } else {\r
2183 Dir->VirtualAddress = mRelocOffset;\r
2184 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,\r
2185 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
2186 | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
2187 | EFI_IMAGE_SCN_MEM_READ);\r
2188 }\r
2189}\r
2190\r
2191STATIC\r
2192VOID\r
2193WriteDebug64 (\r
2194 VOID\r
2195 )\r
2196{\r
2197 UINT32 Len;\r
f51461c8
LG
2198 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
2199 EFI_IMAGE_DATA_DIRECTORY *DataDir;\r
2200 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;\r
2201 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;\r
2202\r
2203 Len = strlen(mInImageName) + 1;\r
f51461c8 2204\r
0192b71c 2205 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);\r
f51461c8
LG
2206 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
2207 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
0192b71c
AB
2208 Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
2209 Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
f51461c8
LG
2210\r
2211 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);\r
2212 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;\r
2213 strcpy ((char *)(Nb10 + 1), mInImageName);\r
2214\r
2215\r
2216 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
2217 DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
0192b71c 2218 DataDir->VirtualAddress = mDebugOffset;\r
60e85a39 2219 DataDir->Size = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
f51461c8
LG
2220}\r
2221\r
2222STATIC\r
2223VOID\r
2224SetImageSize64 (\r
2225 VOID\r
2226 )\r
2227{\r
2228 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
2229\r
2230 //\r
2231 // Set image size\r
2232 //\r
2233 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
2234 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = mCoffOffset;\r
2235}\r
2236\r
2237STATIC\r
2238VOID\r
2239CleanUp64 (\r
2240 VOID\r
2241 )\r
2242{\r
2243 if (mCoffSectionsOffset != NULL) {\r
2244 free (mCoffSectionsOffset);\r
2245 }\r
2246}\r
2247\r
414cd2a4
HLX
2248STATIC\r
2249VOID\r
2250WriteExport64 (\r
2251 VOID\r
2252 )\r
2253{\r
2254 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
2255 EFI_IMAGE_EXPORT_DIRECTORY *ExportDir;\r
2256 EFI_IMAGE_DATA_DIRECTORY *DataDir;\r
2257 UINT32 FileNameOffset;\r
2258 UINT32 NameOffset;\r
2259 UINT16 Index;\r
2260 UINT8 *Tdata = NULL;\r
2261\r
2262 ExportDir = (EFI_IMAGE_EXPORT_DIRECTORY*)(mCoffFile + mExportOffset);\r
2263 ExportDir->Characteristics = 0;\r
2264 ExportDir->TimeDateStamp = 0;\r
2265 ExportDir->MajorVersion = 0;\r
2266 ExportDir->MinorVersion =0;\r
2267 ExportDir->Name = 0;\r
2268 ExportDir->NumberOfFunctions = mExportSymNum;\r
2269 ExportDir->NumberOfNames = mExportSymNum;\r
2270 ExportDir->Base = EFI_IMAGE_EXPORT_ORDINAL_BASE;\r
2271 ExportDir->AddressOfFunctions = mExportOffset + sizeof(EFI_IMAGE_EXPORT_DIRECTORY);\r
2272 ExportDir->AddressOfNames = ExportDir->AddressOfFunctions + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum;\r
2273 ExportDir->AddressOfNameOrdinals = ExportDir->AddressOfNames + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum;\r
2274\r
2275 FileNameOffset = ExportDir->AddressOfNameOrdinals + EFI_IMAGE_EXPORT_ORDINAL_SIZE * mExportSymNum;\r
2276 NameOffset = FileNameOffset + strlen(mInImageName) + 1;\r
2277\r
2278 // Write Input image Name RVA\r
2279 ExportDir->Name = FileNameOffset;\r
2280\r
2281 // Write Input image Name\r
2282 strcpy((char *)(mCoffFile + FileNameOffset), mInImageName);\r
2283\r
2284 for (Index = 0; Index < mExportSymNum; Index++) {\r
2285 //\r
2286 // Write Export Address Table\r
2287 //\r
2288 Tdata = mCoffFile + ExportDir->AddressOfFunctions + Index * EFI_IMAGE_EXPORT_ADDR_SIZE;\r
2289 *(UINT32 *)Tdata = mExportRVA[Index];\r
2290\r
2291 //\r
2292 // Write Export Name Pointer Table\r
2293 //\r
2294 Tdata = mCoffFile + ExportDir->AddressOfNames + Index * EFI_IMAGE_EXPORT_ADDR_SIZE;\r
2295 *(UINT32 *)Tdata = NameOffset;\r
2296\r
2297 //\r
2298 // Write Export Ordinal table\r
2299 //\r
2300 Tdata = mCoffFile + ExportDir->AddressOfNameOrdinals + Index * EFI_IMAGE_EXPORT_ORDINAL_SIZE;\r
2301 *(UINT16 *)Tdata = Index;\r
2302\r
2303 //\r
2304 // Write Export Name Table\r
2305 //\r
2306 strcpy((char *)(mCoffFile + NameOffset), mExportSymName[Index]);\r
2307 NameOffset += strlen(mExportSymName[Index]) + 1;\r
2308 }\r
2309\r
2310 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
2311 DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT];\r
2312 DataDir->VirtualAddress = mExportOffset;\r
2313 DataDir->Size = mExportSize;\r
2314\r
2315}\r
f51461c8 2316\r