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