]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFw/Elf64Convert.c
Sync BaseTools Branch (version r2149) to EDKII main trunk.
[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;
640 BOOLEAN FoundRelocations;
641 Elf_Sym *Sym;
642 Elf_Shdr *SymtabShdr;
643 UINT8 *Symtab;
644
645
646 for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {
647 Elf_Shdr *RelShdr = GetShdrByIndex(Index);
648 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {
649 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);
650 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
651 UINT64 RelIdx;
652
653 SymtabShdr = GetShdrByIndex (RelShdr->sh_link);
654 Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;
655 FoundRelocations = TRUE;
656 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
657 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);
658 Elf_Shdr *SymShdr;
659
660 Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
661 SymShdr = GetShdrByIndex (Sym->st_shndx);
662
663 if (mEhdr->e_machine == EM_X86_64) {
664 switch (ELF_R_TYPE(Rel->r_info)) {
665 case R_X86_64_NONE:
666 case R_X86_64_PC32:
667 break;
668 case R_X86_64_64:
669 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X",
670 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));
671 CoffAddFixup(
672 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]
673 + (Rel->r_offset - SecShdr->sh_addr)),
674 EFI_IMAGE_REL_BASED_DIR64);
675 break;
676 case R_X86_64_32S:
677 case R_X86_64_32:
678 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X",
679 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));
680 CoffAddFixup(
681 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]
682 + (Rel->r_offset - SecShdr->sh_addr)),
683 EFI_IMAGE_REL_BASED_HIGHLOW);
684 break;
685 default:
686 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
687 }
688 } else {
689 Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);
690 }
691 }
692 }
693 }
694 }
695
696 //
697 // Pad by adding empty entries.
698 //
699 while (mCoffOffset & (mCoffAlignment - 1)) {
700 CoffAddFixupEntry(0);
701 }
702
703 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
704 Dir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
705 Dir->Size = mCoffOffset - mRelocOffset;
706 if (Dir->Size == 0) {
707 // If no relocations, null out the directory entry and don't add the .reloc section
708 Dir->VirtualAddress = 0;
709 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;
710 } else {
711 Dir->VirtualAddress = mRelocOffset;
712 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,
713 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
714 | EFI_IMAGE_SCN_MEM_DISCARDABLE
715 | EFI_IMAGE_SCN_MEM_READ);
716 }
717}
718
719STATIC
720VOID
721WriteDebug64 (
722 VOID
723 )
724{
725 UINT32 Len;
726 UINT32 DebugOffset;
727 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
728 EFI_IMAGE_DATA_DIRECTORY *DataDir;
729 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
730 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
731
732 Len = strlen(mInImageName) + 1;
733 DebugOffset = mCoffOffset;
734
735 mCoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)
736 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)
737 + Len;
738 mCoffOffset = CoffAlign(mCoffOffset);
739
740 mCoffFile = realloc(mCoffFile, mCoffOffset);
741 memset(mCoffFile + DebugOffset, 0, mCoffOffset - DebugOffset);
742
743 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + DebugOffset);
744 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
745 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;
746 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
747 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
748
749 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
750 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
751 strcpy ((char *)(Nb10 + 1), mInImageName);
752
753
754 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
755 DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
756 DataDir->VirtualAddress = DebugOffset;
757 DataDir->Size = mCoffOffset - DebugOffset;
758 if (DataDir->Size == 0) {
759 // If no debug, null out the directory entry and don't add the .debug section
760 DataDir->VirtualAddress = 0;
761 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;
762 } else {
763 DataDir->VirtualAddress = DebugOffset;
764 CreateSectionHeader (".debug", DebugOffset, mCoffOffset - DebugOffset,
765 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
766 | EFI_IMAGE_SCN_MEM_DISCARDABLE
767 | EFI_IMAGE_SCN_MEM_READ);
768
769 }
770}
771
772STATIC
773VOID
774SetImageSize64 (
775 VOID
776 )
777{
778 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
779
780 //
781 // Set image size
782 //
783 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
784 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = mCoffOffset;
785}
786
787STATIC
788VOID
789CleanUp64 (
790 VOID
791 )
792{
793 if (mCoffSectionsOffset != NULL) {
794 free (mCoffSectionsOffset);
795 }
796}
797
798