]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFw/Elf64Convert.c
Clean up code.
[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
4Portions copyright (c) 2013, ARM Ltd. All rights reserved.<BR>\r
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
693 case R_AARCH64_LD_PREL_LO19:\r
694 if (Rel->r_addend != 0 ) { /* TODO */\r
695 Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_LD_PREL_LO19 Need to fixup with addend!.");\r
696 }\r
697 break;\r
698\r
699 case R_AARCH64_CALL26:\r
700 if (Rel->r_addend != 0 ) { /* TODO */\r
701 Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_CALL26 Need to fixup with addend!.");\r
702 }\r
703 break;\r
704\r
705 case R_AARCH64_JUMP26:\r
706 if (Rel->r_addend != 0 ) { /* TODO : AArch64 '-O2' optimisation. */\r
707 Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26 Need to fixup with addend!.");\r
708 }\r
709 break;\r
710\r
711 case R_AARCH64_ADR_PREL_PG_HI21:\r
712 // TODO : AArch64 'small' memory model.\r
713 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);\r
714 break;\r
715\r
716 case R_AARCH64_ADD_ABS_LO12_NC:\r
717 // TODO : AArch64 'small' memory model.\r
718 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);\r
719 break;\r
720\r
721 // Absolute relocations.\r
722 case R_AARCH64_ABS64:\r
723 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
724 break;\r
725\r
726 default:\r
727 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
728 }\r
729 } else {\r
730 Error (NULL, 0, 3000, "Invalid", "Not a supported machine type");\r
731 }\r
732 }\r
733 }\r
734 }\r
735\r
736 return TRUE;\r
737}\r
738\r
739STATIC\r
740VOID\r
741WriteRelocations64 (\r
742 VOID\r
743 )\r
744{\r
745 UINT32 Index;\r
746 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
747 EFI_IMAGE_DATA_DIRECTORY *Dir;\r
748\r
749 for (Index = 0; Index < mEhdr->e_shnum; Index++) {\r
750 Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
751 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {\r
752 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);\r
753 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {\r
754 UINT64 RelIdx;\r
755\r
756 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {\r
757 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
758\r
759 if (mEhdr->e_machine == EM_X86_64) {\r
760 switch (ELF_R_TYPE(Rel->r_info)) {\r
761 case R_X86_64_NONE:\r
762 case R_X86_64_PC32:\r
763 break;\r
764 case R_X86_64_64:\r
765 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", \r
766 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
767 CoffAddFixup(\r
768 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
769 + (Rel->r_offset - SecShdr->sh_addr)),\r
770 EFI_IMAGE_REL_BASED_DIR64);\r
771 break;\r
772 case R_X86_64_32S:\r
773 case R_X86_64_32:\r
774 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X", \r
775 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
776 CoffAddFixup(\r
777 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
778 + (Rel->r_offset - SecShdr->sh_addr)),\r
779 EFI_IMAGE_REL_BASED_HIGHLOW);\r
780 break;\r
781 default:\r
782 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
783 }\r
784 } else if (mEhdr->e_machine == EM_AARCH64) {\r
785 // AArch64 GCC uses RELA relocation, so all relocations has to be fixed up. ARM32 uses REL.\r
786 switch (ELF_R_TYPE(Rel->r_info)) {\r
787 case R_AARCH64_LD_PREL_LO19:\r
788 break;\r
789\r
790 case R_AARCH64_CALL26:\r
791 break;\r
792\r
793 case R_AARCH64_JUMP26:\r
794 break;\r
795\r
796 case R_AARCH64_ADR_PREL_PG_HI21:\r
797 // TODO : AArch64 'small' memory model.\r
798 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName);\r
799 break;\r
800\r
801 case R_AARCH64_ADD_ABS_LO12_NC:\r
802 // TODO : AArch64 'small' memory model.\r
803 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName);\r
804 break;\r
805\r
806 case R_AARCH64_ABS64:\r
807 CoffAddFixup(\r
808 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
809 + (Rel->r_offset - SecShdr->sh_addr)),\r
810 EFI_IMAGE_REL_BASED_DIR64);\r
811 break;\r
812\r
813 case R_AARCH64_ABS32:\r
814 CoffAddFixup(\r
815 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
816 + (Rel->r_offset - SecShdr->sh_addr)),\r
817 EFI_IMAGE_REL_BASED_HIGHLOW);\r
818 break;\r
819\r
820 default:\r
821 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
822 }\r
823 } else {\r
824 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
825 }\r
826 }\r
827 }\r
828 }\r
829 }\r
830\r
831 //\r
832 // Pad by adding empty entries.\r
833 //\r
834 while (mCoffOffset & (mCoffAlignment - 1)) {\r
835 CoffAddFixupEntry(0);\r
836 }\r
837\r
838 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
839 Dir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
840 Dir->Size = mCoffOffset - mRelocOffset;\r
841 if (Dir->Size == 0) {\r
842 // If no relocations, null out the directory entry and don't add the .reloc section\r
843 Dir->VirtualAddress = 0;\r
844 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
845 } else {\r
846 Dir->VirtualAddress = mRelocOffset;\r
847 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,\r
848 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
849 | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
850 | EFI_IMAGE_SCN_MEM_READ);\r
851 }\r
852}\r
853\r
854STATIC\r
855VOID\r
856WriteDebug64 (\r
857 VOID\r
858 )\r
859{\r
860 UINT32 Len;\r
861 UINT32 DebugOffset;\r
862 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
863 EFI_IMAGE_DATA_DIRECTORY *DataDir;\r
864 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;\r
865 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;\r
866\r
867 Len = strlen(mInImageName) + 1;\r
868 DebugOffset = mCoffOffset;\r
869\r
870 mCoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)\r
871 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)\r
872 + Len;\r
873 mCoffOffset = CoffAlign(mCoffOffset);\r
874\r
875 mCoffFile = realloc(mCoffFile, mCoffOffset);\r
876 memset(mCoffFile + DebugOffset, 0, mCoffOffset - DebugOffset);\r
877\r
878 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + DebugOffset);\r
879 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
880 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
881 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
882 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
883\r
884 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);\r
885 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;\r
886 strcpy ((char *)(Nb10 + 1), mInImageName);\r
887\r
888\r
889 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
890 DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
891 DataDir->VirtualAddress = DebugOffset;\r
892 DataDir->Size = mCoffOffset - DebugOffset;\r
893 if (DataDir->Size == 0) {\r
894 // If no debug, null out the directory entry and don't add the .debug section\r
895 DataDir->VirtualAddress = 0;\r
896 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
897 } else {\r
898 DataDir->VirtualAddress = DebugOffset;\r
899 CreateSectionHeader (".debug", DebugOffset, mCoffOffset - DebugOffset,\r
900 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
901 | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
902 | EFI_IMAGE_SCN_MEM_READ);\r
903\r
904 }\r
905}\r
906\r
907STATIC\r
908VOID\r
909SetImageSize64 (\r
910 VOID\r
911 )\r
912{\r
913 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
914\r
915 //\r
916 // Set image size\r
917 //\r
918 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
919 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = mCoffOffset;\r
920}\r
921\r
922STATIC\r
923VOID\r
924CleanUp64 (\r
925 VOID\r
926 )\r
927{\r
928 if (mCoffSectionsOffset != NULL) {\r
929 free (mCoffSectionsOffset);\r
930 }\r
931}\r
932\r
933\r