]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/GenFw/Elf32Convert.c
BaseTools/GenFw: Fix a bug for GCC build
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf32Convert.c
1 /** @file
2 Elf32 Convert solution
3
4 Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2013, ARM Ltd. All rights reserved.<BR>
6
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "WinNtInclude.h"
18
19 #ifndef __GNUC__
20 #include <windows.h>
21 #include <io.h>
22 #endif
23 #include <assert.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <ctype.h>
30
31 #include <Common/UefiBaseTypes.h>
32 #include <IndustryStandard/PeImage.h>
33
34 #include "PeCoffLib.h"
35 #include "EfiUtilityMsgs.h"
36
37 #include "GenFw.h"
38 #include "ElfConvert.h"
39 #include "Elf32Convert.h"
40
41 STATIC
42 VOID
43 ScanSections32 (
44 VOID
45 );
46
47 STATIC
48 BOOLEAN
49 WriteSections32 (
50 SECTION_FILTER_TYPES FilterType
51 );
52
53 STATIC
54 VOID
55 WriteRelocations32 (
56 VOID
57 );
58
59 STATIC
60 VOID
61 WriteDebug32 (
62 VOID
63 );
64
65 STATIC
66 VOID
67 SetImageSize32 (
68 VOID
69 );
70
71 STATIC
72 VOID
73 CleanUp32 (
74 VOID
75 );
76
77 //
78 // Rename ELF32 strucutres to common names to help when porting to ELF64.
79 //
80 typedef Elf32_Shdr Elf_Shdr;
81 typedef Elf32_Ehdr Elf_Ehdr;
82 typedef Elf32_Rel Elf_Rel;
83 typedef Elf32_Sym Elf_Sym;
84 typedef Elf32_Phdr Elf_Phdr;
85 typedef Elf32_Dyn Elf_Dyn;
86 #define ELFCLASS ELFCLASS32
87 #define ELF_R_TYPE(r) ELF32_R_TYPE(r)
88 #define ELF_R_SYM(r) ELF32_R_SYM(r)
89
90 //
91 // Well known ELF structures.
92 //
93 STATIC Elf_Ehdr *mEhdr;
94 STATIC Elf_Shdr *mShdrBase;
95 STATIC Elf_Phdr *mPhdrBase;
96
97 //
98 // Coff information
99 //
100 STATIC UINT32 mCoffAlignment = 0x20;
101
102 //
103 // PE section alignment.
104 //
105 STATIC const UINT16 mCoffNbrSections = 4;
106
107 //
108 // ELF sections to offset in Coff file.
109 //
110 STATIC UINT32 *mCoffSectionsOffset = NULL;
111
112 //
113 // Offsets in COFF file
114 //
115 STATIC UINT32 mNtHdrOffset;
116 STATIC UINT32 mTextOffset;
117 STATIC UINT32 mDataOffset;
118 STATIC UINT32 mHiiRsrcOffset;
119 STATIC UINT32 mRelocOffset;
120 STATIC UINT32 mDebugOffset;
121
122 //
123 // Initialization Function
124 //
125 BOOLEAN
126 InitializeElf32 (
127 UINT8 *FileBuffer,
128 ELF_FUNCTION_TABLE *ElfFunctions
129 )
130 {
131 //
132 // Initialize data pointer and structures.
133 //
134 mEhdr = (Elf_Ehdr*) FileBuffer;
135
136 //
137 // Check the ELF32 specific header information.
138 //
139 if (mEhdr->e_ident[EI_CLASS] != ELFCLASS32) {
140 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFCLASS32");
141 return FALSE;
142 }
143 if (mEhdr->e_ident[EI_DATA] != ELFDATA2LSB) {
144 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB");
145 return FALSE;
146 }
147 if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) {
148 Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN");
149 return FALSE;
150 }
151 if (!((mEhdr->e_machine == EM_386) || (mEhdr->e_machine == EM_ARM))) {
152 Error (NULL, 0, 3000, "Unsupported", "ELF e_machine not EM_386 or EM_ARM");
153 return FALSE;
154 }
155 if (mEhdr->e_version != EV_CURRENT) {
156 Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT);
157 return FALSE;
158 }
159
160 //
161 // Update section header pointers
162 //
163 mShdrBase = (Elf_Shdr *)((UINT8 *)mEhdr + mEhdr->e_shoff);
164 mPhdrBase = (Elf_Phdr *)((UINT8 *)mEhdr + mEhdr->e_phoff);
165
166 //
167 // Create COFF Section offset buffer and zero.
168 //
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 ElfFunctions->ScanSections = ScanSections32;
176 ElfFunctions->WriteSections = WriteSections32;
177 ElfFunctions->WriteRelocations = WriteRelocations32;
178 ElfFunctions->WriteDebug = WriteDebug32;
179 ElfFunctions->SetImageSize = SetImageSize32;
180 ElfFunctions->CleanUp = CleanUp32;
181
182 return TRUE;
183 }
184
185
186 //
187 // Header by Index functions
188 //
189 STATIC
190 Elf_Shdr*
191 GetShdrByIndex (
192 UINT32 Num
193 )
194 {
195 if (Num >= mEhdr->e_shnum) {
196 Error (NULL, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num);
197 exit(EXIT_FAILURE);
198 }
199
200 return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);
201 }
202
203 STATIC
204 Elf_Phdr*
205 GetPhdrByIndex (
206 UINT32 num
207 )
208 {
209 if (num >= mEhdr->e_phnum) {
210 Error (NULL, 0, 3000, "Invalid", "GetPhdrByIndex: Index %u is too high.", num);
211 exit(EXIT_FAILURE);
212 }
213
214 return (Elf_Phdr *)((UINT8*)mPhdrBase + num * mEhdr->e_phentsize);
215 }
216
217 STATIC
218 UINT32
219 CoffAlign (
220 UINT32 Offset
221 )
222 {
223 return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);
224 }
225
226 STATIC
227 UINT32
228 DebugRvaAlign (
229 UINT32 Offset
230 )
231 {
232 return (Offset + 3) & ~3;
233 }
234
235 //
236 // filter functions
237 //
238 STATIC
239 BOOLEAN
240 IsTextShdr (
241 Elf_Shdr *Shdr
242 )
243 {
244 return (BOOLEAN) ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC);
245 }
246
247 STATIC
248 BOOLEAN
249 IsHiiRsrcShdr (
250 Elf_Shdr *Shdr
251 )
252 {
253 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);
254
255 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);
256 }
257
258 STATIC
259 BOOLEAN
260 IsDataShdr (
261 Elf_Shdr *Shdr
262 )
263 {
264 if (IsHiiRsrcShdr(Shdr)) {
265 return FALSE;
266 }
267 return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);
268 }
269
270 STATIC
271 BOOLEAN
272 IsStrtabShdr (
273 Elf_Shdr *Shdr
274 )
275 {
276 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);
277
278 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_STRTAB_SECTION_NAME) == 0);
279 }
280
281 STATIC
282 Elf_Shdr *
283 FindStrtabShdr (
284 VOID
285 )
286 {
287 UINT32 i;
288 for (i = 0; i < mEhdr->e_shnum; i++) {
289 Elf_Shdr *shdr = GetShdrByIndex(i);
290 if (IsStrtabShdr(shdr)) {
291 return shdr;
292 }
293 }
294 return NULL;
295 }
296
297 STATIC
298 const UINT8 *
299 GetSymName (
300 Elf_Sym *Sym
301 )
302 {
303 if (Sym->st_name == 0) {
304 return NULL;
305 }
306
307 Elf_Shdr *StrtabShdr = FindStrtabShdr();
308 if (StrtabShdr == NULL) {
309 return NULL;
310 }
311
312 assert(Sym->st_name < StrtabShdr->sh_size);
313
314 UINT8* StrtabContents = (UINT8*)mEhdr + StrtabShdr->sh_offset;
315
316 bool foundEnd = false;
317 UINT32 i;
318 for (i = Sym->st_name; (i < StrtabShdr->sh_size) && !foundEnd; i++) {
319 foundEnd = StrtabContents[i] == 0;
320 }
321 assert(foundEnd);
322
323 return StrtabContents + Sym->st_name;
324 }
325
326 //
327 // Elf functions interface implementation
328 //
329
330 STATIC
331 VOID
332 ScanSections32 (
333 VOID
334 )
335 {
336 UINT32 i;
337 EFI_IMAGE_DOS_HEADER *DosHdr;
338 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
339 UINT32 CoffEntry;
340 UINT32 SectionCount;
341 BOOLEAN FoundSection;
342
343 CoffEntry = 0;
344 mCoffOffset = 0;
345
346 //
347 // Coff file start with a DOS header.
348 //
349 mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;
350 mNtHdrOffset = mCoffOffset;
351 switch (mEhdr->e_machine) {
352 case EM_386:
353 case EM_ARM:
354 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32);
355 break;
356 default:
357 VerboseMsg ("%s unknown e_machine type. Assume IA-32", (UINTN)mEhdr->e_machine);
358 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32);
359 break;
360 }
361
362 mTableOffset = mCoffOffset;
363 mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);
364
365 //
366 // Set mCoffAlignment to the maximum alignment of the input sections
367 // we care about
368 //
369 for (i = 0; i < mEhdr->e_shnum; i++) {
370 Elf_Shdr *shdr = GetShdrByIndex(i);
371 if (shdr->sh_addralign <= mCoffAlignment) {
372 continue;
373 }
374 if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) {
375 mCoffAlignment = (UINT32)shdr->sh_addralign;
376 }
377 }
378
379 //
380 // Move the PE/COFF header right before the first section. This will help us
381 // save space when converting to TE.
382 //
383 if (mCoffAlignment > mCoffOffset) {
384 mNtHdrOffset += mCoffAlignment - mCoffOffset;
385 mTableOffset += mCoffAlignment - mCoffOffset;
386 mCoffOffset = mCoffAlignment;
387 }
388
389 //
390 // First text sections.
391 //
392 mCoffOffset = CoffAlign(mCoffOffset);
393 mTextOffset = mCoffOffset;
394 FoundSection = FALSE;
395 SectionCount = 0;
396 for (i = 0; i < mEhdr->e_shnum; i++) {
397 Elf_Shdr *shdr = GetShdrByIndex(i);
398 if (IsTextShdr(shdr)) {
399 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
400 // the alignment field is valid
401 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
402 // if the section address is aligned we must align PE/COFF
403 mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
404 } else {
405 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
406 }
407 }
408
409 /* Relocate entry. */
410 if ((mEhdr->e_entry >= shdr->sh_addr) &&
411 (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
412 CoffEntry = mCoffOffset + mEhdr->e_entry - shdr->sh_addr;
413 }
414
415 //
416 // Set mTextOffset with the offset of the first '.text' section
417 //
418 if (!FoundSection) {
419 mTextOffset = mCoffOffset;
420 FoundSection = TRUE;
421 }
422
423 mCoffSectionsOffset[i] = mCoffOffset;
424 mCoffOffset += shdr->sh_size;
425 SectionCount ++;
426 }
427 }
428
429 if (!FoundSection) {
430 Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");
431 assert (FALSE);
432 }
433
434 mDebugOffset = DebugRvaAlign(mCoffOffset);
435 mCoffOffset = CoffAlign(mCoffOffset);
436
437 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {
438 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);
439 }
440
441 //
442 // Then data sections.
443 //
444 mDataOffset = mCoffOffset;
445 FoundSection = FALSE;
446 SectionCount = 0;
447 for (i = 0; i < mEhdr->e_shnum; i++) {
448 Elf_Shdr *shdr = GetShdrByIndex(i);
449 if (IsDataShdr(shdr)) {
450 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
451 // the alignment field is valid
452 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
453 // if the section address is aligned we must align PE/COFF
454 mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
455 } else {
456 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
457 }
458 }
459
460 //
461 // Set mDataOffset with the offset of the first '.data' section
462 //
463 if (!FoundSection) {
464 mDataOffset = mCoffOffset;
465 FoundSection = TRUE;
466 }
467
468 mCoffSectionsOffset[i] = mCoffOffset;
469 mCoffOffset += shdr->sh_size;
470 SectionCount ++;
471 }
472 }
473
474 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {
475 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);
476 }
477
478 //
479 // Make room for .debug data in .data (or .text if .data is empty) instead of
480 // putting it in a section of its own. This is explicitly allowed by the
481 // PE/COFF spec, and prevents bloat in the binary when using large values for
482 // section alignment.
483 //
484 if (SectionCount > 0) {
485 mDebugOffset = DebugRvaAlign(mCoffOffset);
486 }
487 mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) +
488 sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) +
489 strlen(mInImageName) + 1;
490
491 mCoffOffset = CoffAlign(mCoffOffset);
492 if (SectionCount == 0) {
493 mDataOffset = mCoffOffset;
494 }
495
496 //
497 // The HII resource sections.
498 //
499 mHiiRsrcOffset = mCoffOffset;
500 for (i = 0; i < mEhdr->e_shnum; i++) {
501 Elf_Shdr *shdr = GetShdrByIndex(i);
502 if (IsHiiRsrcShdr(shdr)) {
503 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
504 // the alignment field is valid
505 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
506 // if the section address is aligned we must align PE/COFF
507 mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
508 } else {
509 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
510 }
511 }
512 if (shdr->sh_size != 0) {
513 mHiiRsrcOffset = mCoffOffset;
514 mCoffSectionsOffset[i] = mCoffOffset;
515 mCoffOffset += shdr->sh_size;
516 mCoffOffset = CoffAlign(mCoffOffset);
517 SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);
518 }
519 break;
520 }
521 }
522
523 mRelocOffset = mCoffOffset;
524
525 //
526 // Allocate base Coff file. Will be expanded later for relocations.
527 //
528 mCoffFile = (UINT8 *)malloc(mCoffOffset);
529 memset(mCoffFile, 0, mCoffOffset);
530
531 //
532 // Fill headers.
533 //
534 DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;
535 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
536 DosHdr->e_lfanew = mNtHdrOffset;
537
538 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);
539
540 NtHdr->Pe32.Signature = EFI_IMAGE_NT_SIGNATURE;
541
542 switch (mEhdr->e_machine) {
543 case EM_386:
544 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
545 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
546 break;
547 case EM_ARM:
548 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_ARMT;
549 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
550 break;
551 default:
552 VerboseMsg ("%s unknown e_machine type %hu. Assume IA-32", mInImageName, mEhdr->e_machine);
553 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
554 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
555 }
556
557 NtHdr->Pe32.FileHeader.NumberOfSections = mCoffNbrSections;
558 NtHdr->Pe32.FileHeader.TimeDateStamp = (UINT32) time(NULL);
559 mImageTimeStamp = NtHdr->Pe32.FileHeader.TimeDateStamp;
560 NtHdr->Pe32.FileHeader.PointerToSymbolTable = 0;
561 NtHdr->Pe32.FileHeader.NumberOfSymbols = 0;
562 NtHdr->Pe32.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32.OptionalHeader);
563 NtHdr->Pe32.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE
564 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
565 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
566 | EFI_IMAGE_FILE_32BIT_MACHINE;
567
568 NtHdr->Pe32.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;
569 NtHdr->Pe32.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;
570 NtHdr->Pe32.OptionalHeader.SizeOfUninitializedData = 0;
571 NtHdr->Pe32.OptionalHeader.AddressOfEntryPoint = CoffEntry;
572
573 NtHdr->Pe32.OptionalHeader.BaseOfCode = mTextOffset;
574
575 NtHdr->Pe32.OptionalHeader.BaseOfData = mDataOffset;
576 NtHdr->Pe32.OptionalHeader.ImageBase = 0;
577 NtHdr->Pe32.OptionalHeader.SectionAlignment = mCoffAlignment;
578 NtHdr->Pe32.OptionalHeader.FileAlignment = mCoffAlignment;
579 NtHdr->Pe32.OptionalHeader.SizeOfImage = 0;
580
581 NtHdr->Pe32.OptionalHeader.SizeOfHeaders = mTextOffset;
582 NtHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
583
584 //
585 // Section headers.
586 //
587 if ((mDataOffset - mTextOffset) > 0) {
588 CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,
589 EFI_IMAGE_SCN_CNT_CODE
590 | EFI_IMAGE_SCN_MEM_EXECUTE
591 | EFI_IMAGE_SCN_MEM_READ);
592 } else {
593 // Don't make a section of size 0.
594 NtHdr->Pe32.FileHeader.NumberOfSections--;
595 }
596
597 if ((mHiiRsrcOffset - mDataOffset) > 0) {
598 CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,
599 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
600 | EFI_IMAGE_SCN_MEM_WRITE
601 | EFI_IMAGE_SCN_MEM_READ);
602 } else {
603 // Don't make a section of size 0.
604 NtHdr->Pe32.FileHeader.NumberOfSections--;
605 }
606
607 if ((mRelocOffset - mHiiRsrcOffset) > 0) {
608 CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,
609 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
610 | EFI_IMAGE_SCN_MEM_READ);
611
612 NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;
613 NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;
614 } else {
615 // Don't make a section of size 0.
616 NtHdr->Pe32.FileHeader.NumberOfSections--;
617 }
618
619 }
620
621 STATIC
622 BOOLEAN
623 WriteSections32 (
624 SECTION_FILTER_TYPES FilterType
625 )
626 {
627 UINT32 Idx;
628 Elf_Shdr *SecShdr;
629 UINT32 SecOffset;
630 BOOLEAN (*Filter)(Elf_Shdr *);
631
632 //
633 // Initialize filter pointer
634 //
635 switch (FilterType) {
636 case SECTION_TEXT:
637 Filter = IsTextShdr;
638 break;
639 case SECTION_HII:
640 Filter = IsHiiRsrcShdr;
641 break;
642 case SECTION_DATA:
643 Filter = IsDataShdr;
644 break;
645 default:
646 return FALSE;
647 }
648
649 //
650 // First: copy sections.
651 //
652 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {
653 Elf_Shdr *Shdr = GetShdrByIndex(Idx);
654 if ((*Filter)(Shdr)) {
655 switch (Shdr->sh_type) {
656 case SHT_PROGBITS:
657 /* Copy. */
658 memcpy(mCoffFile + mCoffSectionsOffset[Idx],
659 (UINT8*)mEhdr + Shdr->sh_offset,
660 Shdr->sh_size);
661 break;
662
663 case SHT_NOBITS:
664 memset(mCoffFile + mCoffSectionsOffset[Idx], 0, Shdr->sh_size);
665 break;
666
667 default:
668 //
669 // Ignore for unkown section type.
670 //
671 VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type);
672 break;
673 }
674 }
675 }
676
677 //
678 // Second: apply relocations.
679 //
680 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {
681 //
682 // Determine if this is a relocation section.
683 //
684 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
685 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {
686 continue;
687 }
688
689 //
690 // Relocation section found. Now extract section information that the relocations
691 // apply to in the ELF data and the new COFF data.
692 //
693 SecShdr = GetShdrByIndex(RelShdr->sh_info);
694 SecOffset = mCoffSectionsOffset[RelShdr->sh_info];
695
696 //
697 // Only process relocations for the current filter type.
698 //
699 if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
700 UINT32 RelOffset;
701
702 //
703 // Determine the symbol table referenced by the relocation data.
704 //
705 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
706 UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;
707
708 //
709 // Process all relocation entries for this section.
710 //
711 for (RelOffset = 0; RelOffset < RelShdr->sh_size; RelOffset += RelShdr->sh_entsize) {
712 //
713 // Set pointer to relocation entry
714 //
715 Elf_Rel *Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelOffset);
716
717 //
718 // Set pointer to symbol table entry associated with the relocation entry.
719 //
720 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
721
722 Elf_Shdr *SymShdr;
723 UINT8 *Targ;
724 UINT16 Address;
725
726 //
727 // Check section header index found in symbol table and get the section
728 // header location.
729 //
730 if (Sym->st_shndx == SHN_UNDEF
731 || Sym->st_shndx >= mEhdr->e_shnum) {
732 const UINT8 *SymName = GetSymName(Sym);
733 if (SymName == NULL) {
734 SymName = (const UINT8 *)"<unknown>";
735 }
736
737 Error (NULL, 0, 3000, "Invalid",
738 "%s: Bad definition for symbol '%s'@%#x or unsupported symbol type. "
739 "For example, absolute and undefined symbols are not supported.",
740 mInImageName, SymName, Sym->st_value);
741
742 exit(EXIT_FAILURE);
743 }
744 SymShdr = GetShdrByIndex(Sym->st_shndx);
745
746 //
747 // Convert the relocation data to a pointer into the coff file.
748 //
749 // Note:
750 // r_offset is the virtual address of the storage unit to be relocated.
751 // sh_addr is the virtual address for the base of the section.
752 //
753 Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);
754
755 //
756 // Determine how to handle each relocation type based on the machine type.
757 //
758 if (mEhdr->e_machine == EM_386) {
759 switch (ELF_R_TYPE(Rel->r_info)) {
760 case R_386_NONE:
761 break;
762 case R_386_32:
763 //
764 // Absolute relocation.
765 // Converts Targ from a absolute virtual address to the absolute
766 // COFF address.
767 //
768 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr
769 + mCoffSectionsOffset[Sym->st_shndx];
770 break;
771 case R_386_PC32:
772 //
773 // Relative relocation: Symbol - Ip + Addend
774 //
775 *(UINT32 *)Targ = *(UINT32 *)Targ
776 + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
777 - (SecOffset - SecShdr->sh_addr);
778 break;
779 default:
780 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
781 }
782 } else if (mEhdr->e_machine == EM_ARM) {
783 switch (ELF32_R_TYPE(Rel->r_info)) {
784 case R_ARM_RBASE:
785 // No relocation - no action required
786 // break skipped
787
788 case R_ARM_PC24:
789 case R_ARM_REL32:
790 case R_ARM_XPC25:
791 case R_ARM_THM_PC22:
792 case R_ARM_THM_JUMP19:
793 case R_ARM_CALL:
794 case R_ARM_JMP24:
795 case R_ARM_THM_JUMP24:
796 case R_ARM_PREL31:
797 case R_ARM_MOVW_PREL_NC:
798 case R_ARM_MOVT_PREL:
799 case R_ARM_THM_MOVW_PREL_NC:
800 case R_ARM_THM_MOVT_PREL:
801 case R_ARM_THM_JMP6:
802 case R_ARM_THM_ALU_PREL_11_0:
803 case R_ARM_THM_PC12:
804 case R_ARM_REL32_NOI:
805 case R_ARM_ALU_PC_G0_NC:
806 case R_ARM_ALU_PC_G0:
807 case R_ARM_ALU_PC_G1_NC:
808 case R_ARM_ALU_PC_G1:
809 case R_ARM_ALU_PC_G2:
810 case R_ARM_LDR_PC_G1:
811 case R_ARM_LDR_PC_G2:
812 case R_ARM_LDRS_PC_G0:
813 case R_ARM_LDRS_PC_G1:
814 case R_ARM_LDRS_PC_G2:
815 case R_ARM_LDC_PC_G0:
816 case R_ARM_LDC_PC_G1:
817 case R_ARM_LDC_PC_G2:
818 case R_ARM_GOT_PREL:
819 case R_ARM_THM_JUMP11:
820 case R_ARM_THM_JUMP8:
821 case R_ARM_TLS_GD32:
822 case R_ARM_TLS_LDM32:
823 case R_ARM_TLS_IE32:
824 // Thease are all PC-relative relocations and don't require modification
825 // GCC does not seem to have the concept of a application that just needs to get relocated.
826 break;
827
828 case R_ARM_THM_MOVW_ABS_NC:
829 // MOVW is only lower 16-bits of the addres
830 Address = (UINT16)(Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);
831 ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
832 break;
833
834 case R_ARM_THM_MOVT_ABS:
835 // MOVT is only upper 16-bits of the addres
836 Address = (UINT16)((Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]) >> 16);
837 ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
838 break;
839
840 case R_ARM_ABS32:
841 case R_ARM_RABS32:
842 //
843 // Absolute relocation.
844 //
845 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];
846 break;
847
848 default:
849 Error (NULL, 0, 3000, "Invalid", "WriteSections (): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));
850 }
851 }
852 }
853 }
854 }
855
856 return TRUE;
857 }
858
859 UINTN gMovwOffset = 0;
860
861 STATIC
862 VOID
863 WriteRelocations32 (
864 VOID
865 )
866 {
867 UINT32 Index;
868 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
869 EFI_IMAGE_DATA_DIRECTORY *Dir;
870 BOOLEAN FoundRelocations;
871 Elf_Dyn *Dyn;
872 Elf_Rel *Rel;
873 UINTN RelElementSize;
874 UINTN RelSize;
875 UINTN RelOffset;
876 UINTN K;
877 Elf32_Phdr *DynamicSegment;
878
879 for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {
880 Elf_Shdr *RelShdr = GetShdrByIndex(Index);
881 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {
882 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);
883 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
884 UINT32 RelIdx;
885
886 FoundRelocations = TRUE;
887 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
888 Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);
889
890 if (mEhdr->e_machine == EM_386) {
891 switch (ELF_R_TYPE(Rel->r_info)) {
892 case R_386_NONE:
893 case R_386_PC32:
894 //
895 // No fixup entry required.
896 //
897 break;
898 case R_386_32:
899 //
900 // Creates a relative relocation entry from the absolute entry.
901 //
902 CoffAddFixup(mCoffSectionsOffset[RelShdr->sh_info]
903 + (Rel->r_offset - SecShdr->sh_addr),
904 EFI_IMAGE_REL_BASED_HIGHLOW);
905 break;
906 default:
907 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
908 }
909 } else if (mEhdr->e_machine == EM_ARM) {
910 switch (ELF32_R_TYPE(Rel->r_info)) {
911 case R_ARM_RBASE:
912 // No relocation - no action required
913 // break skipped
914
915 case R_ARM_PC24:
916 case R_ARM_REL32:
917 case R_ARM_XPC25:
918 case R_ARM_THM_PC22:
919 case R_ARM_THM_JUMP19:
920 case R_ARM_CALL:
921 case R_ARM_JMP24:
922 case R_ARM_THM_JUMP24:
923 case R_ARM_PREL31:
924 case R_ARM_MOVW_PREL_NC:
925 case R_ARM_MOVT_PREL:
926 case R_ARM_THM_MOVW_PREL_NC:
927 case R_ARM_THM_MOVT_PREL:
928 case R_ARM_THM_JMP6:
929 case R_ARM_THM_ALU_PREL_11_0:
930 case R_ARM_THM_PC12:
931 case R_ARM_REL32_NOI:
932 case R_ARM_ALU_PC_G0_NC:
933 case R_ARM_ALU_PC_G0:
934 case R_ARM_ALU_PC_G1_NC:
935 case R_ARM_ALU_PC_G1:
936 case R_ARM_ALU_PC_G2:
937 case R_ARM_LDR_PC_G1:
938 case R_ARM_LDR_PC_G2:
939 case R_ARM_LDRS_PC_G0:
940 case R_ARM_LDRS_PC_G1:
941 case R_ARM_LDRS_PC_G2:
942 case R_ARM_LDC_PC_G0:
943 case R_ARM_LDC_PC_G1:
944 case R_ARM_LDC_PC_G2:
945 case R_ARM_GOT_PREL:
946 case R_ARM_THM_JUMP11:
947 case R_ARM_THM_JUMP8:
948 case R_ARM_TLS_GD32:
949 case R_ARM_TLS_LDM32:
950 case R_ARM_TLS_IE32:
951 // Thease are all PC-relative relocations and don't require modification
952 break;
953
954 case R_ARM_THM_MOVW_ABS_NC:
955 CoffAddFixup (
956 mCoffSectionsOffset[RelShdr->sh_info]
957 + (Rel->r_offset - SecShdr->sh_addr),
958 EFI_IMAGE_REL_BASED_ARM_MOV32T
959 );
960
961 // PE/COFF treats MOVW/MOVT relocation as single 64-bit instruction
962 // Track this address so we can log an error for unsupported sequence of MOVW/MOVT
963 gMovwOffset = mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr);
964 break;
965
966 case R_ARM_THM_MOVT_ABS:
967 if ((gMovwOffset + 4) != (mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr))) {
968 Error (NULL, 0, 3000, "Not Supported", "PE/COFF requires MOVW+MOVT instruction sequence %x +4 != %x.", gMovwOffset, mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));
969 }
970 break;
971
972 case R_ARM_ABS32:
973 case R_ARM_RABS32:
974 CoffAddFixup (
975 mCoffSectionsOffset[RelShdr->sh_info]
976 + (Rel->r_offset - SecShdr->sh_addr),
977 EFI_IMAGE_REL_BASED_HIGHLOW
978 );
979 break;
980
981 default:
982 Error (NULL, 0, 3000, "Invalid", "WriteRelocations(): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));
983 }
984 } else {
985 Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);
986 }
987 }
988 }
989 }
990 }
991
992 if (!FoundRelocations && (mEhdr->e_machine == EM_ARM)) {
993 /* Try again, but look for PT_DYNAMIC instead of SHT_REL */
994
995 for (Index = 0; Index < mEhdr->e_phnum; Index++) {
996 RelElementSize = 0;
997 RelSize = 0;
998 RelOffset = 0;
999
1000 DynamicSegment = GetPhdrByIndex (Index);
1001
1002 if (DynamicSegment->p_type == PT_DYNAMIC) {
1003 Dyn = (Elf32_Dyn *) ((UINT8 *)mEhdr + DynamicSegment->p_offset);
1004
1005 while (Dyn->d_tag != DT_NULL) {
1006 switch (Dyn->d_tag) {
1007 case DT_REL:
1008 RelOffset = Dyn->d_un.d_val;
1009 break;
1010
1011 case DT_RELSZ:
1012 RelSize = Dyn->d_un.d_val;
1013 break;
1014
1015 case DT_RELENT:
1016 RelElementSize = Dyn->d_un.d_val;
1017 break;
1018
1019 default:
1020 break;
1021 }
1022 Dyn++;
1023 }
1024 if (( RelOffset == 0 ) || ( RelSize == 0 ) || ( RelElementSize == 0 )) {
1025 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName);
1026 }
1027
1028 for (Index = 0; Index < mEhdr->e_shnum; Index++) {
1029 Elf_Shdr *shdr = GetShdrByIndex(Index);
1030
1031 //
1032 // The PT_DYNAMIC section contains DT_REL relocations whose r_offset
1033 // field is relative to the base of a segment (or the entire image),
1034 // and not to the base of an ELF input section as is the case for
1035 // SHT_REL sections. This means that we cannot fix up such relocations
1036 // unless we cross-reference ELF sections and segments, considering
1037 // that the output placement recorded in mCoffSectionsOffset[] is
1038 // section based, not segment based.
1039 //
1040 // Fortunately, there is a simple way around this: we require that the
1041 // in-memory layout of the ELF and PE/COFF versions of the binary is
1042 // identical. That way, r_offset will retain its validity as a PE/COFF
1043 // image offset, and we can record it in the COFF fixup table
1044 // unmodified.
1045 //
1046 if (shdr->sh_addr != mCoffSectionsOffset[Index]) {
1047 Error (NULL, 0, 3000,
1048 "Invalid", "%s: PT_DYNAMIC relocations require identical ELF and PE/COFF section offsets.",
1049 mInImageName);
1050 }
1051 }
1052
1053 for (K = 0; K < RelSize; K += RelElementSize) {
1054
1055 if (DynamicSegment->p_paddr == 0) {
1056 // Older versions of the ARM ELF (SWS ESPC 0003 B-02) specification define DT_REL
1057 // as an offset in the dynamic segment. p_paddr is defined to be zero for ARM tools
1058 Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + DynamicSegment->p_offset + RelOffset + K);
1059 } else {
1060 // This is how it reads in the generic ELF specification
1061 Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + RelOffset + K);
1062 }
1063
1064 switch (ELF32_R_TYPE (Rel->r_info)) {
1065 case R_ARM_RBASE:
1066 break;
1067
1068 case R_ARM_RABS32:
1069 CoffAddFixup (Rel->r_offset, EFI_IMAGE_REL_BASED_HIGHLOW);
1070 break;
1071
1072 default:
1073 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations, unkown type %d.", mInImageName, ELF32_R_TYPE (Rel->r_info));
1074 break;
1075 }
1076 }
1077 break;
1078 }
1079 }
1080 }
1081
1082 //
1083 // Pad by adding empty entries.
1084 //
1085 while (mCoffOffset & (mCoffAlignment - 1)) {
1086 CoffAddFixupEntry(0);
1087 }
1088
1089 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
1090 Dir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1091 Dir->Size = mCoffOffset - mRelocOffset;
1092 if (Dir->Size == 0) {
1093 // If no relocations, null out the directory entry and don't add the .reloc section
1094 Dir->VirtualAddress = 0;
1095 NtHdr->Pe32.FileHeader.NumberOfSections--;
1096 } else {
1097 Dir->VirtualAddress = mRelocOffset;
1098 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,
1099 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
1100 | EFI_IMAGE_SCN_MEM_DISCARDABLE
1101 | EFI_IMAGE_SCN_MEM_READ);
1102 }
1103
1104 }
1105
1106 STATIC
1107 VOID
1108 WriteDebug32 (
1109 VOID
1110 )
1111 {
1112 UINT32 Len;
1113 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
1114 EFI_IMAGE_DATA_DIRECTORY *DataDir;
1115 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
1116 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
1117
1118 Len = strlen(mInImageName) + 1;
1119
1120 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);
1121 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
1122 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;
1123 Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
1124 Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
1125
1126 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
1127 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
1128 strcpy ((char *)(Nb10 + 1), mInImageName);
1129
1130
1131 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
1132 DataDir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
1133 DataDir->VirtualAddress = mDebugOffset;
1134 DataDir->Size = Dir->SizeOfData + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
1135 }
1136
1137 STATIC
1138 VOID
1139 SetImageSize32 (
1140 VOID
1141 )
1142 {
1143 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
1144
1145 //
1146 // Set image size
1147 //
1148 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
1149 NtHdr->Pe32.OptionalHeader.SizeOfImage = mCoffOffset;
1150 }
1151
1152 STATIC
1153 VOID
1154 CleanUp32 (
1155 VOID
1156 )
1157 {
1158 if (mCoffSectionsOffset != NULL) {
1159 free (mCoffSectionsOffset);
1160 }
1161 }
1162
1163