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