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