]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFw/Elf64Convert.c
MdeModulePkg PCD: Print which PCD was unable to be found
[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
87280982 5Portions copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
ad1db975 6Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>\r
f51461c8 7\r
2e351cbe 8SPDX-License-Identifier: BSD-2-Clause-Patent\r
f51461c8
LG
9\r
10**/\r
11\r
12#include "WinNtInclude.h"\r
13\r
14#ifndef __GNUC__\r
15#include <windows.h>\r
16#include <io.h>\r
17#endif\r
18#include <assert.h>\r
19#include <stdio.h>\r
20#include <stdlib.h>\r
21#include <string.h>\r
22#include <time.h>\r
23#include <ctype.h>\r
24\r
25#include <Common/UefiBaseTypes.h>\r
26#include <IndustryStandard/PeImage.h>\r
27\r
28#include "PeCoffLib.h"\r
29#include "EfiUtilityMsgs.h"\r
30\r
31#include "GenFw.h"\r
32#include "ElfConvert.h"\r
33#include "Elf64Convert.h"\r
34\r
35STATIC\r
36VOID\r
37ScanSections64 (\r
38 VOID\r
39 );\r
40\r
41STATIC\r
42BOOLEAN\r
43WriteSections64 (\r
44 SECTION_FILTER_TYPES FilterType\r
45 );\r
46\r
47STATIC\r
48VOID\r
49WriteRelocations64 (\r
50 VOID\r
51 );\r
52\r
53STATIC\r
54VOID\r
55WriteDebug64 (\r
56 VOID\r
57 );\r
58\r
59STATIC\r
60VOID\r
61SetImageSize64 (\r
62 VOID\r
63 );\r
64\r
65STATIC\r
66VOID\r
67CleanUp64 (\r
68 VOID\r
69 );\r
70\r
71//\r
fb0b35e0 72// Rename ELF32 structures to common names to help when porting to ELF64.\r
f51461c8
LG
73//\r
74typedef Elf64_Shdr Elf_Shdr;\r
75typedef Elf64_Ehdr Elf_Ehdr;\r
76typedef Elf64_Rel Elf_Rel;\r
77typedef Elf64_Rela Elf_Rela;\r
78typedef Elf64_Sym Elf_Sym;\r
79typedef Elf64_Phdr Elf_Phdr;\r
80typedef Elf64_Dyn Elf_Dyn;\r
81#define ELFCLASS ELFCLASS64\r
82#define ELF_R_TYPE(r) ELF64_R_TYPE(r)\r
83#define ELF_R_SYM(r) ELF64_R_SYM(r)\r
84\r
85//\r
86// Well known ELF structures.\r
87//\r
88STATIC Elf_Ehdr *mEhdr;\r
89STATIC Elf_Shdr *mShdrBase;\r
90STATIC Elf_Phdr *mPhdrBase;\r
91\r
ecbaa856
Z
92//\r
93// GOT information\r
94//\r
95STATIC Elf_Shdr *mGOTShdr = NULL;\r
96STATIC UINT32 mGOTShindex = 0;\r
97STATIC UINT32 *mGOTCoffEntries = NULL;\r
98STATIC UINT32 mGOTMaxCoffEntries = 0;\r
99STATIC UINT32 mGOTNumCoffEntries = 0;\r
100\r
f51461c8
LG
101//\r
102// Coff information\r
103//\r
54b1b57a 104STATIC UINT32 mCoffAlignment = 0x20;\r
f51461c8
LG
105\r
106//\r
107// PE section alignment.\r
108//\r
0192b71c 109STATIC const UINT16 mCoffNbrSections = 4;\r
f51461c8
LG
110\r
111//\r
112// ELF sections to offset in Coff file.\r
113//\r
114STATIC UINT32 *mCoffSectionsOffset = NULL;\r
115\r
116//\r
117// Offsets in COFF file\r
118//\r
119STATIC UINT32 mNtHdrOffset;\r
120STATIC UINT32 mTextOffset;\r
121STATIC UINT32 mDataOffset;\r
122STATIC UINT32 mHiiRsrcOffset;\r
123STATIC UINT32 mRelocOffset;\r
0192b71c 124STATIC UINT32 mDebugOffset;\r
f51461c8 125\r
ad1db975
AC
126//\r
127// Used for RISC-V relocations.\r
128//\r
129STATIC UINT8 *mRiscVPass1Targ = NULL;\r
130STATIC Elf_Shdr *mRiscVPass1Sym = NULL;\r
131STATIC Elf64_Half mRiscVPass1SymSecIndex = 0;\r
abfff7c4
S
132STATIC INT32 mRiscVPass1Offset;\r
133STATIC INT32 mRiscVPass1GotFixup;\r
ad1db975 134\r
f51461c8
LG
135//\r
136// Initialization Function\r
137//\r
138BOOLEAN\r
139InitializeElf64 (\r
140 UINT8 *FileBuffer,\r
141 ELF_FUNCTION_TABLE *ElfFunctions\r
142 )\r
143{\r
144 //\r
145 // Initialize data pointer and structures.\r
146 //\r
147 VerboseMsg ("Set EHDR");\r
148 mEhdr = (Elf_Ehdr*) FileBuffer;\r
149\r
150 //\r
151 // Check the ELF64 specific header information.\r
152 //\r
153 VerboseMsg ("Check ELF64 Header Information");\r
154 if (mEhdr->e_ident[EI_CLASS] != ELFCLASS64) {\r
155 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFCLASS64");\r
156 return FALSE;\r
157 }\r
158 if (mEhdr->e_ident[EI_DATA] != ELFDATA2LSB) {\r
159 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB");\r
160 return FALSE;\r
161 }\r
162 if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) {\r
163 Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN");\r
164 return FALSE;\r
165 }\r
ad1db975 166 if (!((mEhdr->e_machine == EM_X86_64) || (mEhdr->e_machine == EM_AARCH64) || (mEhdr->e_machine == EM_RISCV64))) {\r
251f9b39 167 Warning (NULL, 0, 3000, "Unsupported", "ELF e_machine is not Elf64 machine.");\r
f51461c8
LG
168 }\r
169 if (mEhdr->e_version != EV_CURRENT) {\r
170 Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT);\r
171 return FALSE;\r
172 }\r
173\r
174 //\r
175 // Update section header pointers\r
176 //\r
177 VerboseMsg ("Update Header Pointers");\r
178 mShdrBase = (Elf_Shdr *)((UINT8 *)mEhdr + mEhdr->e_shoff);\r
179 mPhdrBase = (Elf_Phdr *)((UINT8 *)mEhdr + mEhdr->e_phoff);\r
180\r
181 //\r
182 // Create COFF Section offset buffer and zero.\r
183 //\r
184 VerboseMsg ("Create COFF Section Offset Buffer");\r
185 mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32));\r
06b45735
HW
186 if (mCoffSectionsOffset == NULL) {\r
187 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
188 return FALSE;\r
189 }\r
f51461c8
LG
190 memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32));\r
191\r
192 //\r
193 // Fill in function pointers.\r
194 //\r
195 VerboseMsg ("Fill in Function Pointers");\r
196 ElfFunctions->ScanSections = ScanSections64;\r
197 ElfFunctions->WriteSections = WriteSections64;\r
198 ElfFunctions->WriteRelocations = WriteRelocations64;\r
199 ElfFunctions->WriteDebug = WriteDebug64;\r
200 ElfFunctions->SetImageSize = SetImageSize64;\r
201 ElfFunctions->CleanUp = CleanUp64;\r
202\r
203 return TRUE;\r
204}\r
205\r
206\r
207//\r
208// Header by Index functions\r
209//\r
210STATIC\r
211Elf_Shdr*\r
212GetShdrByIndex (\r
213 UINT32 Num\r
214 )\r
215{\r
17751c5f
ML
216 if (Num >= mEhdr->e_shnum) {\r
217 Error (NULL, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num);\r
218 exit(EXIT_FAILURE);\r
219 }\r
220\r
f51461c8
LG
221 return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);\r
222}\r
223\r
224STATIC\r
225UINT32\r
226CoffAlign (\r
227 UINT32 Offset\r
228 )\r
229{\r
230 return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);\r
231}\r
232\r
4f7d5c67
AB
233STATIC\r
234UINT32\r
235DebugRvaAlign (\r
236 UINT32 Offset\r
237 )\r
238{\r
239 return (Offset + 3) & ~3;\r
240}\r
241\r
f51461c8
LG
242//\r
243// filter functions\r
244//\r
245STATIC\r
246BOOLEAN\r
247IsTextShdr (\r
248 Elf_Shdr *Shdr\r
249 )\r
250{\r
1b380aa6
LG
251 return (BOOLEAN) (((Shdr->sh_flags & (SHF_EXECINSTR | SHF_ALLOC)) == (SHF_EXECINSTR | SHF_ALLOC)) ||\r
252 ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC));\r
f51461c8
LG
253}\r
254\r
255STATIC\r
256BOOLEAN\r
257IsHiiRsrcShdr (\r
258 Elf_Shdr *Shdr\r
259 )\r
260{\r
261 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
262\r
263 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);\r
264}\r
265\r
266STATIC\r
267BOOLEAN\r
268IsDataShdr (\r
269 Elf_Shdr *Shdr\r
270 )\r
271{\r
272 if (IsHiiRsrcShdr(Shdr)) {\r
273 return FALSE;\r
274 }\r
c6b872c6 275 return (BOOLEAN) (Shdr->sh_flags & (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);\r
f51461c8
LG
276}\r
277\r
621bb723
ML
278STATIC\r
279BOOLEAN\r
280IsStrtabShdr (\r
281 Elf_Shdr *Shdr\r
282 )\r
283{\r
284 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
285\r
286 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_STRTAB_SECTION_NAME) == 0);\r
287}\r
288\r
289STATIC\r
290Elf_Shdr *\r
291FindStrtabShdr (\r
292 VOID\r
293 )\r
294{\r
295 UINT32 i;\r
296 for (i = 0; i < mEhdr->e_shnum; i++) {\r
297 Elf_Shdr *shdr = GetShdrByIndex(i);\r
298 if (IsStrtabShdr(shdr)) {\r
299 return shdr;\r
300 }\r
301 }\r
302 return NULL;\r
303}\r
304\r
305STATIC\r
306const UINT8 *\r
307GetSymName (\r
308 Elf_Sym *Sym\r
309 )\r
310{\r
7be7b25d
HW
311 Elf_Shdr *StrtabShdr;\r
312 UINT8 *StrtabContents;\r
313 BOOLEAN foundEnd;\r
314 UINT32 i;\r
315\r
621bb723
ML
316 if (Sym->st_name == 0) {\r
317 return NULL;\r
318 }\r
319\r
7be7b25d 320 StrtabShdr = FindStrtabShdr();\r
621bb723
ML
321 if (StrtabShdr == NULL) {\r
322 return NULL;\r
323 }\r
324\r
325 assert(Sym->st_name < StrtabShdr->sh_size);\r
326\r
7be7b25d 327 StrtabContents = (UINT8*)mEhdr + StrtabShdr->sh_offset;\r
ea3e924a 328\r
7be7b25d 329 foundEnd = FALSE;\r
a754c70c 330 for (i= Sym->st_name; (i < StrtabShdr->sh_size) && !foundEnd; i++) {\r
7be7b25d 331 foundEnd = (BOOLEAN)(StrtabContents[i] == 0);\r
ea3e924a
ML
332 }\r
333 assert(foundEnd);\r
334\r
335 return StrtabContents + Sym->st_name;\r
621bb723
ML
336}\r
337\r
ecbaa856
Z
338//\r
339// Find the ELF section hosting the GOT from an ELF Rva\r
340// of a single GOT entry. Normally, GOT is placed in\r
341// ELF .text section, so assume once we find in which\r
342// section the GOT is, all GOT entries are there, and\r
343// just verify this.\r
344//\r
345STATIC\r
346VOID\r
347FindElfGOTSectionFromGOTEntryElfRva (\r
348 Elf64_Addr GOTEntryElfRva\r
349 )\r
350{\r
351 UINT32 i;\r
352 if (mGOTShdr != NULL) {\r
353 if (GOTEntryElfRva >= mGOTShdr->sh_addr &&\r
354 GOTEntryElfRva < mGOTShdr->sh_addr + mGOTShdr->sh_size) {\r
355 return;\r
356 }\r
357 Error (NULL, 0, 3000, "Unsupported", "FindElfGOTSectionFromGOTEntryElfRva: GOT entries found in multiple sections.");\r
358 exit(EXIT_FAILURE);\r
359 }\r
360 for (i = 0; i < mEhdr->e_shnum; i++) {\r
361 Elf_Shdr *shdr = GetShdrByIndex(i);\r
362 if (GOTEntryElfRva >= shdr->sh_addr &&\r
363 GOTEntryElfRva < shdr->sh_addr + shdr->sh_size) {\r
364 mGOTShdr = shdr;\r
365 mGOTShindex = i;\r
366 return;\r
367 }\r
368 }\r
369 Error (NULL, 0, 3000, "Invalid", "FindElfGOTSectionFromGOTEntryElfRva: ElfRva 0x%016LX for GOT entry not found in any section.", GOTEntryElfRva);\r
370 exit(EXIT_FAILURE);\r
371}\r
372\r
373//\r
374// Stores locations of GOT entries in COFF image.\r
375// Returns TRUE if GOT entry is new.\r
376// Simple implementation as number of GOT\r
377// entries is expected to be low.\r
378//\r
379\r
380STATIC\r
381BOOLEAN\r
382AccumulateCoffGOTEntries (\r
383 UINT32 GOTCoffEntry\r
384 )\r
385{\r
386 UINT32 i;\r
387 if (mGOTCoffEntries != NULL) {\r
388 for (i = 0; i < mGOTNumCoffEntries; i++) {\r
389 if (mGOTCoffEntries[i] == GOTCoffEntry) {\r
390 return FALSE;\r
391 }\r
392 }\r
393 }\r
394 if (mGOTCoffEntries == NULL) {\r
395 mGOTCoffEntries = (UINT32*)malloc(5 * sizeof *mGOTCoffEntries);\r
396 if (mGOTCoffEntries == NULL) {\r
397 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
398 }\r
399 assert (mGOTCoffEntries != NULL);\r
400 mGOTMaxCoffEntries = 5;\r
401 mGOTNumCoffEntries = 0;\r
402 } else if (mGOTNumCoffEntries == mGOTMaxCoffEntries) {\r
403 mGOTCoffEntries = (UINT32*)realloc(mGOTCoffEntries, 2 * mGOTMaxCoffEntries * sizeof *mGOTCoffEntries);\r
404 if (mGOTCoffEntries == NULL) {\r
405 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
406 }\r
407 assert (mGOTCoffEntries != NULL);\r
408 mGOTMaxCoffEntries += mGOTMaxCoffEntries;\r
409 }\r
410 mGOTCoffEntries[mGOTNumCoffEntries++] = GOTCoffEntry;\r
411 return TRUE;\r
412}\r
413\r
414//\r
415// 32-bit Unsigned integer comparator for qsort.\r
416//\r
417STATIC\r
418int\r
419UINT32Comparator (\r
420 const void* lhs,\r
421 const void* rhs\r
422 )\r
423{\r
424 if (*(const UINT32*)lhs < *(const UINT32*)rhs) {\r
425 return -1;\r
426 }\r
427 return *(const UINT32*)lhs > *(const UINT32*)rhs;\r
428}\r
429\r
430//\r
431// Emit accumulated Coff GOT entry relocations into\r
432// Coff image. This function performs its job\r
433// once and then releases the entry list, so\r
434// it can safely be called multiple times.\r
435//\r
436STATIC\r
437VOID\r
438EmitGOTRelocations (\r
439 VOID\r
440 )\r
441{\r
442 UINT32 i;\r
443 if (mGOTCoffEntries == NULL) {\r
444 return;\r
445 }\r
446 //\r
447 // Emit Coff relocations with Rvas ordered.\r
448 //\r
449 qsort(\r
450 mGOTCoffEntries,\r
451 mGOTNumCoffEntries,\r
452 sizeof *mGOTCoffEntries,\r
453 UINT32Comparator);\r
454 for (i = 0; i < mGOTNumCoffEntries; i++) {\r
455 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", mGOTCoffEntries[i]);\r
456 CoffAddFixup(\r
457 mGOTCoffEntries[i],\r
458 EFI_IMAGE_REL_BASED_DIR64);\r
459 }\r
460 free(mGOTCoffEntries);\r
461 mGOTCoffEntries = NULL;\r
462 mGOTMaxCoffEntries = 0;\r
463 mGOTNumCoffEntries = 0;\r
464}\r
ad1db975
AC
465//\r
466// RISC-V 64 specific Elf WriteSection function.\r
467//\r
468STATIC\r
469VOID\r
470WriteSectionRiscV64 (\r
471 Elf_Rela *Rel,\r
472 UINT8 *Targ,\r
473 Elf_Shdr *SymShdr,\r
474 Elf_Sym *Sym\r
475 )\r
476{\r
477 UINT32 Value;\r
478 UINT32 Value2;\r
abfff7c4 479 Elf64_Addr GOTEntryRva;\r
ad1db975
AC
480\r
481 switch (ELF_R_TYPE(Rel->r_info)) {\r
482 case R_RISCV_NONE:\r
483 break;\r
484\r
485 case R_RISCV_32:\r
abfff7c4 486 *(UINT64 *)Targ = Sym->st_value + Rel->r_addend;\r
ad1db975
AC
487 break;\r
488\r
489 case R_RISCV_64:\r
abfff7c4 490 *(UINT64 *)Targ = Sym->st_value + Rel->r_addend;\r
ad1db975
AC
491 break;\r
492\r
493 case R_RISCV_HI20:\r
494 mRiscVPass1Targ = Targ;\r
495 mRiscVPass1Sym = SymShdr;\r
496 mRiscVPass1SymSecIndex = Sym->st_shndx;\r
497 break;\r
498\r
499 case R_RISCV_LO12_I:\r
500 if (mRiscVPass1Sym == SymShdr && mRiscVPass1Targ != NULL && mRiscVPass1SymSecIndex == Sym->st_shndx && mRiscVPass1SymSecIndex != 0) {\r
501 Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20) << 12);\r
502 Value2 = (UINT32)(RV_X(*(UINT32 *)Targ, 20, 12));\r
503 if (Value2 & (RISCV_IMM_REACH/2)) {\r
504 Value2 |= ~(RISCV_IMM_REACH-1);\r
505 }\r
506 Value += Value2;\r
507 Value = Value - (UINT32)SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
508 Value2 = RISCV_CONST_HIGH_PART (Value);\r
509 *(UINT32 *)mRiscVPass1Targ = (RV_X (Value2, 12, 20) << 12) | \\r
510 (RV_X (*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
511 *(UINT32 *)Targ = (RV_X (Value, 0, 12) << 20) | \\r
512 (RV_X (*(UINT32 *)Targ, 0, 20));\r
513 }\r
514 mRiscVPass1Sym = NULL;\r
515 mRiscVPass1Targ = NULL;\r
516 mRiscVPass1SymSecIndex = 0;\r
517 break;\r
518\r
519 case R_RISCV_LO12_S:\r
520 if (mRiscVPass1Sym == SymShdr && mRiscVPass1Targ != NULL && mRiscVPass1SymSecIndex == Sym->st_shndx && mRiscVPass1SymSecIndex != 0) {\r
521 Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20) << 12);\r
522 Value2 = (UINT32)(RV_X(*(UINT32 *)Targ, 7, 5) | (RV_X(*(UINT32 *)Targ, 25, 7) << 5));\r
523 if (Value2 & (RISCV_IMM_REACH/2)) {\r
524 Value2 |= ~(RISCV_IMM_REACH-1);\r
525 }\r
526 Value += Value2;\r
527 Value = Value - (UINT32)SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
528 Value2 = RISCV_CONST_HIGH_PART (Value);\r
529 *(UINT32 *)mRiscVPass1Targ = (RV_X (Value2, 12, 20) << 12) | \\r
530 (RV_X (*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
531 Value2 = *(UINT32 *)Targ & 0x01fff07f;\r
532 Value &= RISCV_IMM_REACH - 1;\r
533 *(UINT32 *)Targ = Value2 | (UINT32)(((RV_X(Value, 0, 5) << 7) | (RV_X(Value, 5, 7) << 25)));\r
534 }\r
535 mRiscVPass1Sym = NULL;\r
536 mRiscVPass1Targ = NULL;\r
537 mRiscVPass1SymSecIndex = 0;\r
538 break;\r
539\r
abfff7c4
S
540 case R_RISCV_GOT_HI20:\r
541 GOTEntryRva = (Sym->st_value - Rel->r_offset);\r
542 mRiscVPass1Offset = RV_X(GOTEntryRva, 0, 12);\r
543 Value = (UINT32)RV_X(GOTEntryRva, 12, 20);\r
544 *(UINT32 *)Targ = (Value << 12) | (RV_X(*(UINT32*)Targ, 0, 12));\r
545\r
546 mRiscVPass1Targ = Targ;\r
547 mRiscVPass1Sym = SymShdr;\r
548 mRiscVPass1SymSecIndex = Sym->st_shndx;\r
549 mRiscVPass1GotFixup = 1;\r
550 break;\r
551\r
ad1db975
AC
552 case R_RISCV_PCREL_HI20:\r
553 mRiscVPass1Targ = Targ;\r
554 mRiscVPass1Sym = SymShdr;\r
555 mRiscVPass1SymSecIndex = Sym->st_shndx;\r
556\r
557 Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20));\r
558 break;\r
559\r
560 case R_RISCV_PCREL_LO12_I:\r
561 if (mRiscVPass1Targ != NULL && mRiscVPass1Sym != NULL && mRiscVPass1SymSecIndex != 0) {\r
562 int i;\r
563 Value2 = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20));\r
abfff7c4
S
564\r
565 if(mRiscVPass1GotFixup) {\r
566 Value = (UINT32)(mRiscVPass1Offset);\r
567 } else {\r
568 Value = (UINT32)(RV_X(*(UINT32 *)Targ, 20, 12));\r
569 if(Value & (RISCV_IMM_REACH/2)) {\r
570 Value |= ~(RISCV_IMM_REACH-1);\r
571 }\r
ad1db975
AC
572 }\r
573 Value = Value - (UINT32)mRiscVPass1Sym->sh_addr + mCoffSectionsOffset[mRiscVPass1SymSecIndex];\r
abfff7c4 574\r
ad1db975
AC
575 if(-2048 > (INT32)Value) {\r
576 i = (((INT32)Value * -1) / 4096);\r
577 Value2 -= i;\r
578 Value += 4096 * i;\r
579 if(-2048 > (INT32)Value) {\r
580 Value2 -= 1;\r
581 Value += 4096;\r
582 }\r
583 }\r
584 else if( 2047 < (INT32)Value) {\r
585 i = (Value / 4096);\r
586 Value2 += i;\r
587 Value -= 4096 * i;\r
588 if(2047 < (INT32)Value) {\r
589 Value2 += 1;\r
590 Value -= 4096;\r
591 }\r
592 }\r
593\r
abfff7c4
S
594 if(mRiscVPass1GotFixup) {\r
595 *(UINT32 *)Targ = (RV_X((UINT32)Value, 0, 12) << 20)\r
596 | (RV_X(*(UINT32*)Targ, 0, 20));\r
597 // Convert LD instruction to ADDI\r
598 //\r
599 // |31 20|19 15|14 12|11 7|6 0|\r
600 // |-----------------------------------------|\r
601 // |imm[11:0] | rs1 | 011 | rd | 0000011 | LD\r
602 // -----------------------------------------\r
603\r
604 // |-----------------------------------------|\r
605 // |imm[11:0] | rs1 | 000 | rd | 0010011 | ADDI\r
606 // -----------------------------------------\r
607\r
608 // To convert, let's first reset bits 12-14 and 0-6 using ~0x707f\r
609 // Then modify the opcode to ADDI (0010011)\r
610 // All other fields will remain same.\r
611\r
612 *(UINT32 *)Targ = ((*(UINT32 *)Targ & ~0x707f) | 0x13);\r
613 } else {\r
614 *(UINT32 *)Targ = (RV_X(Value, 0, 12) << 20) | (RV_X(*(UINT32*)Targ, 0, 20));\r
615 }\r
ad1db975
AC
616 *(UINT32 *)mRiscVPass1Targ = (RV_X(Value2, 0, 20)<<12) | (RV_X(*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
617 }\r
618 mRiscVPass1Sym = NULL;\r
619 mRiscVPass1Targ = NULL;\r
620 mRiscVPass1SymSecIndex = 0;\r
abfff7c4
S
621 mRiscVPass1Offset = 0;\r
622 mRiscVPass1GotFixup = 0;\r
ad1db975
AC
623 break;\r
624\r
625 case R_RISCV_ADD64:\r
626 case R_RISCV_SUB64:\r
627 case R_RISCV_ADD32:\r
628 case R_RISCV_SUB32:\r
629 case R_RISCV_BRANCH:\r
630 case R_RISCV_JAL:\r
631 case R_RISCV_GPREL_I:\r
632 case R_RISCV_GPREL_S:\r
633 case R_RISCV_CALL:\r
abfff7c4 634 case R_RISCV_CALL_PLT:\r
ad1db975
AC
635 case R_RISCV_RVC_BRANCH:\r
636 case R_RISCV_RVC_JUMP:\r
637 case R_RISCV_RELAX:\r
638 case R_RISCV_SUB6:\r
639 case R_RISCV_SET6:\r
640 case R_RISCV_SET8:\r
641 case R_RISCV_SET16:\r
642 case R_RISCV_SET32:\r
643 break;\r
644\r
645 default:\r
646 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_RISCV64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
647 }\r
648}\r
ecbaa856 649\r
f51461c8
LG
650//\r
651// Elf functions interface implementation\r
652//\r
653\r
654STATIC\r
655VOID\r
656ScanSections64 (\r
657 VOID\r
658 )\r
659{\r
660 UINT32 i;\r
661 EFI_IMAGE_DOS_HEADER *DosHdr;\r
662 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
663 UINT32 CoffEntry;\r
664 UINT32 SectionCount;\r
234f9ff9 665 BOOLEAN FoundSection;\r
f51461c8
LG
666\r
667 CoffEntry = 0;\r
668 mCoffOffset = 0;\r
f51461c8
LG
669\r
670 //\r
671 // Coff file start with a DOS header.\r
672 //\r
673 mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;\r
674 mNtHdrOffset = mCoffOffset;\r
675 switch (mEhdr->e_machine) {\r
676 case EM_X86_64:\r
f51461c8 677 case EM_AARCH64:\r
ad1db975 678 case EM_RISCV64:\r
f51461c8
LG
679 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
680 break;\r
681 default:\r
ea3e924a 682 VerboseMsg ("%s unknown e_machine type %hu. Assume X64", mInImageName, mEhdr->e_machine);\r
f51461c8
LG
683 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
684 break;\r
685 }\r
686\r
687 mTableOffset = mCoffOffset;\r
688 mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);\r
689\r
54b1b57a
AB
690 //\r
691 // Set mCoffAlignment to the maximum alignment of the input sections\r
692 // we care about\r
693 //\r
694 for (i = 0; i < mEhdr->e_shnum; i++) {\r
695 Elf_Shdr *shdr = GetShdrByIndex(i);\r
696 if (shdr->sh_addralign <= mCoffAlignment) {\r
697 continue;\r
698 }\r
699 if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) {\r
700 mCoffAlignment = (UINT32)shdr->sh_addralign;\r
701 }\r
702 }\r
703\r
3f021800
YF
704 //\r
705 // Check if mCoffAlignment is larger than MAX_COFF_ALIGNMENT\r
706 //\r
707 if (mCoffAlignment > MAX_COFF_ALIGNMENT) {\r
708 Error (NULL, 0, 3000, "Invalid", "Section alignment is larger than MAX_COFF_ALIGNMENT.");\r
709 assert (FALSE);\r
710 }\r
711\r
712\r
02a5421f
AB
713 //\r
714 // Move the PE/COFF header right before the first section. This will help us\r
715 // save space when converting to TE.\r
716 //\r
717 if (mCoffAlignment > mCoffOffset) {\r
718 mNtHdrOffset += mCoffAlignment - mCoffOffset;\r
719 mTableOffset += mCoffAlignment - mCoffOffset;\r
720 mCoffOffset = mCoffAlignment;\r
721 }\r
722\r
f51461c8
LG
723 //\r
724 // First text sections.\r
725 //\r
726 mCoffOffset = CoffAlign(mCoffOffset);\r
234f9ff9
EB
727 mTextOffset = mCoffOffset;\r
728 FoundSection = FALSE;\r
f51461c8
LG
729 SectionCount = 0;\r
730 for (i = 0; i < mEhdr->e_shnum; i++) {\r
731 Elf_Shdr *shdr = GetShdrByIndex(i);\r
732 if (IsTextShdr(shdr)) {\r
733 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
734 // the alignment field is valid\r
735 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
736 // if the section address is aligned we must align PE/COFF\r
737 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
0c960e86
AB
738 } else {\r
739 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
f51461c8
LG
740 }\r
741 }\r
742\r
743 /* Relocate entry. */\r
744 if ((mEhdr->e_entry >= shdr->sh_addr) &&\r
745 (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {\r
746 CoffEntry = (UINT32) (mCoffOffset + mEhdr->e_entry - shdr->sh_addr);\r
747 }\r
748\r
749 //\r
750 // Set mTextOffset with the offset of the first '.text' section\r
751 //\r
234f9ff9 752 if (!FoundSection) {\r
f51461c8 753 mTextOffset = mCoffOffset;\r
234f9ff9 754 FoundSection = TRUE;\r
f51461c8
LG
755 }\r
756\r
757 mCoffSectionsOffset[i] = mCoffOffset;\r
758 mCoffOffset += (UINT32) shdr->sh_size;\r
759 SectionCount ++;\r
760 }\r
761 }\r
762\r
ddb3fdbe 763 if (!FoundSection && mOutImageType != FW_ACPI_IMAGE) {\r
f51461c8
LG
764 Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");\r
765 assert (FALSE);\r
766 }\r
767\r
4f7d5c67 768 mDebugOffset = DebugRvaAlign(mCoffOffset);\r
0c960e86 769 mCoffOffset = CoffAlign(mCoffOffset);\r
f51461c8
LG
770\r
771 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
fb0b35e0 772 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
773 }\r
774\r
775 //\r
776 // Then data sections.\r
777 //\r
778 mDataOffset = mCoffOffset;\r
234f9ff9 779 FoundSection = FALSE;\r
f51461c8
LG
780 SectionCount = 0;\r
781 for (i = 0; i < mEhdr->e_shnum; i++) {\r
782 Elf_Shdr *shdr = GetShdrByIndex(i);\r
783 if (IsDataShdr(shdr)) {\r
784 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
785 // the alignment field is valid\r
786 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
787 // if the section address is aligned we must align PE/COFF\r
788 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
0c960e86
AB
789 } else {\r
790 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
f51461c8
LG
791 }\r
792 }\r
234f9ff9
EB
793\r
794 //\r
795 // Set mDataOffset with the offset of the first '.data' section\r
796 //\r
797 if (!FoundSection) {\r
798 mDataOffset = mCoffOffset;\r
799 FoundSection = TRUE;\r
800 }\r
f51461c8
LG
801 mCoffSectionsOffset[i] = mCoffOffset;\r
802 mCoffOffset += (UINT32) shdr->sh_size;\r
803 SectionCount ++;\r
804 }\r
805 }\r
0192b71c
AB
806\r
807 //\r
808 // Make room for .debug data in .data (or .text if .data is empty) instead of\r
809 // putting it in a section of its own. This is explicitly allowed by the\r
810 // PE/COFF spec, and prevents bloat in the binary when using large values for\r
811 // section alignment.\r
812 //\r
813 if (SectionCount > 0) {\r
4f7d5c67 814 mDebugOffset = DebugRvaAlign(mCoffOffset);\r
0192b71c
AB
815 }\r
816 mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) +\r
817 sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) +\r
818 strlen(mInImageName) + 1;\r
819\r
f51461c8 820 mCoffOffset = CoffAlign(mCoffOffset);\r
0192b71c
AB
821 if (SectionCount == 0) {\r
822 mDataOffset = mCoffOffset;\r
823 }\r
f51461c8
LG
824\r
825 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
fb0b35e0 826 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
827 }\r
828\r
829 //\r
830 // The HII resource sections.\r
831 //\r
832 mHiiRsrcOffset = mCoffOffset;\r
833 for (i = 0; i < mEhdr->e_shnum; i++) {\r
834 Elf_Shdr *shdr = GetShdrByIndex(i);\r
835 if (IsHiiRsrcShdr(shdr)) {\r
836 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
837 // the alignment field is valid\r
838 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
839 // if the section address is aligned we must align PE/COFF\r
840 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
0c960e86
AB
841 } else {\r
842 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
f51461c8
LG
843 }\r
844 }\r
845 if (shdr->sh_size != 0) {\r
234f9ff9 846 mHiiRsrcOffset = mCoffOffset;\r
f51461c8
LG
847 mCoffSectionsOffset[i] = mCoffOffset;\r
848 mCoffOffset += (UINT32) shdr->sh_size;\r
849 mCoffOffset = CoffAlign(mCoffOffset);\r
850 SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);\r
851 }\r
852 break;\r
853 }\r
854 }\r
855\r
856 mRelocOffset = mCoffOffset;\r
857\r
858 //\r
859 // Allocate base Coff file. Will be expanded later for relocations.\r
860 //\r
861 mCoffFile = (UINT8 *)malloc(mCoffOffset);\r
06b45735
HW
862 if (mCoffFile == NULL) {\r
863 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
864 }\r
865 assert (mCoffFile != NULL);\r
f51461c8
LG
866 memset(mCoffFile, 0, mCoffOffset);\r
867\r
868 //\r
869 // Fill headers.\r
870 //\r
871 DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;\r
872 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;\r
873 DosHdr->e_lfanew = mNtHdrOffset;\r
874\r
875 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);\r
876\r
877 NtHdr->Pe32Plus.Signature = EFI_IMAGE_NT_SIGNATURE;\r
878\r
879 switch (mEhdr->e_machine) {\r
880 case EM_X86_64:\r
881 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
882 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
883 break;\r
f51461c8
LG
884 case EM_AARCH64:\r
885 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_AARCH64;\r
886 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
887 break;\r
ad1db975
AC
888 case EM_RISCV64:\r
889 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_RISCV64;\r
890 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
891 break;\r
892\r
f51461c8
LG
893 default:\r
894 VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
895 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
896 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
897 }\r
898\r
899 NtHdr->Pe32Plus.FileHeader.NumberOfSections = mCoffNbrSections;\r
900 NtHdr->Pe32Plus.FileHeader.TimeDateStamp = (UINT32) time(NULL);\r
901 mImageTimeStamp = NtHdr->Pe32Plus.FileHeader.TimeDateStamp;\r
902 NtHdr->Pe32Plus.FileHeader.PointerToSymbolTable = 0;\r
903 NtHdr->Pe32Plus.FileHeader.NumberOfSymbols = 0;\r
904 NtHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32Plus.OptionalHeader);\r
905 NtHdr->Pe32Plus.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE\r
906 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED\r
907 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED\r
908 | EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE;\r
909\r
910 NtHdr->Pe32Plus.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;\r
911 NtHdr->Pe32Plus.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;\r
912 NtHdr->Pe32Plus.OptionalHeader.SizeOfUninitializedData = 0;\r
913 NtHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint = CoffEntry;\r
914\r
915 NtHdr->Pe32Plus.OptionalHeader.BaseOfCode = mTextOffset;\r
916\r
917 NtHdr->Pe32Plus.OptionalHeader.ImageBase = 0;\r
918 NtHdr->Pe32Plus.OptionalHeader.SectionAlignment = mCoffAlignment;\r
919 NtHdr->Pe32Plus.OptionalHeader.FileAlignment = mCoffAlignment;\r
920 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = 0;\r
921\r
922 NtHdr->Pe32Plus.OptionalHeader.SizeOfHeaders = mTextOffset;\r
923 NtHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
924\r
925 //\r
926 // Section headers.\r
927 //\r
928 if ((mDataOffset - mTextOffset) > 0) {\r
929 CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,\r
930 EFI_IMAGE_SCN_CNT_CODE\r
931 | EFI_IMAGE_SCN_MEM_EXECUTE\r
932 | EFI_IMAGE_SCN_MEM_READ);\r
933 } else {\r
934 // Don't make a section of size 0.\r
935 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
936 }\r
937\r
938 if ((mHiiRsrcOffset - mDataOffset) > 0) {\r
939 CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,\r
940 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
941 | EFI_IMAGE_SCN_MEM_WRITE\r
942 | EFI_IMAGE_SCN_MEM_READ);\r
943 } else {\r
944 // Don't make a section of size 0.\r
945 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
946 }\r
947\r
948 if ((mRelocOffset - mHiiRsrcOffset) > 0) {\r
949 CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,\r
950 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
951 | EFI_IMAGE_SCN_MEM_READ);\r
952\r
953 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;\r
954 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;\r
955 } else {\r
956 // Don't make a section of size 0.\r
957 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
958 }\r
959\r
960}\r
961\r
962STATIC\r
963BOOLEAN\r
964WriteSections64 (\r
965 SECTION_FILTER_TYPES FilterType\r
966 )\r
967{\r
968 UINT32 Idx;\r
969 Elf_Shdr *SecShdr;\r
970 UINT32 SecOffset;\r
971 BOOLEAN (*Filter)(Elf_Shdr *);\r
ecbaa856 972 Elf64_Addr GOTEntryRva;\r
f51461c8
LG
973\r
974 //\r
975 // Initialize filter pointer\r
976 //\r
977 switch (FilterType) {\r
978 case SECTION_TEXT:\r
979 Filter = IsTextShdr;\r
980 break;\r
981 case SECTION_HII:\r
982 Filter = IsHiiRsrcShdr;\r
983 break;\r
984 case SECTION_DATA:\r
985 Filter = IsDataShdr;\r
986 break;\r
987 default:\r
988 return FALSE;\r
989 }\r
990\r
991 //\r
992 // First: copy sections.\r
993 //\r
994 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
995 Elf_Shdr *Shdr = GetShdrByIndex(Idx);\r
996 if ((*Filter)(Shdr)) {\r
997 switch (Shdr->sh_type) {\r
998 case SHT_PROGBITS:\r
999 /* Copy. */\r
d78675d1
YF
1000 if (Shdr->sh_offset + Shdr->sh_size > mFileBufferSize) {\r
1001 return FALSE;\r
1002 }\r
f51461c8
LG
1003 memcpy(mCoffFile + mCoffSectionsOffset[Idx],\r
1004 (UINT8*)mEhdr + Shdr->sh_offset,\r
1005 (size_t) Shdr->sh_size);\r
1006 break;\r
1007\r
1008 case SHT_NOBITS:\r
1009 memset(mCoffFile + mCoffSectionsOffset[Idx], 0, (size_t) Shdr->sh_size);\r
1010 break;\r
1011\r
1012 default:\r
1013 //\r
fb0b35e0 1014 // Ignore for unknown section type.\r
f51461c8 1015 //\r
1794b98f 1016 VerboseMsg ("%s unknown section type %x. We ignore this unknown section type.", mInImageName, (unsigned)Shdr->sh_type);\r
f51461c8
LG
1017 break;\r
1018 }\r
1019 }\r
1020 }\r
1021\r
1022 //\r
1023 // Second: apply relocations.\r
1024 //\r
1025 VerboseMsg ("Applying Relocations...");\r
1026 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
1027 //\r
1028 // Determine if this is a relocation section.\r
1029 //\r
1030 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);\r
1031 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {\r
1032 continue;\r
1033 }\r
1034\r
4962fcfa
AB
1035 //\r
1036 // If this is a ET_DYN (PIE) executable, we will encounter a dynamic SHT_RELA\r
1037 // section that applies to the entire binary, and which will have its section\r
1038 // index set to #0 (which is a NULL section with the SHF_ALLOC bit cleared).\r
1039 //\r
ecbaa856 1040 // In the absence of GOT based relocations,\r
4962fcfa
AB
1041 // this RELA section will contain redundant R_xxx_RELATIVE relocations, one\r
1042 // for every R_xxx_xx64 relocation appearing in the per-section RELA sections.\r
1043 // (i.e., .rela.text and .rela.data)\r
1044 //\r
1045 if (RelShdr->sh_info == 0) {\r
1046 continue;\r
1047 }\r
1048\r
f51461c8
LG
1049 //\r
1050 // Relocation section found. Now extract section information that the relocations\r
1051 // apply to in the ELF data and the new COFF data.\r
1052 //\r
1053 SecShdr = GetShdrByIndex(RelShdr->sh_info);\r
1054 SecOffset = mCoffSectionsOffset[RelShdr->sh_info];\r
1055\r
1056 //\r
1057 // Only process relocations for the current filter type.\r
1058 //\r
1059 if (RelShdr->sh_type == SHT_RELA && (*Filter)(SecShdr)) {\r
1060 UINT64 RelIdx;\r
1061\r
1062 //\r
1063 // Determine the symbol table referenced by the relocation data.\r
1064 //\r
1065 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);\r
1066 UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;\r
1067\r
1068 //\r
1069 // Process all relocation entries for this section.\r
1070 //\r
1071 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINT32) RelShdr->sh_entsize) {\r
1072\r
1073 //\r
1074 // Set pointer to relocation entry\r
1075 //\r
1076 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
1077\r
1078 //\r
1079 // Set pointer to symbol table entry associated with the relocation entry.\r
1080 //\r
1081 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);\r
1082\r
1083 Elf_Shdr *SymShdr;\r
1084 UINT8 *Targ;\r
1085\r
1086 //\r
1087 // Check section header index found in symbol table and get the section\r
1088 // header location.\r
1089 //\r
1090 if (Sym->st_shndx == SHN_UNDEF\r
621bb723
ML
1091 || Sym->st_shndx >= mEhdr->e_shnum) {\r
1092 const UINT8 *SymName = GetSymName(Sym);\r
1093 if (SymName == NULL) {\r
1094 SymName = (const UINT8 *)"<unknown>";\r
1095 }\r
1096\r
ad1db975
AC
1097 //\r
1098 // Skip error on EM_RISCV64 becasue no symble name is built\r
1099 // from RISC-V toolchain.\r
1100 //\r
1101 if (mEhdr->e_machine != EM_RISCV64) {\r
1102 Error (NULL, 0, 3000, "Invalid",\r
1103 "%s: Bad definition for symbol '%s'@%#llx or unsupported symbol type. "\r
1104 "For example, absolute and undefined symbols are not supported.",\r
1105 mInImageName, SymName, Sym->st_value);\r
621bb723 1106\r
ad1db975
AC
1107 exit(EXIT_FAILURE);\r
1108 }\r
c6b872c6 1109 continue;\r
f51461c8
LG
1110 }\r
1111 SymShdr = GetShdrByIndex(Sym->st_shndx);\r
1112\r
1113 //\r
1114 // Convert the relocation data to a pointer into the coff file.\r
1115 //\r
1116 // Note:\r
1117 // r_offset is the virtual address of the storage unit to be relocated.\r
1118 // sh_addr is the virtual address for the base of the section.\r
1119 //\r
1120 // r_offset in a memory address.\r
1121 // Convert it to a pointer in the coff file.\r
1122 //\r
1123 Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);\r
1124\r
1125 //\r
1126 // Determine how to handle each relocation type based on the machine type.\r
1127 //\r
1128 if (mEhdr->e_machine == EM_X86_64) {\r
1129 switch (ELF_R_TYPE(Rel->r_info)) {\r
1130 case R_X86_64_NONE:\r
1131 break;\r
1132 case R_X86_64_64:\r
1133 //\r
1134 // Absolute relocation.\r
1135 //\r
1136 VerboseMsg ("R_X86_64_64");\r
f7496d71
LG
1137 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX",\r
1138 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
f51461c8
LG
1139 *(UINT64 *)Targ);\r
1140 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
1141 VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ);\r
1142 break;\r
1143 case R_X86_64_32:\r
1144 VerboseMsg ("R_X86_64_32");\r
f7496d71
LG
1145 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
1146 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
f51461c8
LG
1147 *(UINT32 *)Targ);\r
1148 *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
1149 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
1150 break;\r
1151 case R_X86_64_32S:\r
1152 VerboseMsg ("R_X86_64_32S");\r
f7496d71
LG
1153 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
1154 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
f51461c8
LG
1155 *(UINT32 *)Targ);\r
1156 *(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
1157 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
1158 break;\r
c9f29755
AB
1159\r
1160 case R_X86_64_PLT32:\r
1161 //\r
1162 // Treat R_X86_64_PLT32 relocations as R_X86_64_PC32: this is\r
1163 // possible since we know all code symbol references resolve to\r
1164 // definitions in the same module (UEFI has no shared libraries),\r
1165 // and so there is never a reason to jump via a PLT entry,\r
1166 // allowing us to resolve the reference using the symbol directly.\r
1167 //\r
1168 VerboseMsg ("Treating R_X86_64_PLT32 as R_X86_64_PC32 ...");\r
1169 /* fall through */\r
f51461c8
LG
1170 case R_X86_64_PC32:\r
1171 //\r
1172 // Relative relocation: Symbol - Ip + Addend\r
1173 //\r
1174 VerboseMsg ("R_X86_64_PC32");\r
f7496d71
LG
1175 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
1176 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
f51461c8
LG
1177 *(UINT32 *)Targ);\r
1178 *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ\r
1179 + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)\r
1180 - (SecOffset - SecShdr->sh_addr));\r
1181 VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ);\r
1182 break;\r
ecbaa856
Z
1183 case R_X86_64_GOTPCREL:\r
1184 case R_X86_64_GOTPCRELX:\r
1185 case R_X86_64_REX_GOTPCRELX:\r
1186 VerboseMsg ("R_X86_64_GOTPCREL family");\r
1187 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
1188 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
1189 *(UINT32 *)Targ);\r
1190 GOTEntryRva = Rel->r_offset - Rel->r_addend + *(INT32 *)Targ;\r
1191 FindElfGOTSectionFromGOTEntryElfRva(GOTEntryRva);\r
1192 *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ\r
1193 + (mCoffSectionsOffset[mGOTShindex] - mGOTShdr->sh_addr)\r
1194 - (SecOffset - SecShdr->sh_addr));\r
1195 VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ);\r
1196 GOTEntryRva += (mCoffSectionsOffset[mGOTShindex] - mGOTShdr->sh_addr); // ELF Rva -> COFF Rva\r
1197 if (AccumulateCoffGOTEntries((UINT32)GOTEntryRva)) {\r
1198 //\r
1199 // Relocate GOT entry if it's the first time we run into it\r
1200 //\r
1201 Targ = mCoffFile + GOTEntryRva;\r
1202 //\r
1203 // Limitation: The following three statements assume memory\r
1204 // at *Targ is valid because the section containing the GOT\r
1205 // has already been copied from the ELF image to the Coff image.\r
1206 // This pre-condition presently holds because the GOT is placed\r
1207 // in section .text, and the ELF text sections are all copied\r
1208 // prior to reaching this point.\r
1209 // If the pre-condition is violated in the future, this fixup\r
1210 // either needs to be deferred after the GOT section is copied\r
1211 // to the Coff image, or the fixup should be performed on the\r
1212 // source Elf image instead of the destination Coff image.\r
1213 //\r
1214 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX",\r
1215 (UINT32)GOTEntryRva,\r
1216 *(UINT64 *)Targ);\r
1217 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
1218 VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ);\r
1219 }\r
1220 break;\r
f51461c8
LG
1221 default:\r
1222 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
1223 }\r
1224 } else if (mEhdr->e_machine == EM_AARCH64) {\r
1225\r
f51461c8 1226 switch (ELF_R_TYPE(Rel->r_info)) {\r
d2687f23
AB
1227 INT64 Offset;\r
1228\r
1229 case R_AARCH64_LD64_GOT_LO12_NC:\r
1230 //\r
1231 // Convert into an ADD instruction - see R_AARCH64_ADR_GOT_PAGE below.\r
1232 //\r
1233 *(UINT32 *)Targ &= 0x3ff;\r
1234 *(UINT32 *)Targ |= 0x91000000 | ((Sym->st_value & 0xfff) << 10);\r
1235 break;\r
1236\r
1237 case R_AARCH64_ADR_GOT_PAGE:\r
1238 //\r
1239 // This relocation points to the GOT entry that contains the absolute\r
1240 // address of the symbol we are referring to. Since EDK2 only uses\r
1241 // fully linked binaries, we can avoid the indirection, and simply\r
1242 // refer to the symbol directly. This implies having to patch the\r
1243 // subsequent LDR instruction (covered by a R_AARCH64_LD64_GOT_LO12_NC\r
1244 // relocation) into an ADD instruction - this is handled above.\r
1245 //\r
1246 Offset = (Sym->st_value - (Rel->r_offset & ~0xfff)) >> 12;\r
1247\r
1248 *(UINT32 *)Targ &= 0x9000001f;\r
1249 *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | ((Offset & 0x3) << 29);\r
1250\r
1251 /* fall through */\r
f51461c8 1252\r
24d610e6 1253 case R_AARCH64_ADR_PREL_PG_HI21:\r
f55c76b3
AB
1254 //\r
1255 // In order to handle Cortex-A53 erratum #843419, the LD linker may\r
1256 // convert ADRP instructions into ADR instructions, but without\r
1257 // updating the static relocation type, and so we may end up here\r
1258 // while the instruction in question is actually ADR. So let's\r
1259 // just disregard it: the section offset check we apply below to\r
1260 // ADR instructions will trigger for its R_AARCH64_xxx_ABS_LO12_NC\r
1261 // companion instruction as well, so it is safe to omit it here.\r
1262 //\r
1263 if ((*(UINT32 *)Targ & BIT31) == 0) {\r
1264 break;\r
1265 }\r
1266\r
24d610e6
AB
1267 //\r
1268 // AArch64 PG_H21 relocations are typically paired with ABS_LO12\r
1269 // relocations, where a PC-relative reference with +/- 4 GB range is\r
1270 // split into a relative high part and an absolute low part. Since\r
1271 // the absolute low part represents the offset into a 4 KB page, we\r
026a82ab
AB
1272 // either have to convert the ADRP into an ADR instruction, or we\r
1273 // need to use a section alignment of at least 4 KB, so that the\r
1274 // binary appears at a correct offset at runtime. In any case, we\r
24d610e6
AB
1275 // have to make sure that the 4 KB relative offsets of both the\r
1276 // section containing the reference as well as the section to which\r
1277 // it refers have not been changed during PE/COFF conversion (i.e.,\r
1278 // in ScanSections64() above).\r
1279 //\r
026a82ab
AB
1280 if (mCoffAlignment < 0x1000) {\r
1281 //\r
1282 // Attempt to convert the ADRP into an ADR instruction.\r
1283 // This is only possible if the symbol is within +/- 1 MB.\r
1284 //\r
026a82ab
AB
1285\r
1286 // Decode the ADRP instruction\r
1287 Offset = (INT32)((*(UINT32 *)Targ & 0xffffe0) << 8);\r
1288 Offset = (Offset << (6 - 5)) | ((*(UINT32 *)Targ & 0x60000000) >> (29 - 12));\r
1289\r
1290 //\r
1291 // ADRP offset is relative to the previous page boundary,\r
1292 // whereas ADR offset is relative to the instruction itself.\r
1293 // So fix up the offset so it points to the page containing\r
1294 // the symbol.\r
1295 //\r
1296 Offset -= (UINTN)(Targ - mCoffFile) & 0xfff;\r
1297\r
1298 if (Offset < -0x100000 || Offset > 0xfffff) {\r
1299 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s due to its size (> 1 MB), this module requires 4 KB section alignment.",\r
1300 mInImageName);\r
1301 break;\r
1302 }\r
1303\r
1304 // Re-encode the offset as an ADR instruction\r
1305 *(UINT32 *)Targ &= 0x1000001f;\r
1306 *(UINT32 *)Targ |= ((Offset & 0x1ffffc) << (5 - 2)) | ((Offset & 0x3) << 29);\r
1307 }\r
1308 /* fall through */\r
1309\r
1310 case R_AARCH64_ADD_ABS_LO12_NC:\r
1311 case R_AARCH64_LDST8_ABS_LO12_NC:\r
1312 case R_AARCH64_LDST16_ABS_LO12_NC:\r
1313 case R_AARCH64_LDST32_ABS_LO12_NC:\r
1314 case R_AARCH64_LDST64_ABS_LO12_NC:\r
1315 case R_AARCH64_LDST128_ABS_LO12_NC:\r
24d610e6 1316 if (((SecShdr->sh_addr ^ SecOffset) & 0xfff) != 0 ||\r
026a82ab
AB
1317 ((SymShdr->sh_addr ^ mCoffSectionsOffset[Sym->st_shndx]) & 0xfff) != 0) {\r
1318 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
1319 mInImageName);\r
1320 break;\r
87280982 1321 }\r
24d610e6 1322 /* fall through */\r
87280982 1323\r
24d610e6 1324 case R_AARCH64_ADR_PREL_LO21:\r
87280982 1325 case R_AARCH64_CONDBR19:\r
f51461c8 1326 case R_AARCH64_LD_PREL_LO19:\r
f51461c8 1327 case R_AARCH64_CALL26:\r
f51461c8 1328 case R_AARCH64_JUMP26:\r
0b6249f5
AB
1329 case R_AARCH64_PREL64:\r
1330 case R_AARCH64_PREL32:\r
1331 case R_AARCH64_PREL16:\r
24d610e6
AB
1332 //\r
1333 // The GCC toolchains (i.e., binutils) may corrupt section relative\r
1334 // relocations when emitting relocation sections into fully linked\r
1335 // binaries. More specifically, they tend to fail to take into\r
1336 // account the fact that a '.rodata + XXX' relocation needs to have\r
1337 // its addend recalculated once .rodata is merged into the .text\r
1338 // section, and the relocation emitted into the .rela.text section.\r
1339 //\r
1340 // We cannot really recover from this loss of information, so the\r
1341 // only workaround is to prevent having to recalculate any relative\r
1342 // relocations at all, by using a linker script that ensures that\r
1343 // the offset between the Place and the Symbol is the same in both\r
1344 // the ELF and the PE/COFF versions of the binary.\r
1345 //\r
1346 if ((SymShdr->sh_addr - SecShdr->sh_addr) !=\r
1347 (mCoffSectionsOffset[Sym->st_shndx] - SecOffset)) {\r
1348 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 relative relocations require identical ELF and PE/COFF section offsets",\r
1349 mInImageName);\r
f51461c8
LG
1350 }\r
1351 break;\r
1352\r
f51461c8
LG
1353 // Absolute relocations.\r
1354 case R_AARCH64_ABS64:\r
1355 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
1356 break;\r
1357\r
1358 default:\r
1359 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
1360 }\r
ad1db975
AC
1361 } else if (mEhdr->e_machine == EM_RISCV64) {\r
1362 //\r
1363 // Write section for RISC-V 64 architecture.\r
1364 //\r
1365 WriteSectionRiscV64 (Rel, Targ, SymShdr, Sym);\r
f51461c8
LG
1366 } else {\r
1367 Error (NULL, 0, 3000, "Invalid", "Not a supported machine type");\r
1368 }\r
1369 }\r
1370 }\r
1371 }\r
1372\r
1373 return TRUE;\r
1374}\r
1375\r
1376STATIC\r
1377VOID\r
1378WriteRelocations64 (\r
1379 VOID\r
1380 )\r
1381{\r
1382 UINT32 Index;\r
1383 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
1384 EFI_IMAGE_DATA_DIRECTORY *Dir;\r
ad1db975 1385 UINT32 RiscVRelType;\r
f51461c8
LG
1386\r
1387 for (Index = 0; Index < mEhdr->e_shnum; Index++) {\r
1388 Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
1389 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {\r
1390 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);\r
1391 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {\r
1392 UINT64 RelIdx;\r
1393\r
1394 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {\r
1395 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
1396\r
1397 if (mEhdr->e_machine == EM_X86_64) {\r
1398 switch (ELF_R_TYPE(Rel->r_info)) {\r
1399 case R_X86_64_NONE:\r
1400 case R_X86_64_PC32:\r
c9f29755 1401 case R_X86_64_PLT32:\r
ecbaa856
Z
1402 case R_X86_64_GOTPCREL:\r
1403 case R_X86_64_GOTPCRELX:\r
1404 case R_X86_64_REX_GOTPCRELX:\r
f51461c8
LG
1405 break;\r
1406 case R_X86_64_64:\r
f7496d71 1407 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X",\r
f51461c8
LG
1408 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
1409 CoffAddFixup(\r
1410 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1411 + (Rel->r_offset - SecShdr->sh_addr)),\r
1412 EFI_IMAGE_REL_BASED_DIR64);\r
1413 break;\r
c6a14de3
Z
1414 //\r
1415 // R_X86_64_32 and R_X86_64_32S are ELF64 relocations emitted when using\r
1416 // the SYSV X64 ABI small non-position-independent code model.\r
1417 // R_X86_64_32 is used for unsigned 32-bit immediates with a 32-bit operand\r
1418 // size. The value is either not extended, or zero-extended to 64 bits.\r
1419 // R_X86_64_32S is used for either signed 32-bit non-rip-relative displacements\r
1420 // or signed 32-bit immediates with a 64-bit operand size. The value is\r
1421 // sign-extended to 64 bits.\r
1422 // EFI_IMAGE_REL_BASED_HIGHLOW is a PE relocation that uses 32-bit arithmetic\r
1423 // for rebasing an image.\r
1424 // EFI PE binaries declare themselves EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE and\r
1425 // may load above 2GB. If an EFI PE binary with a converted R_X86_64_32S\r
1426 // relocation is loaded above 2GB, the value will get sign-extended to the\r
1427 // negative part of the 64-bit address space. The negative part of the 64-bit\r
1428 // address space is unmapped, so accessing such an address page-faults.\r
1429 // In order to support R_X86_64_32S, it is necessary to unset\r
1430 // EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE, and the EFI PE loader must implement\r
1431 // this flag and abstain from loading such a PE binary above 2GB.\r
1432 // Since this feature is not supported, support for R_X86_64_32S (and hence\r
1433 // the small non-position-independent code model) is disabled.\r
1434 //\r
1435 // case R_X86_64_32S:\r
f51461c8 1436 case R_X86_64_32:\r
f7496d71 1437 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X",\r
f51461c8
LG
1438 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
1439 CoffAddFixup(\r
1440 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1441 + (Rel->r_offset - SecShdr->sh_addr)),\r
1442 EFI_IMAGE_REL_BASED_HIGHLOW);\r
1443 break;\r
1444 default:\r
1445 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
1446 }\r
1447 } else if (mEhdr->e_machine == EM_AARCH64) {\r
24d610e6 1448\r
f51461c8 1449 switch (ELF_R_TYPE(Rel->r_info)) {\r
87280982 1450 case R_AARCH64_ADR_PREL_LO21:\r
87280982 1451 case R_AARCH64_CONDBR19:\r
f51461c8 1452 case R_AARCH64_LD_PREL_LO19:\r
f51461c8 1453 case R_AARCH64_CALL26:\r
f51461c8 1454 case R_AARCH64_JUMP26:\r
0b6249f5
AB
1455 case R_AARCH64_PREL64:\r
1456 case R_AARCH64_PREL32:\r
1457 case R_AARCH64_PREL16:\r
f51461c8 1458 case R_AARCH64_ADR_PREL_PG_HI21:\r
f51461c8 1459 case R_AARCH64_ADD_ABS_LO12_NC:\r
24d610e6
AB
1460 case R_AARCH64_LDST8_ABS_LO12_NC:\r
1461 case R_AARCH64_LDST16_ABS_LO12_NC:\r
1462 case R_AARCH64_LDST32_ABS_LO12_NC:\r
1463 case R_AARCH64_LDST64_ABS_LO12_NC:\r
1464 case R_AARCH64_LDST128_ABS_LO12_NC:\r
d2687f23
AB
1465 case R_AARCH64_ADR_GOT_PAGE:\r
1466 case R_AARCH64_LD64_GOT_LO12_NC:\r
0b6249f5
AB
1467 //\r
1468 // No fixups are required for relative relocations, provided that\r
1469 // the relative offsets between sections have been preserved in\r
1470 // the ELF to PE/COFF conversion. We have already asserted that\r
1471 // this is the case in WriteSections64 ().\r
1472 //\r
f51461c8
LG
1473 break;\r
1474\r
1475 case R_AARCH64_ABS64:\r
1476 CoffAddFixup(\r
1477 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1478 + (Rel->r_offset - SecShdr->sh_addr)),\r
1479 EFI_IMAGE_REL_BASED_DIR64);\r
1480 break;\r
1481\r
1482 case R_AARCH64_ABS32:\r
1483 CoffAddFixup(\r
1484 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1485 + (Rel->r_offset - SecShdr->sh_addr)),\r
1486 EFI_IMAGE_REL_BASED_HIGHLOW);\r
1487 break;\r
1488\r
1489 default:\r
1490 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
1491 }\r
ad1db975
AC
1492 } else if (mEhdr->e_machine == EM_RISCV64) {\r
1493 RiscVRelType = ELF_R_TYPE(Rel->r_info);\r
1494 switch (RiscVRelType) {\r
1495 case R_RISCV_NONE:\r
1496 break;\r
1497\r
1498 case R_RISCV_32:\r
1499 CoffAddFixup(\r
1500 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1501 + (Rel->r_offset - SecShdr->sh_addr)),\r
1502 EFI_IMAGE_REL_BASED_HIGHLOW);\r
1503 break;\r
1504\r
1505 case R_RISCV_64:\r
1506 CoffAddFixup(\r
1507 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1508 + (Rel->r_offset - SecShdr->sh_addr)),\r
1509 EFI_IMAGE_REL_BASED_DIR64);\r
1510 break;\r
1511\r
1512 case R_RISCV_HI20:\r
1513 CoffAddFixup(\r
1514 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1515 + (Rel->r_offset - SecShdr->sh_addr)),\r
1516 EFI_IMAGE_REL_BASED_RISCV_HI20);\r
1517 break;\r
1518\r
1519 case R_RISCV_LO12_I:\r
1520 CoffAddFixup(\r
1521 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1522 + (Rel->r_offset - SecShdr->sh_addr)),\r
1523 EFI_IMAGE_REL_BASED_RISCV_LOW12I);\r
1524 break;\r
1525\r
1526 case R_RISCV_LO12_S:\r
1527 CoffAddFixup(\r
1528 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1529 + (Rel->r_offset - SecShdr->sh_addr)),\r
1530 EFI_IMAGE_REL_BASED_RISCV_LOW12S);\r
1531 break;\r
1532\r
1533 case R_RISCV_ADD64:\r
1534 CoffAddFixup(\r
1535 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1536 + (Rel->r_offset - SecShdr->sh_addr)),\r
1537 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
1538 break;\r
1539\r
1540 case R_RISCV_SUB64:\r
1541 CoffAddFixup(\r
1542 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1543 + (Rel->r_offset - SecShdr->sh_addr)),\r
1544 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
1545 break;\r
1546\r
1547 case R_RISCV_ADD32:\r
1548 CoffAddFixup(\r
1549 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1550 + (Rel->r_offset - SecShdr->sh_addr)),\r
1551 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
1552 break;\r
1553\r
1554 case R_RISCV_SUB32:\r
1555 CoffAddFixup(\r
1556 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1557 + (Rel->r_offset - SecShdr->sh_addr)),\r
1558 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
1559 break;\r
1560\r
1561 case R_RISCV_BRANCH:\r
1562 CoffAddFixup(\r
1563 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1564 + (Rel->r_offset - SecShdr->sh_addr)),\r
1565 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
1566 break;\r
1567\r
1568 case R_RISCV_JAL:\r
1569 CoffAddFixup(\r
1570 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
1571 + (Rel->r_offset - SecShdr->sh_addr)),\r
1572 EFI_IMAGE_REL_BASED_ABSOLUTE);\r
1573 break;\r
1574\r
1575 case R_RISCV_GPREL_I:\r
1576 case R_RISCV_GPREL_S:\r
1577 case R_RISCV_CALL:\r
abfff7c4 1578 case R_RISCV_CALL_PLT:\r
ad1db975
AC
1579 case R_RISCV_RVC_BRANCH:\r
1580 case R_RISCV_RVC_JUMP:\r
1581 case R_RISCV_RELAX:\r
1582 case R_RISCV_SUB6:\r
1583 case R_RISCV_SET6:\r
1584 case R_RISCV_SET8:\r
1585 case R_RISCV_SET16:\r
1586 case R_RISCV_SET32:\r
1587 case R_RISCV_PCREL_HI20:\r
abfff7c4 1588 case R_RISCV_GOT_HI20:\r
ad1db975
AC
1589 case R_RISCV_PCREL_LO12_I:\r
1590 break;\r
1591\r
1592 default:\r
1593 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_RISCV64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
1594 }\r
f51461c8
LG
1595 } else {\r
1596 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
1597 }\r
1598 }\r
ecbaa856
Z
1599 if (mEhdr->e_machine == EM_X86_64 && RelShdr->sh_info == mGOTShindex) {\r
1600 //\r
1601 // Tack relocations for GOT entries after other relocations for\r
1602 // the section the GOT is in, as it's usually found at the end\r
1603 // of the section. This is done in order to maintain Rva order\r
1604 // of Coff relocations.\r
1605 //\r
1606 EmitGOTRelocations();\r
1607 }\r
f51461c8
LG
1608 }\r
1609 }\r
1610 }\r
1611\r
ecbaa856
Z
1612 if (mEhdr->e_machine == EM_X86_64) {\r
1613 //\r
1614 // This is a safety net just in case the GOT is in a section\r
1615 // with no other relocations and the first invocation of\r
1616 // EmitGOTRelocations() above was skipped. This invocation\r
1617 // does not maintain Rva order of Coff relocations.\r
1618 // At present, with a single text section, all references to\r
1619 // the GOT and the GOT itself reside in section .text, so\r
1620 // if there's a GOT at all, the first invocation above\r
1621 // is executed.\r
1622 //\r
1623 EmitGOTRelocations();\r
1624 }\r
f51461c8
LG
1625 //\r
1626 // Pad by adding empty entries.\r
1627 //\r
1628 while (mCoffOffset & (mCoffAlignment - 1)) {\r
1629 CoffAddFixupEntry(0);\r
1630 }\r
1631\r
1632 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
1633 Dir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1634 Dir->Size = mCoffOffset - mRelocOffset;\r
1635 if (Dir->Size == 0) {\r
1636 // If no relocations, null out the directory entry and don't add the .reloc section\r
1637 Dir->VirtualAddress = 0;\r
1638 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
1639 } else {\r
1640 Dir->VirtualAddress = mRelocOffset;\r
1641 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,\r
1642 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
1643 | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
1644 | EFI_IMAGE_SCN_MEM_READ);\r
1645 }\r
1646}\r
1647\r
1648STATIC\r
1649VOID\r
1650WriteDebug64 (\r
1651 VOID\r
1652 )\r
1653{\r
1654 UINT32 Len;\r
f51461c8
LG
1655 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
1656 EFI_IMAGE_DATA_DIRECTORY *DataDir;\r
1657 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;\r
1658 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;\r
1659\r
1660 Len = strlen(mInImageName) + 1;\r
f51461c8 1661\r
0192b71c 1662 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);\r
f51461c8
LG
1663 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
1664 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
0192b71c
AB
1665 Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
1666 Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
f51461c8
LG
1667\r
1668 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);\r
1669 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;\r
1670 strcpy ((char *)(Nb10 + 1), mInImageName);\r
1671\r
1672\r
1673 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
1674 DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
0192b71c 1675 DataDir->VirtualAddress = mDebugOffset;\r
60e85a39 1676 DataDir->Size = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
f51461c8
LG
1677}\r
1678\r
1679STATIC\r
1680VOID\r
1681SetImageSize64 (\r
1682 VOID\r
1683 )\r
1684{\r
1685 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
1686\r
1687 //\r
1688 // Set image size\r
1689 //\r
1690 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
1691 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = mCoffOffset;\r
1692}\r
1693\r
1694STATIC\r
1695VOID\r
1696CleanUp64 (\r
1697 VOID\r
1698 )\r
1699{\r
1700 if (mCoffSectionsOffset != NULL) {\r
1701 free (mCoffSectionsOffset);\r
1702 }\r
1703}\r
1704\r
1705\r