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