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