]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/GenFw/Elf64Convert.c
Sync BaseTools Branch (version r2149) to EDKII main trunk.
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
1 /** @file
2
3 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
4
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT 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
37 STATIC
38 VOID
39 ScanSections64 (
40 VOID
41 );
42
43 STATIC
44 BOOLEAN
45 WriteSections64 (
46 SECTION_FILTER_TYPES FilterType
47 );
48
49 STATIC
50 VOID
51 WriteRelocations64 (
52 VOID
53 );
54
55 STATIC
56 VOID
57 WriteDebug64 (
58 VOID
59 );
60
61 STATIC
62 VOID
63 SetImageSize64 (
64 VOID
65 );
66
67 STATIC
68 VOID
69 CleanUp64 (
70 VOID
71 );
72
73 //
74 // Rename ELF32 strucutres to common names to help when porting to ELF64.
75 //
76 typedef Elf64_Shdr Elf_Shdr;
77 typedef Elf64_Ehdr Elf_Ehdr;
78 typedef Elf64_Rel Elf_Rel;
79 typedef Elf64_Rela Elf_Rela;
80 typedef Elf64_Sym Elf_Sym;
81 typedef Elf64_Phdr Elf_Phdr;
82 typedef 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 //
90 STATIC Elf_Ehdr *mEhdr;
91 STATIC Elf_Shdr *mShdrBase;
92 STATIC Elf_Phdr *mPhdrBase;
93
94 //
95 // Coff information
96 //
97 STATIC const UINT32 mCoffAlignment = 0x20;
98
99 //
100 // PE section alignment.
101 //
102 STATIC const UINT16 mCoffNbrSections = 5;
103
104 //
105 // ELF sections to offset in Coff file.
106 //
107 STATIC UINT32 *mCoffSectionsOffset = NULL;
108
109 //
110 // Offsets in COFF file
111 //
112 STATIC UINT32 mNtHdrOffset;
113 STATIC UINT32 mTextOffset;
114 STATIC UINT32 mDataOffset;
115 STATIC UINT32 mHiiRsrcOffset;
116 STATIC UINT32 mRelocOffset;
117
118 //
119 // Initialization Function
120 //
121 BOOLEAN
122 InitializeElf64 (
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 //
190 STATIC
191 Elf_Shdr*
192 GetShdrByIndex (
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
201 STATIC
202 UINT32
203 CoffAlign (
204 UINT32 Offset
205 )
206 {
207 return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);
208 }
209
210 //
211 // filter functions
212 //
213 STATIC
214 BOOLEAN
215 IsTextShdr (
216 Elf_Shdr *Shdr
217 )
218 {
219 return (BOOLEAN) ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC);
220 }
221
222 STATIC
223 BOOLEAN
224 IsHiiRsrcShdr (
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
233 STATIC
234 BOOLEAN
235 IsDataShdr (
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
249 STATIC
250 VOID
251 ScanSections64 (
252 VOID
253 )
254 {
255 UINT32 i;
256 EFI_IMAGE_DOS_HEADER *DosHdr;
257 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
258 UINT32 CoffEntry;
259 UINT32 SectionCount;
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;
288 SectionCount = 0;
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;
313 SectionCount ++;
314 }
315 }
316
317 if (mEhdr->e_machine != EM_ARM) {
318 mCoffOffset = CoffAlign(mCoffOffset);
319 }
320
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
325 //
326 // Then data sections.
327 //
328 mDataOffset = mCoffOffset;
329 SectionCount = 0;
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;
348 SectionCount ++;
349 }
350 }
351 mCoffOffset = CoffAlign(mCoffOffset);
352
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
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
484 STATIC
485 BOOLEAN
486 WriteSections64 (
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
631 STATIC
632 VOID
633 WriteRelocations64 (
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
719 STATIC
720 VOID
721 WriteDebug64 (
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
772 STATIC
773 VOID
774 SetImageSize64 (
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
787 STATIC
788 VOID
789 CleanUp64 (
790 VOID
791 )
792 {
793 if (mCoffSectionsOffset != NULL) {
794 free (mCoffSectionsOffset);
795 }
796 }
797
798