BaseTools/GenFw: Exit with error when header lookup fails
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
CommitLineData
f51461c8 1/** @file\r
97fa0ee9 2Elf64 convert solution\r
f51461c8 3\r
97fa0ee9 4Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
87280982 5Portions copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
f51461c8
LG
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
54b1b57a 100STATIC UINT32 mCoffAlignment = 0x20;\r
f51461c8
LG
101\r
102//\r
103// PE section alignment.\r
104//\r
0192b71c 105STATIC const UINT16 mCoffNbrSections = 4;\r
f51461c8
LG
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
0192b71c 120STATIC UINT32 mDebugOffset;\r
f51461c8
LG
121\r
122//\r
123// Initialization Function\r
124//\r
125BOOLEAN\r
126InitializeElf64 (\r
127 UINT8 *FileBuffer,\r
128 ELF_FUNCTION_TABLE *ElfFunctions\r
129 )\r
130{\r
131 //\r
132 // Initialize data pointer and structures.\r
133 //\r
134 VerboseMsg ("Set EHDR");\r
135 mEhdr = (Elf_Ehdr*) FileBuffer;\r
136\r
137 //\r
138 // Check the ELF64 specific header information.\r
139 //\r
140 VerboseMsg ("Check ELF64 Header Information");\r
141 if (mEhdr->e_ident[EI_CLASS] != ELFCLASS64) {\r
142 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFCLASS64");\r
143 return FALSE;\r
144 }\r
145 if (mEhdr->e_ident[EI_DATA] != ELFDATA2LSB) {\r
146 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB");\r
147 return FALSE;\r
148 }\r
149 if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) {\r
150 Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN");\r
151 return FALSE;\r
152 }\r
153 if (!((mEhdr->e_machine == EM_X86_64) || (mEhdr->e_machine == EM_AARCH64))) {\r
154 Error (NULL, 0, 3000, "Unsupported", "ELF e_machine not EM_X86_64 or EM_AARCH64");\r
155 return FALSE;\r
156 }\r
157 if (mEhdr->e_version != EV_CURRENT) {\r
158 Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT);\r
159 return FALSE;\r
160 }\r
161\r
162 //\r
163 // Update section header pointers\r
164 //\r
165 VerboseMsg ("Update Header Pointers");\r
166 mShdrBase = (Elf_Shdr *)((UINT8 *)mEhdr + mEhdr->e_shoff);\r
167 mPhdrBase = (Elf_Phdr *)((UINT8 *)mEhdr + mEhdr->e_phoff);\r
168\r
169 //\r
170 // Create COFF Section offset buffer and zero.\r
171 //\r
172 VerboseMsg ("Create COFF Section Offset Buffer");\r
173 mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32));\r
174 memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32));\r
175\r
176 //\r
177 // Fill in function pointers.\r
178 //\r
179 VerboseMsg ("Fill in Function Pointers");\r
180 ElfFunctions->ScanSections = ScanSections64;\r
181 ElfFunctions->WriteSections = WriteSections64;\r
182 ElfFunctions->WriteRelocations = WriteRelocations64;\r
183 ElfFunctions->WriteDebug = WriteDebug64;\r
184 ElfFunctions->SetImageSize = SetImageSize64;\r
185 ElfFunctions->CleanUp = CleanUp64;\r
186\r
187 return TRUE;\r
188}\r
189\r
190\r
191//\r
192// Header by Index functions\r
193//\r
194STATIC\r
195Elf_Shdr*\r
196GetShdrByIndex (\r
197 UINT32 Num\r
198 )\r
199{\r
17751c5f
ML
200 if (Num >= mEhdr->e_shnum) {\r
201 Error (NULL, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num);\r
202 exit(EXIT_FAILURE);\r
203 }\r
204\r
f51461c8
LG
205 return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);\r
206}\r
207\r
208STATIC\r
209UINT32\r
210CoffAlign (\r
211 UINT32 Offset\r
212 )\r
213{\r
214 return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);\r
215}\r
216\r
4f7d5c67
AB
217STATIC\r
218UINT32\r
219DebugRvaAlign (\r
220 UINT32 Offset\r
221 )\r
222{\r
223 return (Offset + 3) & ~3;\r
224}\r
225\r
f51461c8
LG
226//\r
227// filter functions\r
228//\r
229STATIC\r
230BOOLEAN\r
231IsTextShdr (\r
232 Elf_Shdr *Shdr\r
233 )\r
234{\r
235 return (BOOLEAN) ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC);\r
236}\r
237\r
238STATIC\r
239BOOLEAN\r
240IsHiiRsrcShdr (\r
241 Elf_Shdr *Shdr\r
242 )\r
243{\r
244 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
245\r
246 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);\r
247}\r
248\r
249STATIC\r
250BOOLEAN\r
251IsDataShdr (\r
252 Elf_Shdr *Shdr\r
253 )\r
254{\r
255 if (IsHiiRsrcShdr(Shdr)) {\r
256 return FALSE;\r
257 }\r
258 return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);\r
259}\r
260\r
261//\r
262// Elf functions interface implementation\r
263//\r
264\r
265STATIC\r
266VOID\r
267ScanSections64 (\r
268 VOID\r
269 )\r
270{\r
271 UINT32 i;\r
272 EFI_IMAGE_DOS_HEADER *DosHdr;\r
273 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
274 UINT32 CoffEntry;\r
275 UINT32 SectionCount;\r
234f9ff9 276 BOOLEAN FoundSection;\r
f51461c8
LG
277\r
278 CoffEntry = 0;\r
279 mCoffOffset = 0;\r
f51461c8
LG
280\r
281 //\r
282 // Coff file start with a DOS header.\r
283 //\r
284 mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;\r
285 mNtHdrOffset = mCoffOffset;\r
286 switch (mEhdr->e_machine) {\r
287 case EM_X86_64:\r
288 case EM_IA_64:\r
289 case EM_AARCH64:\r
290 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
291 break;\r
292 default:\r
293 VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
294 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
295 break;\r
296 }\r
297\r
298 mTableOffset = mCoffOffset;\r
299 mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);\r
300\r
54b1b57a
AB
301 //\r
302 // Set mCoffAlignment to the maximum alignment of the input sections\r
303 // we care about\r
304 //\r
305 for (i = 0; i < mEhdr->e_shnum; i++) {\r
306 Elf_Shdr *shdr = GetShdrByIndex(i);\r
307 if (shdr->sh_addralign <= mCoffAlignment) {\r
308 continue;\r
309 }\r
310 if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) {\r
311 mCoffAlignment = (UINT32)shdr->sh_addralign;\r
312 }\r
313 }\r
314\r
02a5421f
AB
315 //\r
316 // Move the PE/COFF header right before the first section. This will help us\r
317 // save space when converting to TE.\r
318 //\r
319 if (mCoffAlignment > mCoffOffset) {\r
320 mNtHdrOffset += mCoffAlignment - mCoffOffset;\r
321 mTableOffset += mCoffAlignment - mCoffOffset;\r
322 mCoffOffset = mCoffAlignment;\r
323 }\r
324\r
f51461c8
LG
325 //\r
326 // First text sections.\r
327 //\r
328 mCoffOffset = CoffAlign(mCoffOffset);\r
234f9ff9
EB
329 mTextOffset = mCoffOffset;\r
330 FoundSection = FALSE;\r
f51461c8
LG
331 SectionCount = 0;\r
332 for (i = 0; i < mEhdr->e_shnum; i++) {\r
333 Elf_Shdr *shdr = GetShdrByIndex(i);\r
334 if (IsTextShdr(shdr)) {\r
335 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
336 // the alignment field is valid\r
337 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
338 // if the section address is aligned we must align PE/COFF\r
339 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
0c960e86
AB
340 } else {\r
341 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
f51461c8
LG
342 }\r
343 }\r
344\r
345 /* Relocate entry. */\r
346 if ((mEhdr->e_entry >= shdr->sh_addr) &&\r
347 (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {\r
348 CoffEntry = (UINT32) (mCoffOffset + mEhdr->e_entry - shdr->sh_addr);\r
349 }\r
350\r
351 //\r
352 // Set mTextOffset with the offset of the first '.text' section\r
353 //\r
234f9ff9 354 if (!FoundSection) {\r
f51461c8 355 mTextOffset = mCoffOffset;\r
234f9ff9 356 FoundSection = TRUE;\r
f51461c8
LG
357 }\r
358\r
359 mCoffSectionsOffset[i] = mCoffOffset;\r
360 mCoffOffset += (UINT32) shdr->sh_size;\r
361 SectionCount ++;\r
362 }\r
363 }\r
364\r
234f9ff9 365 if (!FoundSection) {\r
f51461c8
LG
366 Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");\r
367 assert (FALSE);\r
368 }\r
369\r
4f7d5c67 370 mDebugOffset = DebugRvaAlign(mCoffOffset);\r
0c960e86 371 mCoffOffset = CoffAlign(mCoffOffset);\r
f51461c8
LG
372\r
373 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
374 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);\r
375 }\r
376\r
377 //\r
378 // Then data sections.\r
379 //\r
380 mDataOffset = mCoffOffset;\r
234f9ff9 381 FoundSection = FALSE;\r
f51461c8
LG
382 SectionCount = 0;\r
383 for (i = 0; i < mEhdr->e_shnum; i++) {\r
384 Elf_Shdr *shdr = GetShdrByIndex(i);\r
385 if (IsDataShdr(shdr)) {\r
386 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
387 // the alignment field is valid\r
388 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
389 // if the section address is aligned we must align PE/COFF\r
390 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
0c960e86
AB
391 } else {\r
392 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
f51461c8
LG
393 }\r
394 }\r
234f9ff9
EB
395\r
396 //\r
397 // Set mDataOffset with the offset of the first '.data' section\r
398 //\r
399 if (!FoundSection) {\r
400 mDataOffset = mCoffOffset;\r
401 FoundSection = TRUE;\r
402 }\r
f51461c8
LG
403 mCoffSectionsOffset[i] = mCoffOffset;\r
404 mCoffOffset += (UINT32) shdr->sh_size;\r
405 SectionCount ++;\r
406 }\r
407 }\r
0192b71c
AB
408\r
409 //\r
410 // Make room for .debug data in .data (or .text if .data is empty) instead of\r
411 // putting it in a section of its own. This is explicitly allowed by the\r
412 // PE/COFF spec, and prevents bloat in the binary when using large values for\r
413 // section alignment.\r
414 //\r
415 if (SectionCount > 0) {\r
4f7d5c67 416 mDebugOffset = DebugRvaAlign(mCoffOffset);\r
0192b71c
AB
417 }\r
418 mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) +\r
419 sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) +\r
420 strlen(mInImageName) + 1;\r
421\r
f51461c8 422 mCoffOffset = CoffAlign(mCoffOffset);\r
0192b71c
AB
423 if (SectionCount == 0) {\r
424 mDataOffset = mCoffOffset;\r
425 }\r
f51461c8
LG
426\r
427 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
428 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
429 }\r
430\r
431 //\r
432 // The HII resource sections.\r
433 //\r
434 mHiiRsrcOffset = mCoffOffset;\r
435 for (i = 0; i < mEhdr->e_shnum; i++) {\r
436 Elf_Shdr *shdr = GetShdrByIndex(i);\r
437 if (IsHiiRsrcShdr(shdr)) {\r
438 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
439 // the alignment field is valid\r
440 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
441 // if the section address is aligned we must align PE/COFF\r
442 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
0c960e86
AB
443 } else {\r
444 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
f51461c8
LG
445 }\r
446 }\r
447 if (shdr->sh_size != 0) {\r
234f9ff9 448 mHiiRsrcOffset = mCoffOffset;\r
f51461c8
LG
449 mCoffSectionsOffset[i] = mCoffOffset;\r
450 mCoffOffset += (UINT32) shdr->sh_size;\r
451 mCoffOffset = CoffAlign(mCoffOffset);\r
452 SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);\r
453 }\r
454 break;\r
455 }\r
456 }\r
457\r
458 mRelocOffset = mCoffOffset;\r
459\r
460 //\r
461 // Allocate base Coff file. Will be expanded later for relocations.\r
462 //\r
463 mCoffFile = (UINT8 *)malloc(mCoffOffset);\r
464 memset(mCoffFile, 0, mCoffOffset);\r
465\r
466 //\r
467 // Fill headers.\r
468 //\r
469 DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;\r
470 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;\r
471 DosHdr->e_lfanew = mNtHdrOffset;\r
472\r
473 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);\r
474\r
475 NtHdr->Pe32Plus.Signature = EFI_IMAGE_NT_SIGNATURE;\r
476\r
477 switch (mEhdr->e_machine) {\r
478 case EM_X86_64:\r
479 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
480 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
481 break;\r
482 case EM_IA_64:\r
483 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_IPF;\r
484 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
485 break;\r
486 case EM_AARCH64:\r
487 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_AARCH64;\r
488 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
489 break;\r
490 default:\r
491 VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
492 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
493 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
494 }\r
495\r
496 NtHdr->Pe32Plus.FileHeader.NumberOfSections = mCoffNbrSections;\r
497 NtHdr->Pe32Plus.FileHeader.TimeDateStamp = (UINT32) time(NULL);\r
498 mImageTimeStamp = NtHdr->Pe32Plus.FileHeader.TimeDateStamp;\r
499 NtHdr->Pe32Plus.FileHeader.PointerToSymbolTable = 0;\r
500 NtHdr->Pe32Plus.FileHeader.NumberOfSymbols = 0;\r
501 NtHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32Plus.OptionalHeader);\r
502 NtHdr->Pe32Plus.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE\r
503 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED\r
504 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED\r
505 | EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE;\r
506\r
507 NtHdr->Pe32Plus.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;\r
508 NtHdr->Pe32Plus.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;\r
509 NtHdr->Pe32Plus.OptionalHeader.SizeOfUninitializedData = 0;\r
510 NtHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint = CoffEntry;\r
511\r
512 NtHdr->Pe32Plus.OptionalHeader.BaseOfCode = mTextOffset;\r
513\r
514 NtHdr->Pe32Plus.OptionalHeader.ImageBase = 0;\r
515 NtHdr->Pe32Plus.OptionalHeader.SectionAlignment = mCoffAlignment;\r
516 NtHdr->Pe32Plus.OptionalHeader.FileAlignment = mCoffAlignment;\r
517 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = 0;\r
518\r
519 NtHdr->Pe32Plus.OptionalHeader.SizeOfHeaders = mTextOffset;\r
520 NtHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
521\r
522 //\r
523 // Section headers.\r
524 //\r
525 if ((mDataOffset - mTextOffset) > 0) {\r
526 CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,\r
527 EFI_IMAGE_SCN_CNT_CODE\r
528 | EFI_IMAGE_SCN_MEM_EXECUTE\r
529 | EFI_IMAGE_SCN_MEM_READ);\r
530 } else {\r
531 // Don't make a section of size 0.\r
532 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
533 }\r
534\r
535 if ((mHiiRsrcOffset - mDataOffset) > 0) {\r
536 CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,\r
537 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
538 | EFI_IMAGE_SCN_MEM_WRITE\r
539 | EFI_IMAGE_SCN_MEM_READ);\r
540 } else {\r
541 // Don't make a section of size 0.\r
542 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
543 }\r
544\r
545 if ((mRelocOffset - mHiiRsrcOffset) > 0) {\r
546 CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,\r
547 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
548 | EFI_IMAGE_SCN_MEM_READ);\r
549\r
550 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;\r
551 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;\r
552 } else {\r
553 // Don't make a section of size 0.\r
554 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
555 }\r
556\r
557}\r
558\r
559STATIC\r
560BOOLEAN\r
561WriteSections64 (\r
562 SECTION_FILTER_TYPES FilterType\r
563 )\r
564{\r
565 UINT32 Idx;\r
566 Elf_Shdr *SecShdr;\r
567 UINT32 SecOffset;\r
568 BOOLEAN (*Filter)(Elf_Shdr *);\r
569\r
570 //\r
571 // Initialize filter pointer\r
572 //\r
573 switch (FilterType) {\r
574 case SECTION_TEXT:\r
575 Filter = IsTextShdr;\r
576 break;\r
577 case SECTION_HII:\r
578 Filter = IsHiiRsrcShdr;\r
579 break;\r
580 case SECTION_DATA:\r
581 Filter = IsDataShdr;\r
582 break;\r
583 default:\r
584 return FALSE;\r
585 }\r
586\r
587 //\r
588 // First: copy sections.\r
589 //\r
590 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
591 Elf_Shdr *Shdr = GetShdrByIndex(Idx);\r
592 if ((*Filter)(Shdr)) {\r
593 switch (Shdr->sh_type) {\r
594 case SHT_PROGBITS:\r
595 /* Copy. */\r
596 memcpy(mCoffFile + mCoffSectionsOffset[Idx],\r
597 (UINT8*)mEhdr + Shdr->sh_offset,\r
598 (size_t) Shdr->sh_size);\r
599 break;\r
600\r
601 case SHT_NOBITS:\r
602 memset(mCoffFile + mCoffSectionsOffset[Idx], 0, (size_t) Shdr->sh_size);\r
603 break;\r
604\r
605 default:\r
606 //\r
607 // Ignore for unkown section type.\r
608 //\r
609 VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type);\r
610 break;\r
611 }\r
612 }\r
613 }\r
614\r
615 //\r
616 // Second: apply relocations.\r
617 //\r
618 VerboseMsg ("Applying Relocations...");\r
619 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
620 //\r
621 // Determine if this is a relocation section.\r
622 //\r
623 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);\r
624 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {\r
625 continue;\r
626 }\r
627\r
628 //\r
629 // Relocation section found. Now extract section information that the relocations\r
630 // apply to in the ELF data and the new COFF data.\r
631 //\r
632 SecShdr = GetShdrByIndex(RelShdr->sh_info);\r
633 SecOffset = mCoffSectionsOffset[RelShdr->sh_info];\r
634\r
635 //\r
636 // Only process relocations for the current filter type.\r
637 //\r
638 if (RelShdr->sh_type == SHT_RELA && (*Filter)(SecShdr)) {\r
639 UINT64 RelIdx;\r
640\r
641 //\r
642 // Determine the symbol table referenced by the relocation data.\r
643 //\r
644 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);\r
645 UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;\r
646\r
647 //\r
648 // Process all relocation entries for this section.\r
649 //\r
650 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINT32) RelShdr->sh_entsize) {\r
651\r
652 //\r
653 // Set pointer to relocation entry\r
654 //\r
655 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
656\r
657 //\r
658 // Set pointer to symbol table entry associated with the relocation entry.\r
659 //\r
660 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);\r
661\r
662 Elf_Shdr *SymShdr;\r
663 UINT8 *Targ;\r
664\r
665 //\r
666 // Check section header index found in symbol table and get the section\r
667 // header location.\r
668 //\r
669 if (Sym->st_shndx == SHN_UNDEF\r
670 || Sym->st_shndx == SHN_ABS\r
671 || Sym->st_shndx > mEhdr->e_shnum) {\r
672 Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName);\r
673 }\r
674 SymShdr = GetShdrByIndex(Sym->st_shndx);\r
675\r
676 //\r
677 // Convert the relocation data to a pointer into the coff file.\r
678 //\r
679 // Note:\r
680 // r_offset is the virtual address of the storage unit to be relocated.\r
681 // sh_addr is the virtual address for the base of the section.\r
682 //\r
683 // r_offset in a memory address.\r
684 // Convert it to a pointer in the coff file.\r
685 //\r
686 Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);\r
687\r
688 //\r
689 // Determine how to handle each relocation type based on the machine type.\r
690 //\r
691 if (mEhdr->e_machine == EM_X86_64) {\r
692 switch (ELF_R_TYPE(Rel->r_info)) {\r
693 case R_X86_64_NONE:\r
694 break;\r
695 case R_X86_64_64:\r
696 //\r
697 // Absolute relocation.\r
698 //\r
699 VerboseMsg ("R_X86_64_64");\r
700 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX", \r
701 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
702 *(UINT64 *)Targ);\r
703 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
704 VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ);\r
705 break;\r
706 case R_X86_64_32:\r
707 VerboseMsg ("R_X86_64_32");\r
708 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
709 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
710 *(UINT32 *)Targ);\r
711 *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
712 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
713 break;\r
714 case R_X86_64_32S:\r
715 VerboseMsg ("R_X86_64_32S");\r
716 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
717 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
718 *(UINT32 *)Targ);\r
719 *(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
720 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
721 break;\r
722 case R_X86_64_PC32:\r
723 //\r
724 // Relative relocation: Symbol - Ip + Addend\r
725 //\r
726 VerboseMsg ("R_X86_64_PC32");\r
727 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
728 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
729 *(UINT32 *)Targ);\r
730 *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ\r
731 + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)\r
732 - (SecOffset - SecShdr->sh_addr));\r
733 VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ);\r
734 break;\r
735 default:\r
736 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
737 }\r
738 } else if (mEhdr->e_machine == EM_AARCH64) {\r
739\r
f51461c8
LG
740 switch (ELF_R_TYPE(Rel->r_info)) {\r
741\r
24d610e6
AB
742 case R_AARCH64_ADR_PREL_PG_HI21:\r
743 case R_AARCH64_ADD_ABS_LO12_NC:\r
744 case R_AARCH64_LDST8_ABS_LO12_NC:\r
745 case R_AARCH64_LDST16_ABS_LO12_NC:\r
746 case R_AARCH64_LDST32_ABS_LO12_NC:\r
747 case R_AARCH64_LDST64_ABS_LO12_NC:\r
748 case R_AARCH64_LDST128_ABS_LO12_NC:\r
749 //\r
750 // AArch64 PG_H21 relocations are typically paired with ABS_LO12\r
751 // relocations, where a PC-relative reference with +/- 4 GB range is\r
752 // split into a relative high part and an absolute low part. Since\r
753 // the absolute low part represents the offset into a 4 KB page, we\r
754 // have to make sure that the 4 KB relative offsets of both the\r
755 // section containing the reference as well as the section to which\r
756 // it refers have not been changed during PE/COFF conversion (i.e.,\r
757 // in ScanSections64() above).\r
758 //\r
759 if (((SecShdr->sh_addr ^ SecOffset) & 0xfff) != 0 ||\r
760 ((SymShdr->sh_addr ^ mCoffSectionsOffset[Sym->st_shndx]) & 0xfff) != 0 ||\r
761 mCoffAlignment < 0x1000) {\r
762 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 small code model requires 4 KB section alignment.",\r
763 mInImageName);\r
764 break;\r
87280982 765 }\r
24d610e6 766 /* fall through */\r
87280982 767\r
24d610e6 768 case R_AARCH64_ADR_PREL_LO21:\r
87280982 769 case R_AARCH64_CONDBR19:\r
f51461c8 770 case R_AARCH64_LD_PREL_LO19:\r
f51461c8 771 case R_AARCH64_CALL26:\r
f51461c8 772 case R_AARCH64_JUMP26:\r
0b6249f5
AB
773 case R_AARCH64_PREL64:\r
774 case R_AARCH64_PREL32:\r
775 case R_AARCH64_PREL16:\r
24d610e6
AB
776 //\r
777 // The GCC toolchains (i.e., binutils) may corrupt section relative\r
778 // relocations when emitting relocation sections into fully linked\r
779 // binaries. More specifically, they tend to fail to take into\r
780 // account the fact that a '.rodata + XXX' relocation needs to have\r
781 // its addend recalculated once .rodata is merged into the .text\r
782 // section, and the relocation emitted into the .rela.text section.\r
783 //\r
784 // We cannot really recover from this loss of information, so the\r
785 // only workaround is to prevent having to recalculate any relative\r
786 // relocations at all, by using a linker script that ensures that\r
787 // the offset between the Place and the Symbol is the same in both\r
788 // the ELF and the PE/COFF versions of the binary.\r
789 //\r
790 if ((SymShdr->sh_addr - SecShdr->sh_addr) !=\r
791 (mCoffSectionsOffset[Sym->st_shndx] - SecOffset)) {\r
792 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 relative relocations require identical ELF and PE/COFF section offsets",\r
793 mInImageName);\r
f51461c8
LG
794 }\r
795 break;\r
796\r
f51461c8
LG
797 // Absolute relocations.\r
798 case R_AARCH64_ABS64:\r
799 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
800 break;\r
801\r
802 default:\r
803 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
804 }\r
805 } else {\r
806 Error (NULL, 0, 3000, "Invalid", "Not a supported machine type");\r
807 }\r
808 }\r
809 }\r
810 }\r
811\r
812 return TRUE;\r
813}\r
814\r
815STATIC\r
816VOID\r
817WriteRelocations64 (\r
818 VOID\r
819 )\r
820{\r
821 UINT32 Index;\r
822 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
823 EFI_IMAGE_DATA_DIRECTORY *Dir;\r
824\r
825 for (Index = 0; Index < mEhdr->e_shnum; Index++) {\r
826 Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
827 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {\r
828 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);\r
829 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {\r
830 UINT64 RelIdx;\r
831\r
832 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {\r
833 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
834\r
835 if (mEhdr->e_machine == EM_X86_64) {\r
836 switch (ELF_R_TYPE(Rel->r_info)) {\r
837 case R_X86_64_NONE:\r
838 case R_X86_64_PC32:\r
839 break;\r
840 case R_X86_64_64:\r
841 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", \r
842 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
843 CoffAddFixup(\r
844 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
845 + (Rel->r_offset - SecShdr->sh_addr)),\r
846 EFI_IMAGE_REL_BASED_DIR64);\r
847 break;\r
848 case R_X86_64_32S:\r
849 case R_X86_64_32:\r
850 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X", \r
851 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\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_HIGHLOW);\r
856 break;\r
857 default:\r
858 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
859 }\r
860 } else if (mEhdr->e_machine == EM_AARCH64) {\r
24d610e6 861\r
f51461c8 862 switch (ELF_R_TYPE(Rel->r_info)) {\r
87280982 863 case R_AARCH64_ADR_PREL_LO21:\r
87280982 864 case R_AARCH64_CONDBR19:\r
f51461c8 865 case R_AARCH64_LD_PREL_LO19:\r
f51461c8 866 case R_AARCH64_CALL26:\r
f51461c8 867 case R_AARCH64_JUMP26:\r
0b6249f5
AB
868 case R_AARCH64_PREL64:\r
869 case R_AARCH64_PREL32:\r
870 case R_AARCH64_PREL16:\r
f51461c8 871 case R_AARCH64_ADR_PREL_PG_HI21:\r
f51461c8 872 case R_AARCH64_ADD_ABS_LO12_NC:\r
24d610e6
AB
873 case R_AARCH64_LDST8_ABS_LO12_NC:\r
874 case R_AARCH64_LDST16_ABS_LO12_NC:\r
875 case R_AARCH64_LDST32_ABS_LO12_NC:\r
876 case R_AARCH64_LDST64_ABS_LO12_NC:\r
877 case R_AARCH64_LDST128_ABS_LO12_NC:\r
0b6249f5
AB
878 //\r
879 // No fixups are required for relative relocations, provided that\r
880 // the relative offsets between sections have been preserved in\r
881 // the ELF to PE/COFF conversion. We have already asserted that\r
882 // this is the case in WriteSections64 ().\r
883 //\r
f51461c8
LG
884 break;\r
885\r
886 case R_AARCH64_ABS64:\r
887 CoffAddFixup(\r
888 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
889 + (Rel->r_offset - SecShdr->sh_addr)),\r
890 EFI_IMAGE_REL_BASED_DIR64);\r
891 break;\r
892\r
893 case R_AARCH64_ABS32:\r
894 CoffAddFixup(\r
895 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
896 + (Rel->r_offset - SecShdr->sh_addr)),\r
897 EFI_IMAGE_REL_BASED_HIGHLOW);\r
898 break;\r
899\r
900 default:\r
901 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
902 }\r
903 } else {\r
904 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
905 }\r
906 }\r
907 }\r
908 }\r
909 }\r
910\r
911 //\r
912 // Pad by adding empty entries.\r
913 //\r
914 while (mCoffOffset & (mCoffAlignment - 1)) {\r
915 CoffAddFixupEntry(0);\r
916 }\r
917\r
918 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
919 Dir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
920 Dir->Size = mCoffOffset - mRelocOffset;\r
921 if (Dir->Size == 0) {\r
922 // If no relocations, null out the directory entry and don't add the .reloc section\r
923 Dir->VirtualAddress = 0;\r
924 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
925 } else {\r
926 Dir->VirtualAddress = mRelocOffset;\r
927 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,\r
928 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
929 | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
930 | EFI_IMAGE_SCN_MEM_READ);\r
931 }\r
932}\r
933\r
934STATIC\r
935VOID\r
936WriteDebug64 (\r
937 VOID\r
938 )\r
939{\r
940 UINT32 Len;\r
f51461c8
LG
941 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
942 EFI_IMAGE_DATA_DIRECTORY *DataDir;\r
943 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;\r
944 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;\r
945\r
946 Len = strlen(mInImageName) + 1;\r
f51461c8 947\r
0192b71c 948 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);\r
f51461c8
LG
949 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
950 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
0192b71c
AB
951 Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
952 Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
f51461c8
LG
953\r
954 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);\r
955 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;\r
956 strcpy ((char *)(Nb10 + 1), mInImageName);\r
957\r
958\r
959 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
960 DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
0192b71c
AB
961 DataDir->VirtualAddress = mDebugOffset;\r
962 DataDir->Size = Dir->SizeOfData + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
f51461c8
LG
963}\r
964\r
965STATIC\r
966VOID\r
967SetImageSize64 (\r
968 VOID\r
969 )\r
970{\r
971 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
972\r
973 //\r
974 // Set image size\r
975 //\r
976 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
977 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = mCoffOffset;\r
978}\r
979\r
980STATIC\r
981VOID\r
982CleanUp64 (\r
983 VOID\r
984 )\r
985{\r
986 if (mCoffSectionsOffset != NULL) {\r
987 free (mCoffSectionsOffset);\r
988 }\r
989}\r
990\r
991\r