]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/C/GenFw/Elf64Convert.c
MdeModulePkg:Add ESC key support in setup browser pop-up message box
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
... / ...
CommitLineData
1/** @file\r
2Elf64 convert solution\r
3\r
4Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
5Portions copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
6\r
7This program and the accompanying materials are licensed and made available\r
8under the terms and conditions of the BSD License which accompanies this\r
9distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "WinNtInclude.h"\r
18\r
19#ifndef __GNUC__\r
20#include <windows.h>\r
21#include <io.h>\r
22#endif\r
23#include <assert.h>\r
24#include <stdio.h>\r
25#include <stdlib.h>\r
26#include <string.h>\r
27#include <time.h>\r
28#include <ctype.h>\r
29\r
30#include <Common/UefiBaseTypes.h>\r
31#include <IndustryStandard/PeImage.h>\r
32\r
33#include "PeCoffLib.h"\r
34#include "EfiUtilityMsgs.h"\r
35\r
36#include "GenFw.h"\r
37#include "ElfConvert.h"\r
38#include "Elf64Convert.h"\r
39\r
40STATIC\r
41VOID\r
42ScanSections64 (\r
43 VOID\r
44 );\r
45\r
46STATIC\r
47BOOLEAN\r
48WriteSections64 (\r
49 SECTION_FILTER_TYPES FilterType\r
50 );\r
51\r
52STATIC\r
53VOID\r
54WriteRelocations64 (\r
55 VOID\r
56 );\r
57\r
58STATIC\r
59VOID\r
60WriteDebug64 (\r
61 VOID\r
62 );\r
63\r
64STATIC\r
65VOID\r
66SetImageSize64 (\r
67 VOID\r
68 );\r
69\r
70STATIC\r
71VOID\r
72CleanUp64 (\r
73 VOID\r
74 );\r
75\r
76//\r
77// Rename ELF32 strucutres to common names to help when porting to ELF64.\r
78//\r
79typedef Elf64_Shdr Elf_Shdr;\r
80typedef Elf64_Ehdr Elf_Ehdr;\r
81typedef Elf64_Rel Elf_Rel;\r
82typedef Elf64_Rela Elf_Rela;\r
83typedef Elf64_Sym Elf_Sym;\r
84typedef Elf64_Phdr Elf_Phdr;\r
85typedef Elf64_Dyn Elf_Dyn;\r
86#define ELFCLASS ELFCLASS64\r
87#define ELF_R_TYPE(r) ELF64_R_TYPE(r)\r
88#define ELF_R_SYM(r) ELF64_R_SYM(r)\r
89\r
90//\r
91// Well known ELF structures.\r
92//\r
93STATIC Elf_Ehdr *mEhdr;\r
94STATIC Elf_Shdr *mShdrBase;\r
95STATIC Elf_Phdr *mPhdrBase;\r
96\r
97//\r
98// Coff information\r
99//\r
100STATIC UINT32 mCoffAlignment = 0x20;\r
101\r
102//\r
103// PE section alignment.\r
104//\r
105STATIC const UINT16 mCoffNbrSections = 5;\r
106\r
107//\r
108// ELF sections to offset in Coff file.\r
109//\r
110STATIC UINT32 *mCoffSectionsOffset = NULL;\r
111\r
112//\r
113// Offsets in COFF file\r
114//\r
115STATIC UINT32 mNtHdrOffset;\r
116STATIC UINT32 mTextOffset;\r
117STATIC UINT32 mDataOffset;\r
118STATIC UINT32 mHiiRsrcOffset;\r
119STATIC UINT32 mRelocOffset;\r
120\r
121//\r
122// Initialization Function\r
123//\r
124BOOLEAN\r
125InitializeElf64 (\r
126 UINT8 *FileBuffer,\r
127 ELF_FUNCTION_TABLE *ElfFunctions\r
128 )\r
129{\r
130 //\r
131 // Initialize data pointer and structures.\r
132 //\r
133 VerboseMsg ("Set EHDR");\r
134 mEhdr = (Elf_Ehdr*) FileBuffer;\r
135\r
136 //\r
137 // Check the ELF64 specific header information.\r
138 //\r
139 VerboseMsg ("Check ELF64 Header Information");\r
140 if (mEhdr->e_ident[EI_CLASS] != ELFCLASS64) {\r
141 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFCLASS64");\r
142 return FALSE;\r
143 }\r
144 if (mEhdr->e_ident[EI_DATA] != ELFDATA2LSB) {\r
145 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB");\r
146 return FALSE;\r
147 }\r
148 if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) {\r
149 Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN");\r
150 return FALSE;\r
151 }\r
152 if (!((mEhdr->e_machine == EM_X86_64) || (mEhdr->e_machine == EM_AARCH64))) {\r
153 Error (NULL, 0, 3000, "Unsupported", "ELF e_machine not EM_X86_64 or EM_AARCH64");\r
154 return FALSE;\r
155 }\r
156 if (mEhdr->e_version != EV_CURRENT) {\r
157 Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT);\r
158 return FALSE;\r
159 }\r
160\r
161 //\r
162 // Update section header pointers\r
163 //\r
164 VerboseMsg ("Update Header Pointers");\r
165 mShdrBase = (Elf_Shdr *)((UINT8 *)mEhdr + mEhdr->e_shoff);\r
166 mPhdrBase = (Elf_Phdr *)((UINT8 *)mEhdr + mEhdr->e_phoff);\r
167\r
168 //\r
169 // Create COFF Section offset buffer and zero.\r
170 //\r
171 VerboseMsg ("Create COFF Section Offset Buffer");\r
172 mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32));\r
173 memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32));\r
174\r
175 //\r
176 // Fill in function pointers.\r
177 //\r
178 VerboseMsg ("Fill in Function Pointers");\r
179 ElfFunctions->ScanSections = ScanSections64;\r
180 ElfFunctions->WriteSections = WriteSections64;\r
181 ElfFunctions->WriteRelocations = WriteRelocations64;\r
182 ElfFunctions->WriteDebug = WriteDebug64;\r
183 ElfFunctions->SetImageSize = SetImageSize64;\r
184 ElfFunctions->CleanUp = CleanUp64;\r
185\r
186 return TRUE;\r
187}\r
188\r
189\r
190//\r
191// Header by Index functions\r
192//\r
193STATIC\r
194Elf_Shdr*\r
195GetShdrByIndex (\r
196 UINT32 Num\r
197 )\r
198{\r
199 if (Num >= mEhdr->e_shnum)\r
200 return NULL;\r
201 return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);\r
202}\r
203\r
204STATIC\r
205UINT32\r
206CoffAlign (\r
207 UINT32 Offset\r
208 )\r
209{\r
210 return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);\r
211}\r
212\r
213//\r
214// filter functions\r
215//\r
216STATIC\r
217BOOLEAN\r
218IsTextShdr (\r
219 Elf_Shdr *Shdr\r
220 )\r
221{\r
222 return (BOOLEAN) ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC);\r
223}\r
224\r
225STATIC\r
226BOOLEAN\r
227IsHiiRsrcShdr (\r
228 Elf_Shdr *Shdr\r
229 )\r
230{\r
231 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
232\r
233 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);\r
234}\r
235\r
236STATIC\r
237BOOLEAN\r
238IsDataShdr (\r
239 Elf_Shdr *Shdr\r
240 )\r
241{\r
242 if (IsHiiRsrcShdr(Shdr)) {\r
243 return FALSE;\r
244 }\r
245 return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);\r
246}\r
247\r
248//\r
249// Elf functions interface implementation\r
250//\r
251\r
252STATIC\r
253VOID\r
254ScanSections64 (\r
255 VOID\r
256 )\r
257{\r
258 UINT32 i;\r
259 EFI_IMAGE_DOS_HEADER *DosHdr;\r
260 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
261 UINT32 CoffEntry;\r
262 UINT32 SectionCount;\r
263 BOOLEAN FoundSection;\r
264\r
265 CoffEntry = 0;\r
266 mCoffOffset = 0;\r
267\r
268 //\r
269 // Coff file start with a DOS header.\r
270 //\r
271 mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;\r
272 mNtHdrOffset = mCoffOffset;\r
273 switch (mEhdr->e_machine) {\r
274 case EM_X86_64:\r
275 case EM_IA_64:\r
276 case EM_AARCH64:\r
277 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
278 break;\r
279 default:\r
280 VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
281 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
282 break;\r
283 }\r
284\r
285 mTableOffset = mCoffOffset;\r
286 mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);\r
287\r
288 //\r
289 // Set mCoffAlignment to the maximum alignment of the input sections\r
290 // we care about\r
291 //\r
292 for (i = 0; i < mEhdr->e_shnum; i++) {\r
293 Elf_Shdr *shdr = GetShdrByIndex(i);\r
294 if (shdr->sh_addralign <= mCoffAlignment) {\r
295 continue;\r
296 }\r
297 if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) {\r
298 mCoffAlignment = (UINT32)shdr->sh_addralign;\r
299 }\r
300 }\r
301\r
302 //\r
303 // First text sections.\r
304 //\r
305 mCoffOffset = CoffAlign(mCoffOffset);\r
306 mTextOffset = mCoffOffset;\r
307 FoundSection = FALSE;\r
308 SectionCount = 0;\r
309 for (i = 0; i < mEhdr->e_shnum; i++) {\r
310 Elf_Shdr *shdr = GetShdrByIndex(i);\r
311 if (IsTextShdr(shdr)) {\r
312 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
313 // the alignment field is valid\r
314 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
315 // if the section address is aligned we must align PE/COFF\r
316 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
317 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
318 // ARM RVCT tools have behavior outside of the ELF specification to try\r
319 // and make images smaller. If sh_addr is not aligned to sh_addralign\r
320 // then the section needs to preserve sh_addr MOD sh_addralign.\r
321 // Normally doing nothing here works great.\r
322 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
323 }\r
324 }\r
325\r
326 /* Relocate entry. */\r
327 if ((mEhdr->e_entry >= shdr->sh_addr) &&\r
328 (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {\r
329 CoffEntry = (UINT32) (mCoffOffset + mEhdr->e_entry - shdr->sh_addr);\r
330 }\r
331\r
332 //\r
333 // Set mTextOffset with the offset of the first '.text' section\r
334 //\r
335 if (!FoundSection) {\r
336 mTextOffset = mCoffOffset;\r
337 FoundSection = TRUE;\r
338 }\r
339\r
340 mCoffSectionsOffset[i] = mCoffOffset;\r
341 mCoffOffset += (UINT32) shdr->sh_size;\r
342 SectionCount ++;\r
343 }\r
344 }\r
345\r
346 if (!FoundSection) {\r
347 Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");\r
348 assert (FALSE);\r
349 }\r
350\r
351 if (mEhdr->e_machine != EM_ARM) {\r
352 mCoffOffset = CoffAlign(mCoffOffset);\r
353 }\r
354\r
355 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
356 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);\r
357 }\r
358\r
359 //\r
360 // Then data sections.\r
361 //\r
362 mDataOffset = mCoffOffset;\r
363 FoundSection = FALSE;\r
364 SectionCount = 0;\r
365 for (i = 0; i < mEhdr->e_shnum; i++) {\r
366 Elf_Shdr *shdr = GetShdrByIndex(i);\r
367 if (IsDataShdr(shdr)) {\r
368 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
369 // the alignment field is valid\r
370 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
371 // if the section address is aligned we must align PE/COFF\r
372 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
373 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
374 // ARM RVCT tools have behavior outside of the ELF specification to try\r
375 // and make images smaller. If sh_addr is not aligned to sh_addralign\r
376 // then the section needs to preserve sh_addr MOD sh_addralign.\r
377 // Normally doing nothing here works great.\r
378 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
379 }\r
380 }\r
381\r
382 //\r
383 // Set mDataOffset with the offset of the first '.data' section\r
384 //\r
385 if (!FoundSection) {\r
386 mDataOffset = mCoffOffset;\r
387 FoundSection = TRUE;\r
388 }\r
389 mCoffSectionsOffset[i] = mCoffOffset;\r
390 mCoffOffset += (UINT32) shdr->sh_size;\r
391 SectionCount ++;\r
392 }\r
393 }\r
394 mCoffOffset = CoffAlign(mCoffOffset);\r
395\r
396 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
397 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
398 }\r
399\r
400 //\r
401 // The HII resource sections.\r
402 //\r
403 mHiiRsrcOffset = mCoffOffset;\r
404 for (i = 0; i < mEhdr->e_shnum; i++) {\r
405 Elf_Shdr *shdr = GetShdrByIndex(i);\r
406 if (IsHiiRsrcShdr(shdr)) {\r
407 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
408 // the alignment field is valid\r
409 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
410 // if the section address is aligned we must align PE/COFF\r
411 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
412 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
413 // ARM RVCT tools have behavior outside of the ELF specification to try\r
414 // and make images smaller. If sh_addr is not aligned to sh_addralign\r
415 // then the section needs to preserve sh_addr MOD sh_addralign.\r
416 // Normally doing nothing here works great.\r
417 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
418 }\r
419 }\r
420 if (shdr->sh_size != 0) {\r
421 mHiiRsrcOffset = mCoffOffset;\r
422 mCoffSectionsOffset[i] = mCoffOffset;\r
423 mCoffOffset += (UINT32) shdr->sh_size;\r
424 mCoffOffset = CoffAlign(mCoffOffset);\r
425 SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);\r
426 }\r
427 break;\r
428 }\r
429 }\r
430\r
431 mRelocOffset = mCoffOffset;\r
432\r
433 //\r
434 // Allocate base Coff file. Will be expanded later for relocations.\r
435 //\r
436 mCoffFile = (UINT8 *)malloc(mCoffOffset);\r
437 memset(mCoffFile, 0, mCoffOffset);\r
438\r
439 //\r
440 // Fill headers.\r
441 //\r
442 DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;\r
443 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;\r
444 DosHdr->e_lfanew = mNtHdrOffset;\r
445\r
446 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);\r
447\r
448 NtHdr->Pe32Plus.Signature = EFI_IMAGE_NT_SIGNATURE;\r
449\r
450 switch (mEhdr->e_machine) {\r
451 case EM_X86_64:\r
452 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
453 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
454 break;\r
455 case EM_IA_64:\r
456 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_IPF;\r
457 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
458 break;\r
459 case EM_AARCH64:\r
460 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_AARCH64;\r
461 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
462 break;\r
463 default:\r
464 VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
465 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
466 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
467 }\r
468\r
469 NtHdr->Pe32Plus.FileHeader.NumberOfSections = mCoffNbrSections;\r
470 NtHdr->Pe32Plus.FileHeader.TimeDateStamp = (UINT32) time(NULL);\r
471 mImageTimeStamp = NtHdr->Pe32Plus.FileHeader.TimeDateStamp;\r
472 NtHdr->Pe32Plus.FileHeader.PointerToSymbolTable = 0;\r
473 NtHdr->Pe32Plus.FileHeader.NumberOfSymbols = 0;\r
474 NtHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32Plus.OptionalHeader);\r
475 NtHdr->Pe32Plus.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE\r
476 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED\r
477 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED\r
478 | EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE;\r
479\r
480 NtHdr->Pe32Plus.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;\r
481 NtHdr->Pe32Plus.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;\r
482 NtHdr->Pe32Plus.OptionalHeader.SizeOfUninitializedData = 0;\r
483 NtHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint = CoffEntry;\r
484\r
485 NtHdr->Pe32Plus.OptionalHeader.BaseOfCode = mTextOffset;\r
486\r
487 NtHdr->Pe32Plus.OptionalHeader.ImageBase = 0;\r
488 NtHdr->Pe32Plus.OptionalHeader.SectionAlignment = mCoffAlignment;\r
489 NtHdr->Pe32Plus.OptionalHeader.FileAlignment = mCoffAlignment;\r
490 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = 0;\r
491\r
492 NtHdr->Pe32Plus.OptionalHeader.SizeOfHeaders = mTextOffset;\r
493 NtHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
494\r
495 //\r
496 // Section headers.\r
497 //\r
498 if ((mDataOffset - mTextOffset) > 0) {\r
499 CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,\r
500 EFI_IMAGE_SCN_CNT_CODE\r
501 | EFI_IMAGE_SCN_MEM_EXECUTE\r
502 | EFI_IMAGE_SCN_MEM_READ);\r
503 } else {\r
504 // Don't make a section of size 0.\r
505 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
506 }\r
507\r
508 if ((mHiiRsrcOffset - mDataOffset) > 0) {\r
509 CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,\r
510 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
511 | EFI_IMAGE_SCN_MEM_WRITE\r
512 | EFI_IMAGE_SCN_MEM_READ);\r
513 } else {\r
514 // Don't make a section of size 0.\r
515 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
516 }\r
517\r
518 if ((mRelocOffset - mHiiRsrcOffset) > 0) {\r
519 CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,\r
520 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
521 | EFI_IMAGE_SCN_MEM_READ);\r
522\r
523 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;\r
524 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;\r
525 } else {\r
526 // Don't make a section of size 0.\r
527 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
528 }\r
529\r
530}\r
531\r
532STATIC\r
533BOOLEAN\r
534WriteSections64 (\r
535 SECTION_FILTER_TYPES FilterType\r
536 )\r
537{\r
538 UINT32 Idx;\r
539 Elf_Shdr *SecShdr;\r
540 UINT32 SecOffset;\r
541 BOOLEAN (*Filter)(Elf_Shdr *);\r
542\r
543 //\r
544 // Initialize filter pointer\r
545 //\r
546 switch (FilterType) {\r
547 case SECTION_TEXT:\r
548 Filter = IsTextShdr;\r
549 break;\r
550 case SECTION_HII:\r
551 Filter = IsHiiRsrcShdr;\r
552 break;\r
553 case SECTION_DATA:\r
554 Filter = IsDataShdr;\r
555 break;\r
556 default:\r
557 return FALSE;\r
558 }\r
559\r
560 //\r
561 // First: copy sections.\r
562 //\r
563 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
564 Elf_Shdr *Shdr = GetShdrByIndex(Idx);\r
565 if ((*Filter)(Shdr)) {\r
566 switch (Shdr->sh_type) {\r
567 case SHT_PROGBITS:\r
568 /* Copy. */\r
569 memcpy(mCoffFile + mCoffSectionsOffset[Idx],\r
570 (UINT8*)mEhdr + Shdr->sh_offset,\r
571 (size_t) Shdr->sh_size);\r
572 break;\r
573\r
574 case SHT_NOBITS:\r
575 memset(mCoffFile + mCoffSectionsOffset[Idx], 0, (size_t) Shdr->sh_size);\r
576 break;\r
577\r
578 default:\r
579 //\r
580 // Ignore for unkown section type.\r
581 //\r
582 VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type);\r
583 break;\r
584 }\r
585 }\r
586 }\r
587\r
588 //\r
589 // Second: apply relocations.\r
590 //\r
591 VerboseMsg ("Applying Relocations...");\r
592 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
593 //\r
594 // Determine if this is a relocation section.\r
595 //\r
596 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);\r
597 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {\r
598 continue;\r
599 }\r
600\r
601 //\r
602 // Relocation section found. Now extract section information that the relocations\r
603 // apply to in the ELF data and the new COFF data.\r
604 //\r
605 SecShdr = GetShdrByIndex(RelShdr->sh_info);\r
606 SecOffset = mCoffSectionsOffset[RelShdr->sh_info];\r
607\r
608 //\r
609 // Only process relocations for the current filter type.\r
610 //\r
611 if (RelShdr->sh_type == SHT_RELA && (*Filter)(SecShdr)) {\r
612 UINT64 RelIdx;\r
613\r
614 //\r
615 // Determine the symbol table referenced by the relocation data.\r
616 //\r
617 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);\r
618 UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;\r
619\r
620 //\r
621 // Process all relocation entries for this section.\r
622 //\r
623 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINT32) RelShdr->sh_entsize) {\r
624\r
625 //\r
626 // Set pointer to relocation entry\r
627 //\r
628 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
629\r
630 //\r
631 // Set pointer to symbol table entry associated with the relocation entry.\r
632 //\r
633 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);\r
634\r
635 Elf_Shdr *SymShdr;\r
636 UINT8 *Targ;\r
637\r
638 //\r
639 // Check section header index found in symbol table and get the section\r
640 // header location.\r
641 //\r
642 if (Sym->st_shndx == SHN_UNDEF\r
643 || Sym->st_shndx == SHN_ABS\r
644 || Sym->st_shndx > mEhdr->e_shnum) {\r
645 Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName);\r
646 }\r
647 SymShdr = GetShdrByIndex(Sym->st_shndx);\r
648\r
649 //\r
650 // Convert the relocation data to a pointer into the coff file.\r
651 //\r
652 // Note:\r
653 // r_offset is the virtual address of the storage unit to be relocated.\r
654 // sh_addr is the virtual address for the base of the section.\r
655 //\r
656 // r_offset in a memory address.\r
657 // Convert it to a pointer in the coff file.\r
658 //\r
659 Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);\r
660\r
661 //\r
662 // Determine how to handle each relocation type based on the machine type.\r
663 //\r
664 if (mEhdr->e_machine == EM_X86_64) {\r
665 switch (ELF_R_TYPE(Rel->r_info)) {\r
666 case R_X86_64_NONE:\r
667 break;\r
668 case R_X86_64_64:\r
669 //\r
670 // Absolute relocation.\r
671 //\r
672 VerboseMsg ("R_X86_64_64");\r
673 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX", \r
674 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
675 *(UINT64 *)Targ);\r
676 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
677 VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ);\r
678 break;\r
679 case R_X86_64_32:\r
680 VerboseMsg ("R_X86_64_32");\r
681 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
682 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
683 *(UINT32 *)Targ);\r
684 *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
685 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
686 break;\r
687 case R_X86_64_32S:\r
688 VerboseMsg ("R_X86_64_32S");\r
689 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
690 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
691 *(UINT32 *)Targ);\r
692 *(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
693 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
694 break;\r
695 case R_X86_64_PC32:\r
696 //\r
697 // Relative relocation: Symbol - Ip + Addend\r
698 //\r
699 VerboseMsg ("R_X86_64_PC32");\r
700 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
701 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
702 *(UINT32 *)Targ);\r
703 *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ\r
704 + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)\r
705 - (SecOffset - SecShdr->sh_addr));\r
706 VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ);\r
707 break;\r
708 default:\r
709 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
710 }\r
711 } else if (mEhdr->e_machine == EM_AARCH64) {\r
712\r
713 // AARCH64 GCC uses RELA relocation, so all relocations have to be fixed up.\r
714 // As opposed to ARM32 using REL.\r
715\r
716 switch (ELF_R_TYPE(Rel->r_info)) {\r
717\r
718 case R_AARCH64_ADR_PREL_LO21:\r
719 if (Rel->r_addend != 0 ) { /* TODO */\r
720 Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_ADR_PREL_LO21 Need to fixup with addend!.");\r
721 }\r
722 break;\r
723\r
724 case R_AARCH64_CONDBR19:\r
725 if (Rel->r_addend != 0 ) { /* TODO */\r
726 Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_CONDBR19 Need to fixup with addend!.");\r
727 }\r
728 break;\r
729\r
730 case R_AARCH64_LD_PREL_LO19:\r
731 if (Rel->r_addend != 0 ) { /* TODO */\r
732 Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_LD_PREL_LO19 Need to fixup with addend!.");\r
733 }\r
734 break;\r
735\r
736 case R_AARCH64_CALL26:\r
737 case R_AARCH64_JUMP26:\r
738 if (Rel->r_addend != 0 ) {\r
739 // Some references to static functions sometime start at the base of .text + addend.\r
740 // It is safe to ignore these relocations because they patch a `BL` instructions that\r
741 // contains an offset from the instruction itself and there is only a single .text section.\r
742 // So we check if the symbol is a "section symbol"\r
743 if (ELF64_ST_TYPE (Sym->st_info) == STT_SECTION) {\r
744 break;\r
745 }\r
746 Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26 Need to fixup with addend!.");\r
747 }\r
748 break;\r
749\r
750 case R_AARCH64_ADR_PREL_PG_HI21:\r
751 // TODO : AArch64 'small' memory model.\r
752 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);\r
753 break;\r
754\r
755 case R_AARCH64_ADD_ABS_LO12_NC:\r
756 // TODO : AArch64 'small' memory model.\r
757 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);\r
758 break;\r
759\r
760 // Absolute relocations.\r
761 case R_AARCH64_ABS64:\r
762 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
763 break;\r
764\r
765 default:\r
766 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
767 }\r
768 } else {\r
769 Error (NULL, 0, 3000, "Invalid", "Not a supported machine type");\r
770 }\r
771 }\r
772 }\r
773 }\r
774\r
775 return TRUE;\r
776}\r
777\r
778STATIC\r
779VOID\r
780WriteRelocations64 (\r
781 VOID\r
782 )\r
783{\r
784 UINT32 Index;\r
785 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
786 EFI_IMAGE_DATA_DIRECTORY *Dir;\r
787\r
788 for (Index = 0; Index < mEhdr->e_shnum; Index++) {\r
789 Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
790 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {\r
791 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);\r
792 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {\r
793 UINT64 RelIdx;\r
794\r
795 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {\r
796 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
797\r
798 if (mEhdr->e_machine == EM_X86_64) {\r
799 switch (ELF_R_TYPE(Rel->r_info)) {\r
800 case R_X86_64_NONE:\r
801 case R_X86_64_PC32:\r
802 break;\r
803 case R_X86_64_64:\r
804 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", \r
805 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
806 CoffAddFixup(\r
807 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
808 + (Rel->r_offset - SecShdr->sh_addr)),\r
809 EFI_IMAGE_REL_BASED_DIR64);\r
810 break;\r
811 case R_X86_64_32S:\r
812 case R_X86_64_32:\r
813 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X", \r
814 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
815 CoffAddFixup(\r
816 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
817 + (Rel->r_offset - SecShdr->sh_addr)),\r
818 EFI_IMAGE_REL_BASED_HIGHLOW);\r
819 break;\r
820 default:\r
821 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
822 }\r
823 } else if (mEhdr->e_machine == EM_AARCH64) {\r
824 // AArch64 GCC uses RELA relocation, so all relocations has to be fixed up. ARM32 uses REL.\r
825 switch (ELF_R_TYPE(Rel->r_info)) {\r
826 case R_AARCH64_ADR_PREL_LO21:\r
827 break;\r
828\r
829 case R_AARCH64_CONDBR19:\r
830 break;\r
831\r
832 case R_AARCH64_LD_PREL_LO19:\r
833 break;\r
834\r
835 case R_AARCH64_CALL26:\r
836 break;\r
837\r
838 case R_AARCH64_JUMP26:\r
839 break;\r
840\r
841 case R_AARCH64_ADR_PREL_PG_HI21:\r
842 // TODO : AArch64 'small' memory model.\r
843 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);\r
844 break;\r
845\r
846 case R_AARCH64_ADD_ABS_LO12_NC:\r
847 // TODO : AArch64 'small' memory model.\r
848 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);\r
849 break;\r
850\r
851 case R_AARCH64_ABS64:\r
852 CoffAddFixup(\r
853 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
854 + (Rel->r_offset - SecShdr->sh_addr)),\r
855 EFI_IMAGE_REL_BASED_DIR64);\r
856 break;\r
857\r
858 case R_AARCH64_ABS32:\r
859 CoffAddFixup(\r
860 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
861 + (Rel->r_offset - SecShdr->sh_addr)),\r
862 EFI_IMAGE_REL_BASED_HIGHLOW);\r
863 break;\r
864\r
865 default:\r
866 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
867 }\r
868 } else {\r
869 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
870 }\r
871 }\r
872 }\r
873 }\r
874 }\r
875\r
876 //\r
877 // Pad by adding empty entries.\r
878 //\r
879 while (mCoffOffset & (mCoffAlignment - 1)) {\r
880 CoffAddFixupEntry(0);\r
881 }\r
882\r
883 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
884 Dir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
885 Dir->Size = mCoffOffset - mRelocOffset;\r
886 if (Dir->Size == 0) {\r
887 // If no relocations, null out the directory entry and don't add the .reloc section\r
888 Dir->VirtualAddress = 0;\r
889 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
890 } else {\r
891 Dir->VirtualAddress = mRelocOffset;\r
892 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,\r
893 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
894 | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
895 | EFI_IMAGE_SCN_MEM_READ);\r
896 }\r
897}\r
898\r
899STATIC\r
900VOID\r
901WriteDebug64 (\r
902 VOID\r
903 )\r
904{\r
905 UINT32 Len;\r
906 UINT32 DebugOffset;\r
907 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
908 EFI_IMAGE_DATA_DIRECTORY *DataDir;\r
909 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;\r
910 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;\r
911\r
912 Len = strlen(mInImageName) + 1;\r
913 DebugOffset = mCoffOffset;\r
914\r
915 mCoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)\r
916 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)\r
917 + Len;\r
918 mCoffOffset = CoffAlign(mCoffOffset);\r
919\r
920 mCoffFile = realloc(mCoffFile, mCoffOffset);\r
921 memset(mCoffFile + DebugOffset, 0, mCoffOffset - DebugOffset);\r
922\r
923 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + DebugOffset);\r
924 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
925 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
926 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
927 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
928\r
929 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);\r
930 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;\r
931 strcpy ((char *)(Nb10 + 1), mInImageName);\r
932\r
933\r
934 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
935 DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
936 DataDir->VirtualAddress = DebugOffset;\r
937 DataDir->Size = mCoffOffset - DebugOffset;\r
938 if (DataDir->Size == 0) {\r
939 // If no debug, null out the directory entry and don't add the .debug section\r
940 DataDir->VirtualAddress = 0;\r
941 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
942 } else {\r
943 DataDir->VirtualAddress = DebugOffset;\r
944 CreateSectionHeader (".debug", DebugOffset, mCoffOffset - DebugOffset,\r
945 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
946 | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
947 | EFI_IMAGE_SCN_MEM_READ);\r
948\r
949 }\r
950}\r
951\r
952STATIC\r
953VOID\r
954SetImageSize64 (\r
955 VOID\r
956 )\r
957{\r
958 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
959\r
960 //\r
961 // Set image size\r
962 //\r
963 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
964 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = mCoffOffset;\r
965}\r
966\r
967STATIC\r
968VOID\r
969CleanUp64 (\r
970 VOID\r
971 )\r
972{\r
973 if (mCoffSectionsOffset != NULL) {\r
974 free (mCoffSectionsOffset);\r
975 }\r
976}\r
977\r
978\r