]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/C/GenFw/Elf64Convert.c
ArmPlatformPkg/FVP: use 'auto' alignment and FIXED placement for XIP modules
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
... / ...
CommitLineData
1/** @file\r
2Elf64 convert solution\r
3\r
4Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
5Portions copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
6\r
7This program and the accompanying materials are licensed and made available\r
8under the terms and conditions of the BSD License which accompanies this\r
9distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "WinNtInclude.h"\r
18\r
19#ifndef __GNUC__\r
20#include <windows.h>\r
21#include <io.h>\r
22#endif\r
23#include <assert.h>\r
24#include <stdio.h>\r
25#include <stdlib.h>\r
26#include <string.h>\r
27#include <time.h>\r
28#include <ctype.h>\r
29\r
30#include <Common/UefiBaseTypes.h>\r
31#include <IndustryStandard/PeImage.h>\r
32\r
33#include "PeCoffLib.h"\r
34#include "EfiUtilityMsgs.h"\r
35\r
36#include "GenFw.h"\r
37#include "ElfConvert.h"\r
38#include "Elf64Convert.h"\r
39\r
40STATIC\r
41VOID\r
42ScanSections64 (\r
43 VOID\r
44 );\r
45\r
46STATIC\r
47BOOLEAN\r
48WriteSections64 (\r
49 SECTION_FILTER_TYPES FilterType\r
50 );\r
51\r
52STATIC\r
53VOID\r
54WriteRelocations64 (\r
55 VOID\r
56 );\r
57\r
58STATIC\r
59VOID\r
60WriteDebug64 (\r
61 VOID\r
62 );\r
63\r
64STATIC\r
65VOID\r
66SetImageSize64 (\r
67 VOID\r
68 );\r
69\r
70STATIC\r
71VOID\r
72CleanUp64 (\r
73 VOID\r
74 );\r
75\r
76//\r
77// Rename ELF32 strucutres to common names to help when porting to ELF64.\r
78//\r
79typedef Elf64_Shdr Elf_Shdr;\r
80typedef Elf64_Ehdr Elf_Ehdr;\r
81typedef Elf64_Rel Elf_Rel;\r
82typedef Elf64_Rela Elf_Rela;\r
83typedef Elf64_Sym Elf_Sym;\r
84typedef Elf64_Phdr Elf_Phdr;\r
85typedef Elf64_Dyn Elf_Dyn;\r
86#define ELFCLASS ELFCLASS64\r
87#define ELF_R_TYPE(r) ELF64_R_TYPE(r)\r
88#define ELF_R_SYM(r) ELF64_R_SYM(r)\r
89\r
90//\r
91// Well known ELF structures.\r
92//\r
93STATIC Elf_Ehdr *mEhdr;\r
94STATIC Elf_Shdr *mShdrBase;\r
95STATIC Elf_Phdr *mPhdrBase;\r
96\r
97//\r
98// Coff information\r
99//\r
100STATIC UINT32 mCoffAlignment = 0x20;\r
101\r
102//\r
103// PE section alignment.\r
104//\r
105STATIC const UINT16 mCoffNbrSections = 4;\r
106\r
107//\r
108// ELF sections to offset in Coff file.\r
109//\r
110STATIC UINT32 *mCoffSectionsOffset = NULL;\r
111\r
112//\r
113// Offsets in COFF file\r
114//\r
115STATIC UINT32 mNtHdrOffset;\r
116STATIC UINT32 mTextOffset;\r
117STATIC UINT32 mDataOffset;\r
118STATIC UINT32 mHiiRsrcOffset;\r
119STATIC UINT32 mRelocOffset;\r
120STATIC UINT32 mDebugOffset;\r
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
264 BOOLEAN FoundSection;\r
265\r
266 CoffEntry = 0;\r
267 mCoffOffset = 0;\r
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
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
303 //\r
304 // Move the PE/COFF header right before the first section. This will help us\r
305 // save space when converting to TE.\r
306 //\r
307 if (mCoffAlignment > mCoffOffset) {\r
308 mNtHdrOffset += mCoffAlignment - mCoffOffset;\r
309 mTableOffset += mCoffAlignment - mCoffOffset;\r
310 mCoffOffset = mCoffAlignment;\r
311 }\r
312\r
313 //\r
314 // First text sections.\r
315 //\r
316 mCoffOffset = CoffAlign(mCoffOffset);\r
317 mTextOffset = mCoffOffset;\r
318 FoundSection = FALSE;\r
319 SectionCount = 0;\r
320 for (i = 0; i < mEhdr->e_shnum; i++) {\r
321 Elf_Shdr *shdr = GetShdrByIndex(i);\r
322 if (IsTextShdr(shdr)) {\r
323 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
324 // the alignment field is valid\r
325 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
326 // if the section address is aligned we must align PE/COFF\r
327 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
328 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
329 // ARM RVCT tools have behavior outside of the ELF specification to try\r
330 // and make images smaller. If sh_addr is not aligned to sh_addralign\r
331 // then the section needs to preserve sh_addr MOD sh_addralign.\r
332 // Normally doing nothing here works great.\r
333 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
334 }\r
335 }\r
336\r
337 /* Relocate entry. */\r
338 if ((mEhdr->e_entry >= shdr->sh_addr) &&\r
339 (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {\r
340 CoffEntry = (UINT32) (mCoffOffset + mEhdr->e_entry - shdr->sh_addr);\r
341 }\r
342\r
343 //\r
344 // Set mTextOffset with the offset of the first '.text' section\r
345 //\r
346 if (!FoundSection) {\r
347 mTextOffset = mCoffOffset;\r
348 FoundSection = TRUE;\r
349 }\r
350\r
351 mCoffSectionsOffset[i] = mCoffOffset;\r
352 mCoffOffset += (UINT32) shdr->sh_size;\r
353 SectionCount ++;\r
354 }\r
355 }\r
356\r
357 if (!FoundSection) {\r
358 Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");\r
359 assert (FALSE);\r
360 }\r
361\r
362 mDebugOffset = mCoffOffset;\r
363\r
364 if (mEhdr->e_machine != EM_ARM) {\r
365 mCoffOffset = CoffAlign(mCoffOffset);\r
366 }\r
367\r
368 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
369 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);\r
370 }\r
371\r
372 //\r
373 // Then data sections.\r
374 //\r
375 mDataOffset = mCoffOffset;\r
376 FoundSection = FALSE;\r
377 SectionCount = 0;\r
378 for (i = 0; i < mEhdr->e_shnum; i++) {\r
379 Elf_Shdr *shdr = GetShdrByIndex(i);\r
380 if (IsDataShdr(shdr)) {\r
381 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
382 // the alignment field is valid\r
383 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
384 // if the section address is aligned we must align PE/COFF\r
385 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
386 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
387 // ARM RVCT tools have behavior outside of the ELF specification to try\r
388 // and make images smaller. If sh_addr is not aligned to sh_addralign\r
389 // then the section needs to preserve sh_addr MOD sh_addralign.\r
390 // Normally doing nothing here works great.\r
391 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
392 }\r
393 }\r
394\r
395 //\r
396 // Set mDataOffset with the offset of the first '.data' section\r
397 //\r
398 if (!FoundSection) {\r
399 mDataOffset = mCoffOffset;\r
400 FoundSection = TRUE;\r
401 }\r
402 mCoffSectionsOffset[i] = mCoffOffset;\r
403 mCoffOffset += (UINT32) shdr->sh_size;\r
404 SectionCount ++;\r
405 }\r
406 }\r
407\r
408 //\r
409 // Make room for .debug data in .data (or .text if .data is empty) instead of\r
410 // putting it in a section of its own. This is explicitly allowed by the\r
411 // PE/COFF spec, and prevents bloat in the binary when using large values for\r
412 // section alignment.\r
413 //\r
414 if (SectionCount > 0) {\r
415 mDebugOffset = mCoffOffset;\r
416 }\r
417 mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) +\r
418 sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) +\r
419 strlen(mInImageName) + 1;\r
420\r
421 mCoffOffset = CoffAlign(mCoffOffset);\r
422 if (SectionCount == 0) {\r
423 mDataOffset = mCoffOffset;\r
424 }\r
425\r
426 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
427 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
428 }\r
429\r
430 //\r
431 // The HII resource sections.\r
432 //\r
433 mHiiRsrcOffset = mCoffOffset;\r
434 for (i = 0; i < mEhdr->e_shnum; i++) {\r
435 Elf_Shdr *shdr = GetShdrByIndex(i);\r
436 if (IsHiiRsrcShdr(shdr)) {\r
437 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
438 // the alignment field is valid\r
439 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
440 // if the section address is aligned we must align PE/COFF\r
441 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
442 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
443 // ARM RVCT tools have behavior outside of the ELF specification to try\r
444 // and make images smaller. If sh_addr is not aligned to sh_addralign\r
445 // then the section needs to preserve sh_addr MOD sh_addralign.\r
446 // Normally doing nothing here works great.\r
447 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
448 }\r
449 }\r
450 if (shdr->sh_size != 0) {\r
451 mHiiRsrcOffset = mCoffOffset;\r
452 mCoffSectionsOffset[i] = mCoffOffset;\r
453 mCoffOffset += (UINT32) shdr->sh_size;\r
454 mCoffOffset = CoffAlign(mCoffOffset);\r
455 SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);\r
456 }\r
457 break;\r
458 }\r
459 }\r
460\r
461 mRelocOffset = mCoffOffset;\r
462\r
463 //\r
464 // Allocate base Coff file. Will be expanded later for relocations.\r
465 //\r
466 mCoffFile = (UINT8 *)malloc(mCoffOffset);\r
467 memset(mCoffFile, 0, mCoffOffset);\r
468\r
469 //\r
470 // Fill headers.\r
471 //\r
472 DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;\r
473 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;\r
474 DosHdr->e_lfanew = mNtHdrOffset;\r
475\r
476 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);\r
477\r
478 NtHdr->Pe32Plus.Signature = EFI_IMAGE_NT_SIGNATURE;\r
479\r
480 switch (mEhdr->e_machine) {\r
481 case EM_X86_64:\r
482 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
483 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
484 break;\r
485 case EM_IA_64:\r
486 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_IPF;\r
487 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
488 break;\r
489 case EM_AARCH64:\r
490 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_AARCH64;\r
491 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
492 break;\r
493 default:\r
494 VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
495 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
496 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
497 }\r
498\r
499 NtHdr->Pe32Plus.FileHeader.NumberOfSections = mCoffNbrSections;\r
500 NtHdr->Pe32Plus.FileHeader.TimeDateStamp = (UINT32) time(NULL);\r
501 mImageTimeStamp = NtHdr->Pe32Plus.FileHeader.TimeDateStamp;\r
502 NtHdr->Pe32Plus.FileHeader.PointerToSymbolTable = 0;\r
503 NtHdr->Pe32Plus.FileHeader.NumberOfSymbols = 0;\r
504 NtHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32Plus.OptionalHeader);\r
505 NtHdr->Pe32Plus.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE\r
506 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED\r
507 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED\r
508 | EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE;\r
509\r
510 NtHdr->Pe32Plus.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;\r
511 NtHdr->Pe32Plus.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;\r
512 NtHdr->Pe32Plus.OptionalHeader.SizeOfUninitializedData = 0;\r
513 NtHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint = CoffEntry;\r
514\r
515 NtHdr->Pe32Plus.OptionalHeader.BaseOfCode = mTextOffset;\r
516\r
517 NtHdr->Pe32Plus.OptionalHeader.ImageBase = 0;\r
518 NtHdr->Pe32Plus.OptionalHeader.SectionAlignment = mCoffAlignment;\r
519 NtHdr->Pe32Plus.OptionalHeader.FileAlignment = mCoffAlignment;\r
520 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = 0;\r
521\r
522 NtHdr->Pe32Plus.OptionalHeader.SizeOfHeaders = mTextOffset;\r
523 NtHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
524\r
525 //\r
526 // Section headers.\r
527 //\r
528 if ((mDataOffset - mTextOffset) > 0) {\r
529 CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,\r
530 EFI_IMAGE_SCN_CNT_CODE\r
531 | EFI_IMAGE_SCN_MEM_EXECUTE\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 ((mHiiRsrcOffset - mDataOffset) > 0) {\r
539 CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,\r
540 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
541 | EFI_IMAGE_SCN_MEM_WRITE\r
542 | EFI_IMAGE_SCN_MEM_READ);\r
543 } else {\r
544 // Don't make a section of size 0.\r
545 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
546 }\r
547\r
548 if ((mRelocOffset - mHiiRsrcOffset) > 0) {\r
549 CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,\r
550 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
551 | EFI_IMAGE_SCN_MEM_READ);\r
552\r
553 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;\r
554 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;\r
555 } else {\r
556 // Don't make a section of size 0.\r
557 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
558 }\r
559\r
560}\r
561\r
562STATIC\r
563BOOLEAN\r
564WriteSections64 (\r
565 SECTION_FILTER_TYPES FilterType\r
566 )\r
567{\r
568 UINT32 Idx;\r
569 Elf_Shdr *SecShdr;\r
570 UINT32 SecOffset;\r
571 BOOLEAN (*Filter)(Elf_Shdr *);\r
572\r
573 //\r
574 // Initialize filter pointer\r
575 //\r
576 switch (FilterType) {\r
577 case SECTION_TEXT:\r
578 Filter = IsTextShdr;\r
579 break;\r
580 case SECTION_HII:\r
581 Filter = IsHiiRsrcShdr;\r
582 break;\r
583 case SECTION_DATA:\r
584 Filter = IsDataShdr;\r
585 break;\r
586 default:\r
587 return FALSE;\r
588 }\r
589\r
590 //\r
591 // First: copy sections.\r
592 //\r
593 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
594 Elf_Shdr *Shdr = GetShdrByIndex(Idx);\r
595 if ((*Filter)(Shdr)) {\r
596 switch (Shdr->sh_type) {\r
597 case SHT_PROGBITS:\r
598 /* Copy. */\r
599 memcpy(mCoffFile + mCoffSectionsOffset[Idx],\r
600 (UINT8*)mEhdr + Shdr->sh_offset,\r
601 (size_t) Shdr->sh_size);\r
602 break;\r
603\r
604 case SHT_NOBITS:\r
605 memset(mCoffFile + mCoffSectionsOffset[Idx], 0, (size_t) Shdr->sh_size);\r
606 break;\r
607\r
608 default:\r
609 //\r
610 // Ignore for unkown section type.\r
611 //\r
612 VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type);\r
613 break;\r
614 }\r
615 }\r
616 }\r
617\r
618 //\r
619 // Second: apply relocations.\r
620 //\r
621 VerboseMsg ("Applying Relocations...");\r
622 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
623 //\r
624 // Determine if this is a relocation section.\r
625 //\r
626 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);\r
627 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {\r
628 continue;\r
629 }\r
630\r
631 //\r
632 // Relocation section found. Now extract section information that the relocations\r
633 // apply to in the ELF data and the new COFF data.\r
634 //\r
635 SecShdr = GetShdrByIndex(RelShdr->sh_info);\r
636 SecOffset = mCoffSectionsOffset[RelShdr->sh_info];\r
637\r
638 //\r
639 // Only process relocations for the current filter type.\r
640 //\r
641 if (RelShdr->sh_type == SHT_RELA && (*Filter)(SecShdr)) {\r
642 UINT64 RelIdx;\r
643\r
644 //\r
645 // Determine the symbol table referenced by the relocation data.\r
646 //\r
647 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);\r
648 UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;\r
649\r
650 //\r
651 // Process all relocation entries for this section.\r
652 //\r
653 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINT32) RelShdr->sh_entsize) {\r
654\r
655 //\r
656 // Set pointer to relocation entry\r
657 //\r
658 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
659\r
660 //\r
661 // Set pointer to symbol table entry associated with the relocation entry.\r
662 //\r
663 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);\r
664\r
665 Elf_Shdr *SymShdr;\r
666 UINT8 *Targ;\r
667\r
668 //\r
669 // Check section header index found in symbol table and get the section\r
670 // header location.\r
671 //\r
672 if (Sym->st_shndx == SHN_UNDEF\r
673 || Sym->st_shndx == SHN_ABS\r
674 || Sym->st_shndx > mEhdr->e_shnum) {\r
675 Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName);\r
676 }\r
677 SymShdr = GetShdrByIndex(Sym->st_shndx);\r
678\r
679 //\r
680 // Convert the relocation data to a pointer into the coff file.\r
681 //\r
682 // Note:\r
683 // r_offset is the virtual address of the storage unit to be relocated.\r
684 // sh_addr is the virtual address for the base of the section.\r
685 //\r
686 // r_offset in a memory address.\r
687 // Convert it to a pointer in the coff file.\r
688 //\r
689 Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);\r
690\r
691 //\r
692 // Determine how to handle each relocation type based on the machine type.\r
693 //\r
694 if (mEhdr->e_machine == EM_X86_64) {\r
695 switch (ELF_R_TYPE(Rel->r_info)) {\r
696 case R_X86_64_NONE:\r
697 break;\r
698 case R_X86_64_64:\r
699 //\r
700 // Absolute relocation.\r
701 //\r
702 VerboseMsg ("R_X86_64_64");\r
703 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX", \r
704 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
705 *(UINT64 *)Targ);\r
706 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
707 VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ);\r
708 break;\r
709 case R_X86_64_32:\r
710 VerboseMsg ("R_X86_64_32");\r
711 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
712 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
713 *(UINT32 *)Targ);\r
714 *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
715 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
716 break;\r
717 case R_X86_64_32S:\r
718 VerboseMsg ("R_X86_64_32S");\r
719 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
720 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
721 *(UINT32 *)Targ);\r
722 *(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
723 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
724 break;\r
725 case R_X86_64_PC32:\r
726 //\r
727 // Relative relocation: Symbol - Ip + Addend\r
728 //\r
729 VerboseMsg ("R_X86_64_PC32");\r
730 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
731 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
732 *(UINT32 *)Targ);\r
733 *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ\r
734 + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)\r
735 - (SecOffset - SecShdr->sh_addr));\r
736 VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ);\r
737 break;\r
738 default:\r
739 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
740 }\r
741 } else if (mEhdr->e_machine == EM_AARCH64) {\r
742\r
743 // AARCH64 GCC uses RELA relocation, so all relocations have to be fixed up.\r
744 // As opposed to ARM32 using REL.\r
745\r
746 switch (ELF_R_TYPE(Rel->r_info)) {\r
747\r
748 case R_AARCH64_ADR_PREL_LO21:\r
749 if (Rel->r_addend != 0 ) { /* TODO */\r
750 Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_ADR_PREL_LO21 Need to fixup with addend!.");\r
751 }\r
752 break;\r
753\r
754 case R_AARCH64_CONDBR19:\r
755 if (Rel->r_addend != 0 ) { /* TODO */\r
756 Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_CONDBR19 Need to fixup with addend!.");\r
757 }\r
758 break;\r
759\r
760 case R_AARCH64_LD_PREL_LO19:\r
761 if (Rel->r_addend != 0 ) { /* TODO */\r
762 Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_LD_PREL_LO19 Need to fixup with addend!.");\r
763 }\r
764 break;\r
765\r
766 case R_AARCH64_CALL26:\r
767 case R_AARCH64_JUMP26:\r
768 if (Rel->r_addend != 0 ) {\r
769 // Some references to static functions sometime start at the base of .text + addend.\r
770 // It is safe to ignore these relocations because they patch a `BL` instructions that\r
771 // contains an offset from the instruction itself and there is only a single .text section.\r
772 // So we check if the symbol is a "section symbol"\r
773 if (ELF64_ST_TYPE (Sym->st_info) == STT_SECTION) {\r
774 break;\r
775 }\r
776 Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26 Need to fixup with addend!.");\r
777 }\r
778 break;\r
779\r
780 case R_AARCH64_ADR_PREL_PG_HI21:\r
781 // TODO : AArch64 'small' memory model.\r
782 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);\r
783 break;\r
784\r
785 case R_AARCH64_ADD_ABS_LO12_NC:\r
786 // TODO : AArch64 'small' memory model.\r
787 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);\r
788 break;\r
789\r
790 // Absolute relocations.\r
791 case R_AARCH64_ABS64:\r
792 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
793 break;\r
794\r
795 default:\r
796 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
797 }\r
798 } else {\r
799 Error (NULL, 0, 3000, "Invalid", "Not a supported machine type");\r
800 }\r
801 }\r
802 }\r
803 }\r
804\r
805 return TRUE;\r
806}\r
807\r
808STATIC\r
809VOID\r
810WriteRelocations64 (\r
811 VOID\r
812 )\r
813{\r
814 UINT32 Index;\r
815 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
816 EFI_IMAGE_DATA_DIRECTORY *Dir;\r
817\r
818 for (Index = 0; Index < mEhdr->e_shnum; Index++) {\r
819 Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
820 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {\r
821 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);\r
822 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {\r
823 UINT64 RelIdx;\r
824\r
825 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {\r
826 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
827\r
828 if (mEhdr->e_machine == EM_X86_64) {\r
829 switch (ELF_R_TYPE(Rel->r_info)) {\r
830 case R_X86_64_NONE:\r
831 case R_X86_64_PC32:\r
832 break;\r
833 case R_X86_64_64:\r
834 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", \r
835 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
836 CoffAddFixup(\r
837 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
838 + (Rel->r_offset - SecShdr->sh_addr)),\r
839 EFI_IMAGE_REL_BASED_DIR64);\r
840 break;\r
841 case R_X86_64_32S:\r
842 case R_X86_64_32:\r
843 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X", \r
844 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
845 CoffAddFixup(\r
846 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
847 + (Rel->r_offset - SecShdr->sh_addr)),\r
848 EFI_IMAGE_REL_BASED_HIGHLOW);\r
849 break;\r
850 default:\r
851 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
852 }\r
853 } else if (mEhdr->e_machine == EM_AARCH64) {\r
854 // AArch64 GCC uses RELA relocation, so all relocations has to be fixed up. ARM32 uses REL.\r
855 switch (ELF_R_TYPE(Rel->r_info)) {\r
856 case R_AARCH64_ADR_PREL_LO21:\r
857 break;\r
858\r
859 case R_AARCH64_CONDBR19:\r
860 break;\r
861\r
862 case R_AARCH64_LD_PREL_LO19:\r
863 break;\r
864\r
865 case R_AARCH64_CALL26:\r
866 break;\r
867\r
868 case R_AARCH64_JUMP26:\r
869 break;\r
870\r
871 case R_AARCH64_ADR_PREL_PG_HI21:\r
872 // TODO : AArch64 'small' memory model.\r
873 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);\r
874 break;\r
875\r
876 case R_AARCH64_ADD_ABS_LO12_NC:\r
877 // TODO : AArch64 'small' memory model.\r
878 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);\r
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
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
942\r
943 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);\r
944 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
945 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
946 Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
947 Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
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
956 DataDir->VirtualAddress = mDebugOffset;\r
957 DataDir->Size = Dir->SizeOfData + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
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