]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/C/GenFw/Elf64Convert.c
Sync EDKII BaseTools to BaseTools project r1971
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
... / ...
CommitLineData
1/** @file
2
3Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
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;
259
260 CoffEntry = 0;
261 mCoffOffset = 0;
262
263 //
264 // Coff file start with a DOS header.
265 //
266 mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;
267 mNtHdrOffset = mCoffOffset;
268 switch (mEhdr->e_machine) {
269 case EM_X86_64:
270 case EM_IA_64:
271 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);
272 break;
273 default:
274 VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);
275 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);
276 break;
277 }
278
279 mTableOffset = mCoffOffset;
280 mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);
281
282 //
283 // First text sections.
284 //
285 mCoffOffset = CoffAlign(mCoffOffset);
286 mTextOffset = mCoffOffset;
287 for (i = 0; i < mEhdr->e_shnum; i++) {
288 Elf_Shdr *shdr = GetShdrByIndex(i);
289 if (IsTextShdr(shdr)) {
290 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
291 // the alignment field is valid
292 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
293 // if the section address is aligned we must align PE/COFF
294 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));
295 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {
296 // ARM RVCT tools have behavior outside of the ELF specification to try
297 // and make images smaller. If sh_addr is not aligned to sh_addralign
298 // then the section needs to preserve sh_addr MOD sh_addralign.
299 // Normally doing nothing here works great.
300 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");
301 }
302 }
303
304 /* Relocate entry. */
305 if ((mEhdr->e_entry >= shdr->sh_addr) &&
306 (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
307 CoffEntry = (UINT32) (mCoffOffset + mEhdr->e_entry - shdr->sh_addr);
308 }
309 mCoffSectionsOffset[i] = mCoffOffset;
310 mCoffOffset += (UINT32) shdr->sh_size;
311 }
312 }
313
314 if (mEhdr->e_machine != EM_ARM) {
315 mCoffOffset = CoffAlign(mCoffOffset);
316 }
317
318 //
319 // Then data sections.
320 //
321 mDataOffset = mCoffOffset;
322 for (i = 0; i < mEhdr->e_shnum; i++) {
323 Elf_Shdr *shdr = GetShdrByIndex(i);
324 if (IsDataShdr(shdr)) {
325 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
326 // the alignment field is valid
327 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
328 // if the section address is aligned we must align PE/COFF
329 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));
330 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {
331 // ARM RVCT tools have behavior outside of the ELF specification to try
332 // and make images smaller. If sh_addr is not aligned to sh_addralign
333 // then the section needs to preserve sh_addr MOD sh_addralign.
334 // Normally doing nothing here works great.
335 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");
336 }
337 }
338 mCoffSectionsOffset[i] = mCoffOffset;
339 mCoffOffset += (UINT32) shdr->sh_size;
340 }
341 }
342 mCoffOffset = CoffAlign(mCoffOffset);
343
344 //
345 // The HII resource sections.
346 //
347 mHiiRsrcOffset = mCoffOffset;
348 for (i = 0; i < mEhdr->e_shnum; i++) {
349 Elf_Shdr *shdr = GetShdrByIndex(i);
350 if (IsHiiRsrcShdr(shdr)) {
351 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
352 // the alignment field is valid
353 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
354 // if the section address is aligned we must align PE/COFF
355 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));
356 } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {
357 // ARM RVCT tools have behavior outside of the ELF specification to try
358 // and make images smaller. If sh_addr is not aligned to sh_addralign
359 // then the section needs to preserve sh_addr MOD sh_addralign.
360 // Normally doing nothing here works great.
361 Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");
362 }
363 }
364 if (shdr->sh_size != 0) {
365 mCoffSectionsOffset[i] = mCoffOffset;
366 mCoffOffset += (UINT32) shdr->sh_size;
367 mCoffOffset = CoffAlign(mCoffOffset);
368 SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);
369 }
370 break;
371 }
372 }
373
374 mRelocOffset = mCoffOffset;
375
376 //
377 // Allocate base Coff file. Will be expanded later for relocations.
378 //
379 mCoffFile = (UINT8 *)malloc(mCoffOffset);
380 memset(mCoffFile, 0, mCoffOffset);
381
382 //
383 // Fill headers.
384 //
385 DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;
386 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
387 DosHdr->e_lfanew = mNtHdrOffset;
388
389 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);
390
391 NtHdr->Pe32Plus.Signature = EFI_IMAGE_NT_SIGNATURE;
392
393 switch (mEhdr->e_machine) {
394 case EM_X86_64:
395 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;
396 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
397 break;
398 case EM_IA_64:
399 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_IPF;
400 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
401 break;
402 default:
403 VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);
404 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;
405 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
406 }
407
408 NtHdr->Pe32Plus.FileHeader.NumberOfSections = mCoffNbrSections;
409 NtHdr->Pe32Plus.FileHeader.TimeDateStamp = (UINT32) time(NULL);
410 mImageTimeStamp = NtHdr->Pe32Plus.FileHeader.TimeDateStamp;
411 NtHdr->Pe32Plus.FileHeader.PointerToSymbolTable = 0;
412 NtHdr->Pe32Plus.FileHeader.NumberOfSymbols = 0;
413 NtHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32Plus.OptionalHeader);
414 NtHdr->Pe32Plus.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE
415 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
416 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
417 | EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE;
418
419 NtHdr->Pe32Plus.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;
420 NtHdr->Pe32Plus.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;
421 NtHdr->Pe32Plus.OptionalHeader.SizeOfUninitializedData = 0;
422 NtHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint = CoffEntry;
423
424 NtHdr->Pe32Plus.OptionalHeader.BaseOfCode = mTextOffset;
425
426 NtHdr->Pe32Plus.OptionalHeader.ImageBase = 0;
427 NtHdr->Pe32Plus.OptionalHeader.SectionAlignment = mCoffAlignment;
428 NtHdr->Pe32Plus.OptionalHeader.FileAlignment = mCoffAlignment;
429 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = 0;
430
431 NtHdr->Pe32Plus.OptionalHeader.SizeOfHeaders = mTextOffset;
432 NtHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
433
434 //
435 // Section headers.
436 //
437 if ((mDataOffset - mTextOffset) > 0) {
438 CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,
439 EFI_IMAGE_SCN_CNT_CODE
440 | EFI_IMAGE_SCN_MEM_EXECUTE
441 | EFI_IMAGE_SCN_MEM_READ);
442 } else {
443 // Don't make a section of size 0.
444 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;
445 }
446
447 if ((mHiiRsrcOffset - mDataOffset) > 0) {
448 CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,
449 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
450 | EFI_IMAGE_SCN_MEM_WRITE
451 | EFI_IMAGE_SCN_MEM_READ);
452 } else {
453 // Don't make a section of size 0.
454 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;
455 }
456
457 if ((mRelocOffset - mHiiRsrcOffset) > 0) {
458 CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,
459 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
460 | EFI_IMAGE_SCN_MEM_READ);
461
462 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;
463 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;
464 } else {
465 // Don't make a section of size 0.
466 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;
467 }
468
469}
470
471STATIC
472BOOLEAN
473WriteSections64 (
474 SECTION_FILTER_TYPES FilterType
475 )
476{
477 UINT32 Idx;
478 Elf_Shdr *SecShdr;
479 UINT32 SecOffset;
480 BOOLEAN (*Filter)(Elf_Shdr *);
481
482 //
483 // Initialize filter pointer
484 //
485 switch (FilterType) {
486 case SECTION_TEXT:
487 Filter = IsTextShdr;
488 break;
489 case SECTION_HII:
490 Filter = IsHiiRsrcShdr;
491 break;
492 case SECTION_DATA:
493 Filter = IsDataShdr;
494 break;
495 default:
496 return FALSE;
497 }
498
499 //
500 // First: copy sections.
501 //
502 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {
503 Elf_Shdr *Shdr = GetShdrByIndex(Idx);
504 if ((*Filter)(Shdr)) {
505 switch (Shdr->sh_type) {
506 case SHT_PROGBITS:
507 /* Copy. */
508 memcpy(mCoffFile + mCoffSectionsOffset[Idx],
509 (UINT8*)mEhdr + Shdr->sh_offset,
510 (size_t) Shdr->sh_size);
511 break;
512
513 case SHT_NOBITS:
514 memset(mCoffFile + mCoffSectionsOffset[Idx], 0, (size_t) Shdr->sh_size);
515 break;
516
517 default:
518 //
519 // Ignore for unkown section type.
520 //
521 VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type);
522 break;
523 }
524 }
525 }
526
527 //
528 // Second: apply relocations.
529 //
530 VerboseMsg ("Applying Relocations...");
531 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {
532 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
533 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {
534 continue;
535 }
536 SecShdr = GetShdrByIndex(RelShdr->sh_info);
537 SecOffset = mCoffSectionsOffset[RelShdr->sh_info];
538 if (RelShdr->sh_type == SHT_RELA && (*Filter)(SecShdr)) {
539 UINT64 RelIdx;
540 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
541 UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;
542 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINT32) RelShdr->sh_entsize) {
543 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);
544 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
545 Elf_Shdr *SymShdr;
546 UINT8 *Targ;
547
548 if (Sym->st_shndx == SHN_UNDEF
549 || Sym->st_shndx == SHN_ABS
550 || Sym->st_shndx > mEhdr->e_shnum) {
551 Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName);
552 }
553 SymShdr = GetShdrByIndex(Sym->st_shndx);
554
555 //
556 // Note: r_offset in a memory address.
557 // Convert it to a pointer in the coff file.
558 //
559 Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);
560
561 if (mEhdr->e_machine == EM_X86_64) {
562 switch (ELF_R_TYPE(Rel->r_info)) {
563 case R_X86_64_NONE:
564 break;
565 case R_X86_64_64:
566 //
567 // Absolute relocation.
568 //
569 VerboseMsg ("R_X86_64_64");
570 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX",
571 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),
572 *(UINT64 *)Targ);
573 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];
574 VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ);
575 break;
576 case R_X86_64_32:
577 VerboseMsg ("R_X86_64_32");
578 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",
579 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),
580 *(UINT32 *)Targ);
581 *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);
582 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);
583 break;
584 case R_X86_64_32S:
585 VerboseMsg ("R_X86_64_32S");
586 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",
587 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),
588 *(UINT32 *)Targ);
589 *(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);
590 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);
591 break;
592 case R_X86_64_PC32:
593 //
594 // Relative relocation: Symbol - Ip + Addend
595 //
596 VerboseMsg ("R_X86_64_PC32");
597 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",
598 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),
599 *(UINT32 *)Targ);
600 *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ
601 + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
602 - (SecOffset - SecShdr->sh_addr));
603 VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ);
604 break;
605 default:
606 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
607 }
608 } else {
609 Error (NULL, 0, 3000, "Invalid", "Not EM_X86_X64");
610 }
611 }
612 }
613 }
614
615 return TRUE;
616}
617
618STATIC
619VOID
620WriteRelocations64 (
621 VOID
622 )
623{
624 UINT32 Index;
625 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
626 EFI_IMAGE_DATA_DIRECTORY *Dir;
627 BOOLEAN FoundRelocations;
628 Elf_Sym *Sym;
629 Elf_Shdr *SymtabShdr;
630 UINT8 *Symtab;
631
632
633 for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {
634 Elf_Shdr *RelShdr = GetShdrByIndex(Index);
635 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {
636 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);
637 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
638 UINT64 RelIdx;
639
640 SymtabShdr = GetShdrByIndex (RelShdr->sh_link);
641 Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;
642 FoundRelocations = TRUE;
643 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
644 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);
645 Elf_Shdr *SymShdr;
646
647 Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
648 SymShdr = GetShdrByIndex (Sym->st_shndx);
649
650 if (mEhdr->e_machine == EM_X86_64) {
651 switch (ELF_R_TYPE(Rel->r_info)) {
652 case R_X86_64_NONE:
653 case R_X86_64_PC32:
654 break;
655 case R_X86_64_64:
656 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X",
657 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));
658 CoffAddFixup(
659 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]
660 + (Rel->r_offset - SecShdr->sh_addr)),
661 EFI_IMAGE_REL_BASED_DIR64);
662 break;
663 case R_X86_64_32S:
664 case R_X86_64_32:
665 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X",
666 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));
667 CoffAddFixup(
668 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]
669 + (Rel->r_offset - SecShdr->sh_addr)),
670 EFI_IMAGE_REL_BASED_HIGHLOW);
671 break;
672 default:
673 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
674 }
675 } else {
676 Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);
677 }
678 }
679 }
680 }
681 }
682
683 //
684 // Pad by adding empty entries.
685 //
686 while (mCoffOffset & (mCoffAlignment - 1)) {
687 CoffAddFixupEntry(0);
688 }
689
690 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
691 Dir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
692 Dir->Size = mCoffOffset - mRelocOffset;
693 if (Dir->Size == 0) {
694 // If no relocations, null out the directory entry and don't add the .reloc section
695 Dir->VirtualAddress = 0;
696 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;
697 } else {
698 Dir->VirtualAddress = mRelocOffset;
699 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,
700 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
701 | EFI_IMAGE_SCN_MEM_DISCARDABLE
702 | EFI_IMAGE_SCN_MEM_READ);
703 }
704}
705
706STATIC
707VOID
708WriteDebug64 (
709 VOID
710 )
711{
712 UINT32 Len;
713 UINT32 DebugOffset;
714 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
715 EFI_IMAGE_DATA_DIRECTORY *DataDir;
716 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
717 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
718
719 Len = strlen(mInImageName) + 1;
720 DebugOffset = mCoffOffset;
721
722 mCoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)
723 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)
724 + Len;
725 mCoffOffset = CoffAlign(mCoffOffset);
726
727 mCoffFile = realloc(mCoffFile, mCoffOffset);
728 memset(mCoffFile + DebugOffset, 0, mCoffOffset - DebugOffset);
729
730 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + DebugOffset);
731 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
732 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;
733 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
734 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
735
736 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
737 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
738 strcpy ((char *)(Nb10 + 1), mInImageName);
739
740
741 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
742 DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
743 DataDir->VirtualAddress = DebugOffset;
744 DataDir->Size = mCoffOffset - DebugOffset;
745 if (DataDir->Size == 0) {
746 // If no debug, null out the directory entry and don't add the .debug section
747 DataDir->VirtualAddress = 0;
748 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;
749 } else {
750 DataDir->VirtualAddress = DebugOffset;
751 CreateSectionHeader (".debug", DebugOffset, mCoffOffset - DebugOffset,
752 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
753 | EFI_IMAGE_SCN_MEM_DISCARDABLE
754 | EFI_IMAGE_SCN_MEM_READ);
755
756 }
757}
758
759STATIC
760VOID
761SetImageSize64 (
762 VOID
763 )
764{
765 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
766
767 //
768 // Set image size
769 //
770 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
771 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = mCoffOffset;
772}
773
774STATIC
775VOID
776CleanUp64 (
777 VOID
778 )
779{
780 if (mCoffSectionsOffset != NULL) {
781 free (mCoffSectionsOffset);
782 }
783}
784
785