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