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