]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFw/Elf64Convert.c
BaseTools-Source: Update displayed version information
[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
0b6249f5
AB
770 case R_AARCH64_PREL64:\r
771 case R_AARCH64_PREL32:\r
772 case R_AARCH64_PREL16:\r
24d610e6
AB
773 //\r
774 // The GCC toolchains (i.e., binutils) may corrupt section relative\r
775 // relocations when emitting relocation sections into fully linked\r
776 // binaries. More specifically, they tend to fail to take into\r
777 // account the fact that a '.rodata + XXX' relocation needs to have\r
778 // its addend recalculated once .rodata is merged into the .text\r
779 // section, and the relocation emitted into the .rela.text section.\r
780 //\r
781 // We cannot really recover from this loss of information, so the\r
782 // only workaround is to prevent having to recalculate any relative\r
783 // relocations at all, by using a linker script that ensures that\r
784 // the offset between the Place and the Symbol is the same in both\r
785 // the ELF and the PE/COFF versions of the binary.\r
786 //\r
787 if ((SymShdr->sh_addr - SecShdr->sh_addr) !=\r
788 (mCoffSectionsOffset[Sym->st_shndx] - SecOffset)) {\r
789 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 relative relocations require identical ELF and PE/COFF section offsets",\r
790 mInImageName);\r
f51461c8
LG
791 }\r
792 break;\r
793\r
f51461c8
LG
794 // Absolute relocations.\r
795 case R_AARCH64_ABS64:\r
796 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
797 break;\r
798\r
799 default:\r
800 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
801 }\r
802 } else {\r
803 Error (NULL, 0, 3000, "Invalid", "Not a supported machine type");\r
804 }\r
805 }\r
806 }\r
807 }\r
808\r
809 return TRUE;\r
810}\r
811\r
812STATIC\r
813VOID\r
814WriteRelocations64 (\r
815 VOID\r
816 )\r
817{\r
818 UINT32 Index;\r
819 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
820 EFI_IMAGE_DATA_DIRECTORY *Dir;\r
821\r
822 for (Index = 0; Index < mEhdr->e_shnum; Index++) {\r
823 Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
824 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {\r
825 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);\r
826 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {\r
827 UINT64 RelIdx;\r
828\r
829 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {\r
830 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
831\r
832 if (mEhdr->e_machine == EM_X86_64) {\r
833 switch (ELF_R_TYPE(Rel->r_info)) {\r
834 case R_X86_64_NONE:\r
835 case R_X86_64_PC32:\r
836 break;\r
837 case R_X86_64_64:\r
838 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", \r
839 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
840 CoffAddFixup(\r
841 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
842 + (Rel->r_offset - SecShdr->sh_addr)),\r
843 EFI_IMAGE_REL_BASED_DIR64);\r
844 break;\r
845 case R_X86_64_32S:\r
846 case R_X86_64_32:\r
847 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X", \r
848 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
849 CoffAddFixup(\r
850 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
851 + (Rel->r_offset - SecShdr->sh_addr)),\r
852 EFI_IMAGE_REL_BASED_HIGHLOW);\r
853 break;\r
854 default:\r
855 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
856 }\r
857 } else if (mEhdr->e_machine == EM_AARCH64) {\r
24d610e6 858\r
f51461c8 859 switch (ELF_R_TYPE(Rel->r_info)) {\r
87280982 860 case R_AARCH64_ADR_PREL_LO21:\r
87280982 861 case R_AARCH64_CONDBR19:\r
f51461c8 862 case R_AARCH64_LD_PREL_LO19:\r
f51461c8 863 case R_AARCH64_CALL26:\r
f51461c8 864 case R_AARCH64_JUMP26:\r
0b6249f5
AB
865 case R_AARCH64_PREL64:\r
866 case R_AARCH64_PREL32:\r
867 case R_AARCH64_PREL16:\r
f51461c8 868 case R_AARCH64_ADR_PREL_PG_HI21:\r
f51461c8 869 case R_AARCH64_ADD_ABS_LO12_NC:\r
24d610e6
AB
870 case R_AARCH64_LDST8_ABS_LO12_NC:\r
871 case R_AARCH64_LDST16_ABS_LO12_NC:\r
872 case R_AARCH64_LDST32_ABS_LO12_NC:\r
873 case R_AARCH64_LDST64_ABS_LO12_NC:\r
874 case R_AARCH64_LDST128_ABS_LO12_NC:\r
0b6249f5
AB
875 //\r
876 // No fixups are required for relative relocations, provided that\r
877 // the relative offsets between sections have been preserved in\r
878 // the ELF to PE/COFF conversion. We have already asserted that\r
879 // this is the case in WriteSections64 ().\r
880 //\r
f51461c8
LG
881 break;\r
882\r
883 case R_AARCH64_ABS64:\r
884 CoffAddFixup(\r
885 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
886 + (Rel->r_offset - SecShdr->sh_addr)),\r
887 EFI_IMAGE_REL_BASED_DIR64);\r
888 break;\r
889\r
890 case R_AARCH64_ABS32:\r
891 CoffAddFixup(\r
892 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
893 + (Rel->r_offset - SecShdr->sh_addr)),\r
894 EFI_IMAGE_REL_BASED_HIGHLOW);\r
895 break;\r
896\r
897 default:\r
898 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
899 }\r
900 } else {\r
901 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
902 }\r
903 }\r
904 }\r
905 }\r
906 }\r
907\r
908 //\r
909 // Pad by adding empty entries.\r
910 //\r
911 while (mCoffOffset & (mCoffAlignment - 1)) {\r
912 CoffAddFixupEntry(0);\r
913 }\r
914\r
915 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
916 Dir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
917 Dir->Size = mCoffOffset - mRelocOffset;\r
918 if (Dir->Size == 0) {\r
919 // If no relocations, null out the directory entry and don't add the .reloc section\r
920 Dir->VirtualAddress = 0;\r
921 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
922 } else {\r
923 Dir->VirtualAddress = mRelocOffset;\r
924 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,\r
925 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
926 | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
927 | EFI_IMAGE_SCN_MEM_READ);\r
928 }\r
929}\r
930\r
931STATIC\r
932VOID\r
933WriteDebug64 (\r
934 VOID\r
935 )\r
936{\r
937 UINT32 Len;\r
f51461c8
LG
938 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
939 EFI_IMAGE_DATA_DIRECTORY *DataDir;\r
940 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;\r
941 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;\r
942\r
943 Len = strlen(mInImageName) + 1;\r
f51461c8 944\r
0192b71c 945 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);\r
f51461c8
LG
946 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
947 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
0192b71c
AB
948 Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
949 Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
f51461c8
LG
950\r
951 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);\r
952 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;\r
953 strcpy ((char *)(Nb10 + 1), mInImageName);\r
954\r
955\r
956 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
957 DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
0192b71c
AB
958 DataDir->VirtualAddress = mDebugOffset;\r
959 DataDir->Size = Dir->SizeOfData + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
f51461c8
LG
960}\r
961\r
962STATIC\r
963VOID\r
964SetImageSize64 (\r
965 VOID\r
966 )\r
967{\r
968 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
969\r
970 //\r
971 // Set image size\r
972 //\r
973 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
974 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = mCoffOffset;\r
975}\r
976\r
977STATIC\r
978VOID\r
979CleanUp64 (\r
980 VOID\r
981 )\r
982{\r
983 if (mCoffSectionsOffset != NULL) {\r
984 free (mCoffSectionsOffset);\r
985 }\r
986}\r
987\r
988\r