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