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