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