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