]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/C/GenFw/Elf64Convert.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
... / ...
CommitLineData
1/** @file\r
2Elf64 convert solution\r
3\r
4Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r
5Portions copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
6Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>\r
7\r
8SPDX-License-Identifier: BSD-2-Clause-Patent\r
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
72// Rename ELF32 structures to common names to help when porting to ELF64.\r
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
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
101//\r
102// Coff information\r
103//\r
104STATIC UINT32 mCoffAlignment = 0x20;\r
105\r
106//\r
107// PE section alignment.\r
108//\r
109STATIC const UINT16 mCoffNbrSections = 4;\r
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
124STATIC UINT32 mDebugOffset;\r
125\r
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
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
164 if (!((mEhdr->e_machine == EM_X86_64) || (mEhdr->e_machine == EM_AARCH64) || (mEhdr->e_machine == EM_RISCV64))) {\r
165 Error (NULL, 0, 3000, "Unsupported", "ELF e_machine is not Elf64 machine.");\r
166 return FALSE;\r
167 }\r
168 if (mEhdr->e_version != EV_CURRENT) {\r
169 Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT);\r
170 return FALSE;\r
171 }\r
172\r
173 //\r
174 // Update section header pointers\r
175 //\r
176 VerboseMsg ("Update Header Pointers");\r
177 mShdrBase = (Elf_Shdr *)((UINT8 *)mEhdr + mEhdr->e_shoff);\r
178 mPhdrBase = (Elf_Phdr *)((UINT8 *)mEhdr + mEhdr->e_phoff);\r
179\r
180 //\r
181 // Create COFF Section offset buffer and zero.\r
182 //\r
183 VerboseMsg ("Create COFF Section Offset Buffer");\r
184 mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32));\r
185 if (mCoffSectionsOffset == NULL) {\r
186 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
187 return FALSE;\r
188 }\r
189 memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32));\r
190\r
191 //\r
192 // Fill in function pointers.\r
193 //\r
194 VerboseMsg ("Fill in Function Pointers");\r
195 ElfFunctions->ScanSections = ScanSections64;\r
196 ElfFunctions->WriteSections = WriteSections64;\r
197 ElfFunctions->WriteRelocations = WriteRelocations64;\r
198 ElfFunctions->WriteDebug = WriteDebug64;\r
199 ElfFunctions->SetImageSize = SetImageSize64;\r
200 ElfFunctions->CleanUp = CleanUp64;\r
201\r
202 return TRUE;\r
203}\r
204\r
205\r
206//\r
207// Header by Index functions\r
208//\r
209STATIC\r
210Elf_Shdr*\r
211GetShdrByIndex (\r
212 UINT32 Num\r
213 )\r
214{\r
215 if (Num >= mEhdr->e_shnum) {\r
216 Error (NULL, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num);\r
217 exit(EXIT_FAILURE);\r
218 }\r
219\r
220 return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);\r
221}\r
222\r
223STATIC\r
224UINT32\r
225CoffAlign (\r
226 UINT32 Offset\r
227 )\r
228{\r
229 return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);\r
230}\r
231\r
232STATIC\r
233UINT32\r
234DebugRvaAlign (\r
235 UINT32 Offset\r
236 )\r
237{\r
238 return (Offset + 3) & ~3;\r
239}\r
240\r
241//\r
242// filter functions\r
243//\r
244STATIC\r
245BOOLEAN\r
246IsTextShdr (\r
247 Elf_Shdr *Shdr\r
248 )\r
249{\r
250 return (BOOLEAN) ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC);\r
251}\r
252\r
253STATIC\r
254BOOLEAN\r
255IsHiiRsrcShdr (\r
256 Elf_Shdr *Shdr\r
257 )\r
258{\r
259 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
260\r
261 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);\r
262}\r
263\r
264STATIC\r
265BOOLEAN\r
266IsDataShdr (\r
267 Elf_Shdr *Shdr\r
268 )\r
269{\r
270 if (IsHiiRsrcShdr(Shdr)) {\r
271 return FALSE;\r
272 }\r
273 return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);\r
274}\r
275\r
276STATIC\r
277BOOLEAN\r
278IsStrtabShdr (\r
279 Elf_Shdr *Shdr\r
280 )\r
281{\r
282 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
283\r
284 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_STRTAB_SECTION_NAME) == 0);\r
285}\r
286\r
287STATIC\r
288Elf_Shdr *\r
289FindStrtabShdr (\r
290 VOID\r
291 )\r
292{\r
293 UINT32 i;\r
294 for (i = 0; i < mEhdr->e_shnum; i++) {\r
295 Elf_Shdr *shdr = GetShdrByIndex(i);\r
296 if (IsStrtabShdr(shdr)) {\r
297 return shdr;\r
298 }\r
299 }\r
300 return NULL;\r
301}\r
302\r
303STATIC\r
304const UINT8 *\r
305GetSymName (\r
306 Elf_Sym *Sym\r
307 )\r
308{\r
309 Elf_Shdr *StrtabShdr;\r
310 UINT8 *StrtabContents;\r
311 BOOLEAN foundEnd;\r
312 UINT32 i;\r
313\r
314 if (Sym->st_name == 0) {\r
315 return NULL;\r
316 }\r
317\r
318 StrtabShdr = FindStrtabShdr();\r
319 if (StrtabShdr == NULL) {\r
320 return NULL;\r
321 }\r
322\r
323 assert(Sym->st_name < StrtabShdr->sh_size);\r
324\r
325 StrtabContents = (UINT8*)mEhdr + StrtabShdr->sh_offset;\r
326\r
327 foundEnd = FALSE;\r
328 for (i= Sym->st_name; (i < StrtabShdr->sh_size) && !foundEnd; i++) {\r
329 foundEnd = (BOOLEAN)(StrtabContents[i] == 0);\r
330 }\r
331 assert(foundEnd);\r
332\r
333 return StrtabContents + Sym->st_name;\r
334}\r
335\r
336//\r
337// Find the ELF section hosting the GOT from an ELF Rva\r
338// of a single GOT entry. Normally, GOT is placed in\r
339// ELF .text section, so assume once we find in which\r
340// section the GOT is, all GOT entries are there, and\r
341// just verify this.\r
342//\r
343STATIC\r
344VOID\r
345FindElfGOTSectionFromGOTEntryElfRva (\r
346 Elf64_Addr GOTEntryElfRva\r
347 )\r
348{\r
349 UINT32 i;\r
350 if (mGOTShdr != NULL) {\r
351 if (GOTEntryElfRva >= mGOTShdr->sh_addr &&\r
352 GOTEntryElfRva < mGOTShdr->sh_addr + mGOTShdr->sh_size) {\r
353 return;\r
354 }\r
355 Error (NULL, 0, 3000, "Unsupported", "FindElfGOTSectionFromGOTEntryElfRva: GOT entries found in multiple sections.");\r
356 exit(EXIT_FAILURE);\r
357 }\r
358 for (i = 0; i < mEhdr->e_shnum; i++) {\r
359 Elf_Shdr *shdr = GetShdrByIndex(i);\r
360 if (GOTEntryElfRva >= shdr->sh_addr &&\r
361 GOTEntryElfRva < shdr->sh_addr + shdr->sh_size) {\r
362 mGOTShdr = shdr;\r
363 mGOTShindex = i;\r
364 return;\r
365 }\r
366 }\r
367 Error (NULL, 0, 3000, "Invalid", "FindElfGOTSectionFromGOTEntryElfRva: ElfRva 0x%016LX for GOT entry not found in any section.", GOTEntryElfRva);\r
368 exit(EXIT_FAILURE);\r
369}\r
370\r
371//\r
372// Stores locations of GOT entries in COFF image.\r
373// Returns TRUE if GOT entry is new.\r
374// Simple implementation as number of GOT\r
375// entries is expected to be low.\r
376//\r
377\r
378STATIC\r
379BOOLEAN\r
380AccumulateCoffGOTEntries (\r
381 UINT32 GOTCoffEntry\r
382 )\r
383{\r
384 UINT32 i;\r
385 if (mGOTCoffEntries != NULL) {\r
386 for (i = 0; i < mGOTNumCoffEntries; i++) {\r
387 if (mGOTCoffEntries[i] == GOTCoffEntry) {\r
388 return FALSE;\r
389 }\r
390 }\r
391 }\r
392 if (mGOTCoffEntries == NULL) {\r
393 mGOTCoffEntries = (UINT32*)malloc(5 * sizeof *mGOTCoffEntries);\r
394 if (mGOTCoffEntries == NULL) {\r
395 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
396 }\r
397 assert (mGOTCoffEntries != NULL);\r
398 mGOTMaxCoffEntries = 5;\r
399 mGOTNumCoffEntries = 0;\r
400 } else if (mGOTNumCoffEntries == mGOTMaxCoffEntries) {\r
401 mGOTCoffEntries = (UINT32*)realloc(mGOTCoffEntries, 2 * mGOTMaxCoffEntries * sizeof *mGOTCoffEntries);\r
402 if (mGOTCoffEntries == NULL) {\r
403 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
404 }\r
405 assert (mGOTCoffEntries != NULL);\r
406 mGOTMaxCoffEntries += mGOTMaxCoffEntries;\r
407 }\r
408 mGOTCoffEntries[mGOTNumCoffEntries++] = GOTCoffEntry;\r
409 return TRUE;\r
410}\r
411\r
412//\r
413// 32-bit Unsigned integer comparator for qsort.\r
414//\r
415STATIC\r
416int\r
417UINT32Comparator (\r
418 const void* lhs,\r
419 const void* rhs\r
420 )\r
421{\r
422 if (*(const UINT32*)lhs < *(const UINT32*)rhs) {\r
423 return -1;\r
424 }\r
425 return *(const UINT32*)lhs > *(const UINT32*)rhs;\r
426}\r
427\r
428//\r
429// Emit accumulated Coff GOT entry relocations into\r
430// Coff image. This function performs its job\r
431// once and then releases the entry list, so\r
432// it can safely be called multiple times.\r
433//\r
434STATIC\r
435VOID\r
436EmitGOTRelocations (\r
437 VOID\r
438 )\r
439{\r
440 UINT32 i;\r
441 if (mGOTCoffEntries == NULL) {\r
442 return;\r
443 }\r
444 //\r
445 // Emit Coff relocations with Rvas ordered.\r
446 //\r
447 qsort(\r
448 mGOTCoffEntries,\r
449 mGOTNumCoffEntries,\r
450 sizeof *mGOTCoffEntries,\r
451 UINT32Comparator);\r
452 for (i = 0; i < mGOTNumCoffEntries; i++) {\r
453 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", mGOTCoffEntries[i]);\r
454 CoffAddFixup(\r
455 mGOTCoffEntries[i],\r
456 EFI_IMAGE_REL_BASED_DIR64);\r
457 }\r
458 free(mGOTCoffEntries);\r
459 mGOTCoffEntries = NULL;\r
460 mGOTMaxCoffEntries = 0;\r
461 mGOTNumCoffEntries = 0;\r
462}\r
463//\r
464// RISC-V 64 specific Elf WriteSection function.\r
465//\r
466STATIC\r
467VOID\r
468WriteSectionRiscV64 (\r
469 Elf_Rela *Rel,\r
470 UINT8 *Targ,\r
471 Elf_Shdr *SymShdr,\r
472 Elf_Sym *Sym\r
473 )\r
474{\r
475 UINT32 Value;\r
476 UINT32 Value2;\r
477\r
478 switch (ELF_R_TYPE(Rel->r_info)) {\r
479 case R_RISCV_NONE:\r
480 break;\r
481\r
482 case R_RISCV_32:\r
483 *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
484 break;\r
485\r
486 case R_RISCV_64:\r
487 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
488 break;\r
489\r
490 case R_RISCV_HI20:\r
491 mRiscVPass1Targ = Targ;\r
492 mRiscVPass1Sym = SymShdr;\r
493 mRiscVPass1SymSecIndex = Sym->st_shndx;\r
494 break;\r
495\r
496 case R_RISCV_LO12_I:\r
497 if (mRiscVPass1Sym == SymShdr && mRiscVPass1Targ != NULL && mRiscVPass1SymSecIndex == Sym->st_shndx && mRiscVPass1SymSecIndex != 0) {\r
498 Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20) << 12);\r
499 Value2 = (UINT32)(RV_X(*(UINT32 *)Targ, 20, 12));\r
500 if (Value2 & (RISCV_IMM_REACH/2)) {\r
501 Value2 |= ~(RISCV_IMM_REACH-1);\r
502 }\r
503 Value += Value2;\r
504 Value = Value - (UINT32)SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
505 Value2 = RISCV_CONST_HIGH_PART (Value);\r
506 *(UINT32 *)mRiscVPass1Targ = (RV_X (Value2, 12, 20) << 12) | \\r
507 (RV_X (*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
508 *(UINT32 *)Targ = (RV_X (Value, 0, 12) << 20) | \\r
509 (RV_X (*(UINT32 *)Targ, 0, 20));\r
510 }\r
511 mRiscVPass1Sym = NULL;\r
512 mRiscVPass1Targ = NULL;\r
513 mRiscVPass1SymSecIndex = 0;\r
514 break;\r
515\r
516 case R_RISCV_LO12_S:\r
517 if (mRiscVPass1Sym == SymShdr && mRiscVPass1Targ != NULL && mRiscVPass1SymSecIndex == Sym->st_shndx && mRiscVPass1SymSecIndex != 0) {\r
518 Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20) << 12);\r
519 Value2 = (UINT32)(RV_X(*(UINT32 *)Targ, 7, 5) | (RV_X(*(UINT32 *)Targ, 25, 7) << 5));\r
520 if (Value2 & (RISCV_IMM_REACH/2)) {\r
521 Value2 |= ~(RISCV_IMM_REACH-1);\r
522 }\r
523 Value += Value2;\r
524 Value = Value - (UINT32)SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
525 Value2 = RISCV_CONST_HIGH_PART (Value);\r
526 *(UINT32 *)mRiscVPass1Targ = (RV_X (Value2, 12, 20) << 12) | \\r
527 (RV_X (*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
528 Value2 = *(UINT32 *)Targ & 0x01fff07f;\r
529 Value &= RISCV_IMM_REACH - 1;\r
530 *(UINT32 *)Targ = Value2 | (UINT32)(((RV_X(Value, 0, 5) << 7) | (RV_X(Value, 5, 7) << 25)));\r
531 }\r
532 mRiscVPass1Sym = NULL;\r
533 mRiscVPass1Targ = NULL;\r
534 mRiscVPass1SymSecIndex = 0;\r
535 break;\r
536\r
537 case R_RISCV_PCREL_HI20:\r
538 mRiscVPass1Targ = Targ;\r
539 mRiscVPass1Sym = SymShdr;\r
540 mRiscVPass1SymSecIndex = Sym->st_shndx;\r
541\r
542 Value = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20));\r
543 break;\r
544\r
545 case R_RISCV_PCREL_LO12_I:\r
546 if (mRiscVPass1Targ != NULL && mRiscVPass1Sym != NULL && mRiscVPass1SymSecIndex != 0) {\r
547 int i;\r
548 Value2 = (UINT32)(RV_X(*(UINT32 *)mRiscVPass1Targ, 12, 20));\r
549 Value = (UINT32)(RV_X(*(UINT32 *)Targ, 20, 12));\r
550 if(Value & (RISCV_IMM_REACH/2)) {\r
551 Value |= ~(RISCV_IMM_REACH-1);\r
552 }\r
553 Value = Value - (UINT32)mRiscVPass1Sym->sh_addr + mCoffSectionsOffset[mRiscVPass1SymSecIndex];\r
554 if(-2048 > (INT32)Value) {\r
555 i = (((INT32)Value * -1) / 4096);\r
556 Value2 -= i;\r
557 Value += 4096 * i;\r
558 if(-2048 > (INT32)Value) {\r
559 Value2 -= 1;\r
560 Value += 4096;\r
561 }\r
562 }\r
563 else if( 2047 < (INT32)Value) {\r
564 i = (Value / 4096);\r
565 Value2 += i;\r
566 Value -= 4096 * i;\r
567 if(2047 < (INT32)Value) {\r
568 Value2 += 1;\r
569 Value -= 4096;\r
570 }\r
571 }\r
572\r
573 *(UINT32 *)Targ = (RV_X(Value, 0, 12) << 20) | (RV_X(*(UINT32*)Targ, 0, 20));\r
574 *(UINT32 *)mRiscVPass1Targ = (RV_X(Value2, 0, 20)<<12) | (RV_X(*(UINT32 *)mRiscVPass1Targ, 0, 12));\r
575 }\r
576 mRiscVPass1Sym = NULL;\r
577 mRiscVPass1Targ = NULL;\r
578 mRiscVPass1SymSecIndex = 0;\r
579 break;\r
580\r
581 case R_RISCV_ADD64:\r
582 case R_RISCV_SUB64:\r
583 case R_RISCV_ADD32:\r
584 case R_RISCV_SUB32:\r
585 case R_RISCV_BRANCH:\r
586 case R_RISCV_JAL:\r
587 case R_RISCV_GPREL_I:\r
588 case R_RISCV_GPREL_S:\r
589 case R_RISCV_CALL:\r
590 case R_RISCV_RVC_BRANCH:\r
591 case R_RISCV_RVC_JUMP:\r
592 case R_RISCV_RELAX:\r
593 case R_RISCV_SUB6:\r
594 case R_RISCV_SET6:\r
595 case R_RISCV_SET8:\r
596 case R_RISCV_SET16:\r
597 case R_RISCV_SET32:\r
598 break;\r
599\r
600 default:\r
601 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_RISCV64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
602 }\r
603}\r
604\r
605//\r
606// Elf functions interface implementation\r
607//\r
608\r
609STATIC\r
610VOID\r
611ScanSections64 (\r
612 VOID\r
613 )\r
614{\r
615 UINT32 i;\r
616 EFI_IMAGE_DOS_HEADER *DosHdr;\r
617 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
618 UINT32 CoffEntry;\r
619 UINT32 SectionCount;\r
620 BOOLEAN FoundSection;\r
621\r
622 CoffEntry = 0;\r
623 mCoffOffset = 0;\r
624\r
625 //\r
626 // Coff file start with a DOS header.\r
627 //\r
628 mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;\r
629 mNtHdrOffset = mCoffOffset;\r
630 switch (mEhdr->e_machine) {\r
631 case EM_X86_64:\r
632 case EM_AARCH64:\r
633 case EM_RISCV64:\r
634 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
635 break;\r
636 default:\r
637 VerboseMsg ("%s unknown e_machine type %hu. Assume X64", mInImageName, mEhdr->e_machine);\r
638 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
639 break;\r
640 }\r
641\r
642 mTableOffset = mCoffOffset;\r
643 mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);\r
644\r
645 //\r
646 // Set mCoffAlignment to the maximum alignment of the input sections\r
647 // we care about\r
648 //\r
649 for (i = 0; i < mEhdr->e_shnum; i++) {\r
650 Elf_Shdr *shdr = GetShdrByIndex(i);\r
651 if (shdr->sh_addralign <= mCoffAlignment) {\r
652 continue;\r
653 }\r
654 if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) {\r
655 mCoffAlignment = (UINT32)shdr->sh_addralign;\r
656 }\r
657 }\r
658\r
659 //\r
660 // Check if mCoffAlignment is larger than MAX_COFF_ALIGNMENT\r
661 //\r
662 if (mCoffAlignment > MAX_COFF_ALIGNMENT) {\r
663 Error (NULL, 0, 3000, "Invalid", "Section alignment is larger than MAX_COFF_ALIGNMENT.");\r
664 assert (FALSE);\r
665 }\r
666\r
667\r
668 //\r
669 // Move the PE/COFF header right before the first section. This will help us\r
670 // save space when converting to TE.\r
671 //\r
672 if (mCoffAlignment > mCoffOffset) {\r
673 mNtHdrOffset += mCoffAlignment - mCoffOffset;\r
674 mTableOffset += mCoffAlignment - mCoffOffset;\r
675 mCoffOffset = mCoffAlignment;\r
676 }\r
677\r
678 //\r
679 // First text sections.\r
680 //\r
681 mCoffOffset = CoffAlign(mCoffOffset);\r
682 mTextOffset = mCoffOffset;\r
683 FoundSection = FALSE;\r
684 SectionCount = 0;\r
685 for (i = 0; i < mEhdr->e_shnum; i++) {\r
686 Elf_Shdr *shdr = GetShdrByIndex(i);\r
687 if (IsTextShdr(shdr)) {\r
688 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
689 // the alignment field is valid\r
690 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
691 // if the section address is aligned we must align PE/COFF\r
692 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
693 } else {\r
694 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
695 }\r
696 }\r
697\r
698 /* Relocate entry. */\r
699 if ((mEhdr->e_entry >= shdr->sh_addr) &&\r
700 (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {\r
701 CoffEntry = (UINT32) (mCoffOffset + mEhdr->e_entry - shdr->sh_addr);\r
702 }\r
703\r
704 //\r
705 // Set mTextOffset with the offset of the first '.text' section\r
706 //\r
707 if (!FoundSection) {\r
708 mTextOffset = mCoffOffset;\r
709 FoundSection = TRUE;\r
710 }\r
711\r
712 mCoffSectionsOffset[i] = mCoffOffset;\r
713 mCoffOffset += (UINT32) shdr->sh_size;\r
714 SectionCount ++;\r
715 }\r
716 }\r
717\r
718 if (!FoundSection) {\r
719 Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");\r
720 assert (FALSE);\r
721 }\r
722\r
723 mDebugOffset = DebugRvaAlign(mCoffOffset);\r
724 mCoffOffset = CoffAlign(mCoffOffset);\r
725\r
726 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
727 Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);\r
728 }\r
729\r
730 //\r
731 // Then data sections.\r
732 //\r
733 mDataOffset = mCoffOffset;\r
734 FoundSection = FALSE;\r
735 SectionCount = 0;\r
736 for (i = 0; i < mEhdr->e_shnum; i++) {\r
737 Elf_Shdr *shdr = GetShdrByIndex(i);\r
738 if (IsDataShdr(shdr)) {\r
739 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
740 // the alignment field is valid\r
741 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
742 // if the section address is aligned we must align PE/COFF\r
743 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
744 } else {\r
745 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
746 }\r
747 }\r
748\r
749 //\r
750 // Set mDataOffset with the offset of the first '.data' section\r
751 //\r
752 if (!FoundSection) {\r
753 mDataOffset = mCoffOffset;\r
754 FoundSection = TRUE;\r
755 }\r
756 mCoffSectionsOffset[i] = mCoffOffset;\r
757 mCoffOffset += (UINT32) shdr->sh_size;\r
758 SectionCount ++;\r
759 }\r
760 }\r
761\r
762 //\r
763 // Make room for .debug data in .data (or .text if .data is empty) instead of\r
764 // putting it in a section of its own. This is explicitly allowed by the\r
765 // PE/COFF spec, and prevents bloat in the binary when using large values for\r
766 // section alignment.\r
767 //\r
768 if (SectionCount > 0) {\r
769 mDebugOffset = DebugRvaAlign(mCoffOffset);\r
770 }\r
771 mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) +\r
772 sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) +\r
773 strlen(mInImageName) + 1;\r
774\r
775 mCoffOffset = CoffAlign(mCoffOffset);\r
776 if (SectionCount == 0) {\r
777 mDataOffset = mCoffOffset;\r
778 }\r
779\r
780 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
781 Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
782 }\r
783\r
784 //\r
785 // The HII resource sections.\r
786 //\r
787 mHiiRsrcOffset = mCoffOffset;\r
788 for (i = 0; i < mEhdr->e_shnum; i++) {\r
789 Elf_Shdr *shdr = GetShdrByIndex(i);\r
790 if (IsHiiRsrcShdr(shdr)) {\r
791 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
792 // the alignment field is valid\r
793 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
794 // if the section address is aligned we must align PE/COFF\r
795 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
796 } else {\r
797 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
798 }\r
799 }\r
800 if (shdr->sh_size != 0) {\r
801 mHiiRsrcOffset = mCoffOffset;\r
802 mCoffSectionsOffset[i] = mCoffOffset;\r
803 mCoffOffset += (UINT32) shdr->sh_size;\r
804 mCoffOffset = CoffAlign(mCoffOffset);\r
805 SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);\r
806 }\r
807 break;\r
808 }\r
809 }\r
810\r
811 mRelocOffset = mCoffOffset;\r
812\r
813 //\r
814 // Allocate base Coff file. Will be expanded later for relocations.\r
815 //\r
816 mCoffFile = (UINT8 *)malloc(mCoffOffset);\r
817 if (mCoffFile == NULL) {\r
818 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
819 }\r
820 assert (mCoffFile != NULL);\r
821 memset(mCoffFile, 0, mCoffOffset);\r
822\r
823 //\r
824 // Fill headers.\r
825 //\r
826 DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;\r
827 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;\r
828 DosHdr->e_lfanew = mNtHdrOffset;\r
829\r
830 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);\r
831\r
832 NtHdr->Pe32Plus.Signature = EFI_IMAGE_NT_SIGNATURE;\r
833\r
834 switch (mEhdr->e_machine) {\r
835 case EM_X86_64:\r
836 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
837 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
838 break;\r
839 case EM_AARCH64:\r
840 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_AARCH64;\r
841 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
842 break;\r
843 case EM_RISCV64:\r
844 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_RISCV64;\r
845 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
846 break;\r
847\r
848 default:\r
849 VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
850 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
851 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
852 }\r
853\r
854 NtHdr->Pe32Plus.FileHeader.NumberOfSections = mCoffNbrSections;\r
855 NtHdr->Pe32Plus.FileHeader.TimeDateStamp = (UINT32) time(NULL);\r
856 mImageTimeStamp = NtHdr->Pe32Plus.FileHeader.TimeDateStamp;\r
857 NtHdr->Pe32Plus.FileHeader.PointerToSymbolTable = 0;\r
858 NtHdr->Pe32Plus.FileHeader.NumberOfSymbols = 0;\r
859 NtHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32Plus.OptionalHeader);\r
860 NtHdr->Pe32Plus.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE\r
861 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED\r
862 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED\r
863 | EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE;\r
864\r
865 NtHdr->Pe32Plus.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;\r
866 NtHdr->Pe32Plus.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;\r
867 NtHdr->Pe32Plus.OptionalHeader.SizeOfUninitializedData = 0;\r
868 NtHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint = CoffEntry;\r
869\r
870 NtHdr->Pe32Plus.OptionalHeader.BaseOfCode = mTextOffset;\r
871\r
872 NtHdr->Pe32Plus.OptionalHeader.ImageBase = 0;\r
873 NtHdr->Pe32Plus.OptionalHeader.SectionAlignment = mCoffAlignment;\r
874 NtHdr->Pe32Plus.OptionalHeader.FileAlignment = mCoffAlignment;\r
875 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = 0;\r
876\r
877 NtHdr->Pe32Plus.OptionalHeader.SizeOfHeaders = mTextOffset;\r
878 NtHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
879\r
880 //\r
881 // Section headers.\r
882 //\r
883 if ((mDataOffset - mTextOffset) > 0) {\r
884 CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,\r
885 EFI_IMAGE_SCN_CNT_CODE\r
886 | EFI_IMAGE_SCN_MEM_EXECUTE\r
887 | EFI_IMAGE_SCN_MEM_READ);\r
888 } else {\r
889 // Don't make a section of size 0.\r
890 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
891 }\r
892\r
893 if ((mHiiRsrcOffset - mDataOffset) > 0) {\r
894 CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,\r
895 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
896 | EFI_IMAGE_SCN_MEM_WRITE\r
897 | EFI_IMAGE_SCN_MEM_READ);\r
898 } else {\r
899 // Don't make a section of size 0.\r
900 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
901 }\r
902\r
903 if ((mRelocOffset - mHiiRsrcOffset) > 0) {\r
904 CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,\r
905 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
906 | EFI_IMAGE_SCN_MEM_READ);\r
907\r
908 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;\r
909 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;\r
910 } else {\r
911 // Don't make a section of size 0.\r
912 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
913 }\r
914\r
915}\r
916\r
917STATIC\r
918BOOLEAN\r
919WriteSections64 (\r
920 SECTION_FILTER_TYPES FilterType\r
921 )\r
922{\r
923 UINT32 Idx;\r
924 Elf_Shdr *SecShdr;\r
925 UINT32 SecOffset;\r
926 BOOLEAN (*Filter)(Elf_Shdr *);\r
927 Elf64_Addr GOTEntryRva;\r
928\r
929 //\r
930 // Initialize filter pointer\r
931 //\r
932 switch (FilterType) {\r
933 case SECTION_TEXT:\r
934 Filter = IsTextShdr;\r
935 break;\r
936 case SECTION_HII:\r
937 Filter = IsHiiRsrcShdr;\r
938 break;\r
939 case SECTION_DATA:\r
940 Filter = IsDataShdr;\r
941 break;\r
942 default:\r
943 return FALSE;\r
944 }\r
945\r
946 //\r
947 // First: copy sections.\r
948 //\r
949 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
950 Elf_Shdr *Shdr = GetShdrByIndex(Idx);\r
951 if ((*Filter)(Shdr)) {\r
952 switch (Shdr->sh_type) {\r
953 case SHT_PROGBITS:\r
954 /* Copy. */\r
955 if (Shdr->sh_offset + Shdr->sh_size > mFileBufferSize) {\r
956 return FALSE;\r
957 }\r
958 memcpy(mCoffFile + mCoffSectionsOffset[Idx],\r
959 (UINT8*)mEhdr + Shdr->sh_offset,\r
960 (size_t) Shdr->sh_size);\r
961 break;\r
962\r
963 case SHT_NOBITS:\r
964 memset(mCoffFile + mCoffSectionsOffset[Idx], 0, (size_t) Shdr->sh_size);\r
965 break;\r
966\r
967 default:\r
968 //\r
969 // Ignore for unknown section type.\r
970 //\r
971 VerboseMsg ("%s unknown section type %x. We ignore this unknown section type.", mInImageName, (unsigned)Shdr->sh_type);\r
972 break;\r
973 }\r
974 }\r
975 }\r
976\r
977 //\r
978 // Second: apply relocations.\r
979 //\r
980 VerboseMsg ("Applying Relocations...");\r
981 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
982 //\r
983 // Determine if this is a relocation section.\r
984 //\r
985 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);\r
986 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {\r
987 continue;\r
988 }\r
989\r
990 //\r
991 // If this is a ET_DYN (PIE) executable, we will encounter a dynamic SHT_RELA\r
992 // section that applies to the entire binary, and which will have its section\r
993 // index set to #0 (which is a NULL section with the SHF_ALLOC bit cleared).\r
994 //\r
995 // In the absence of GOT based relocations,\r
996 // this RELA section will contain redundant R_xxx_RELATIVE relocations, one\r
997 // for every R_xxx_xx64 relocation appearing in the per-section RELA sections.\r
998 // (i.e., .rela.text and .rela.data)\r
999 //\r
1000 if (RelShdr->sh_info == 0) {\r
1001 continue;\r
1002 }\r
1003\r
1004 //\r
1005 // Relocation section found. Now extract section information that the relocations\r
1006 // apply to in the ELF data and the new COFF data.\r
1007 //\r
1008 SecShdr = GetShdrByIndex(RelShdr->sh_info);\r
1009 SecOffset = mCoffSectionsOffset[RelShdr->sh_info];\r
1010\r
1011 //\r
1012 // Only process relocations for the current filter type.\r
1013 //\r
1014 if (RelShdr->sh_type == SHT_RELA && (*Filter)(SecShdr)) {\r
1015 UINT64 RelIdx;\r
1016\r
1017 //\r
1018 // Determine the symbol table referenced by the relocation data.\r
1019 //\r
1020 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);\r
1021 UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;\r
1022\r
1023 //\r
1024 // Process all relocation entries for this section.\r
1025 //\r
1026 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINT32) RelShdr->sh_entsize) {\r
1027\r
1028 //\r
1029 // Set pointer to relocation entry\r
1030 //\r
1031 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
1032\r
1033 //\r
1034 // Set pointer to symbol table entry associated with the relocation entry.\r
1035 //\r
1036 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);\r
1037\r
1038 Elf_Shdr *SymShdr;\r
1039 UINT8 *Targ;\r
1040\r
1041 //\r
1042 // Check section header index found in symbol table and get the section\r
1043 // header location.\r
1044 //\r
1045 if (Sym->st_shndx == SHN_UNDEF\r
1046 || Sym->st_shndx >= mEhdr->e_shnum) {\r
1047 const UINT8 *SymName = GetSymName(Sym);\r
1048 if (SymName == NULL) {\r
1049 SymName = (const UINT8 *)"<unknown>";\r
1050 }\r
1051\r
1052 //\r
1053 // Skip error on EM_RISCV64 becasue no symble name is built\r
1054 // from RISC-V toolchain.\r
1055 //\r
1056 if (mEhdr->e_machine != EM_RISCV64) {\r
1057 Error (NULL, 0, 3000, "Invalid",\r
1058 "%s: Bad definition for symbol '%s'@%#llx or unsupported symbol type. "\r
1059 "For example, absolute and undefined symbols are not supported.",\r
1060 mInImageName, SymName, Sym->st_value);\r
1061\r
1062 exit(EXIT_FAILURE);\r
1063 }\r
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
1091 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX",\r
1092 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
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
1099 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
1100 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
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
1107 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
1108 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
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
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
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
1129 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",\r
1130 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),\r
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
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
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
1180 switch (ELF_R_TYPE(Rel->r_info)) {\r
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
1206\r
1207 case R_AARCH64_ADR_PREL_PG_HI21:\r
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
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
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
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
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
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
1270 if (((SecShdr->sh_addr ^ SecOffset) & 0xfff) != 0 ||\r
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
1273 mInImageName);\r
1274 break;\r
1275 }\r
1276 /* fall through */\r
1277\r
1278 case R_AARCH64_ADR_PREL_LO21:\r
1279 case R_AARCH64_CONDBR19:\r
1280 case R_AARCH64_LD_PREL_LO19:\r
1281 case R_AARCH64_CALL26:\r
1282 case R_AARCH64_JUMP26:\r
1283 case R_AARCH64_PREL64:\r
1284 case R_AARCH64_PREL32:\r
1285 case R_AARCH64_PREL16:\r
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
1304 }\r
1305 break;\r
1306\r
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
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
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
1339 UINT32 RiscVRelType;\r
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
1355 case R_X86_64_PLT32:\r
1356 case R_X86_64_GOTPCREL:\r
1357 case R_X86_64_GOTPCRELX:\r
1358 case R_X86_64_REX_GOTPCRELX:\r
1359 break;\r
1360 case R_X86_64_64:\r
1361 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X",\r
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
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
1390 case R_X86_64_32:\r
1391 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X",\r
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
1402\r
1403 switch (ELF_R_TYPE(Rel->r_info)) {\r
1404 case R_AARCH64_ADR_PREL_LO21:\r
1405 case R_AARCH64_CONDBR19:\r
1406 case R_AARCH64_LD_PREL_LO19:\r
1407 case R_AARCH64_CALL26:\r
1408 case R_AARCH64_JUMP26:\r
1409 case R_AARCH64_PREL64:\r
1410 case R_AARCH64_PREL32:\r
1411 case R_AARCH64_PREL16:\r
1412 case R_AARCH64_ADR_PREL_PG_HI21:\r
1413 case R_AARCH64_ADD_ABS_LO12_NC:\r
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
1419 case R_AARCH64_ADR_GOT_PAGE:\r
1420 case R_AARCH64_LD64_GOT_LO12_NC:\r
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
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
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
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
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
1560 }\r
1561 }\r
1562 }\r
1563\r
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
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
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
1613\r
1614 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);\r
1615 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
1616 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
1617 Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
1618 Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
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
1627 DataDir->VirtualAddress = mDebugOffset;\r
1628 DataDir->Size = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
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