]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/GenFw/Elf32Convert.c
BaseTools/GenFw: Exit with error when header lookup fails
[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 //
270 // Elf functions interface implementation
271 //
272
273 STATIC
274 VOID
275 ScanSections32 (
276 VOID
277 )
278 {
279 UINT32 i;
280 EFI_IMAGE_DOS_HEADER *DosHdr;
281 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
282 UINT32 CoffEntry;
283 UINT32 SectionCount;
284 BOOLEAN FoundSection;
285
286 CoffEntry = 0;
287 mCoffOffset = 0;
288
289 //
290 // Coff file start with a DOS header.
291 //
292 mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;
293 mNtHdrOffset = mCoffOffset;
294 switch (mEhdr->e_machine) {
295 case EM_386:
296 case EM_ARM:
297 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32);
298 break;
299 default:
300 VerboseMsg ("%s unknown e_machine type. Assume IA-32", (UINTN)mEhdr->e_machine);
301 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32);
302 break;
303 }
304
305 mTableOffset = mCoffOffset;
306 mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);
307
308 //
309 // Set mCoffAlignment to the maximum alignment of the input sections
310 // we care about
311 //
312 for (i = 0; i < mEhdr->e_shnum; i++) {
313 Elf_Shdr *shdr = GetShdrByIndex(i);
314 if (shdr->sh_addralign <= mCoffAlignment) {
315 continue;
316 }
317 if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) {
318 mCoffAlignment = (UINT32)shdr->sh_addralign;
319 }
320 }
321
322 //
323 // Move the PE/COFF header right before the first section. This will help us
324 // save space when converting to TE.
325 //
326 if (mCoffAlignment > mCoffOffset) {
327 mNtHdrOffset += mCoffAlignment - mCoffOffset;
328 mTableOffset += mCoffAlignment - mCoffOffset;
329 mCoffOffset = mCoffAlignment;
330 }
331
332 //
333 // First text sections.
334 //
335 mCoffOffset = CoffAlign(mCoffOffset);
336 mTextOffset = mCoffOffset;
337 FoundSection = FALSE;
338 SectionCount = 0;
339 for (i = 0; i < mEhdr->e_shnum; i++) {
340 Elf_Shdr *shdr = GetShdrByIndex(i);
341 if (IsTextShdr(shdr)) {
342 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
343 // the alignment field is valid
344 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
345 // if the section address is aligned we must align PE/COFF
346 mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
347 } else {
348 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
349 }
350 }
351
352 /* Relocate entry. */
353 if ((mEhdr->e_entry >= shdr->sh_addr) &&
354 (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
355 CoffEntry = mCoffOffset + mEhdr->e_entry - shdr->sh_addr;
356 }
357
358 //
359 // Set mTextOffset with the offset of the first '.text' section
360 //
361 if (!FoundSection) {
362 mTextOffset = mCoffOffset;
363 FoundSection = TRUE;
364 }
365
366 mCoffSectionsOffset[i] = mCoffOffset;
367 mCoffOffset += shdr->sh_size;
368 SectionCount ++;
369 }
370 }
371
372 if (!FoundSection) {
373 Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");
374 assert (FALSE);
375 }
376
377 mDebugOffset = DebugRvaAlign(mCoffOffset);
378 mCoffOffset = CoffAlign(mCoffOffset);
379
380 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {
381 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);
382 }
383
384 //
385 // Then data sections.
386 //
387 mDataOffset = mCoffOffset;
388 FoundSection = FALSE;
389 SectionCount = 0;
390 for (i = 0; i < mEhdr->e_shnum; i++) {
391 Elf_Shdr *shdr = GetShdrByIndex(i);
392 if (IsDataShdr(shdr)) {
393 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
394 // the alignment field is valid
395 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
396 // if the section address is aligned we must align PE/COFF
397 mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
398 } else {
399 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
400 }
401 }
402
403 //
404 // Set mDataOffset with the offset of the first '.data' section
405 //
406 if (!FoundSection) {
407 mDataOffset = mCoffOffset;
408 FoundSection = TRUE;
409 }
410
411 mCoffSectionsOffset[i] = mCoffOffset;
412 mCoffOffset += shdr->sh_size;
413 SectionCount ++;
414 }
415 }
416
417 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {
418 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);
419 }
420
421 //
422 // Make room for .debug data in .data (or .text if .data is empty) instead of
423 // putting it in a section of its own. This is explicitly allowed by the
424 // PE/COFF spec, and prevents bloat in the binary when using large values for
425 // section alignment.
426 //
427 if (SectionCount > 0) {
428 mDebugOffset = DebugRvaAlign(mCoffOffset);
429 }
430 mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) +
431 sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) +
432 strlen(mInImageName) + 1;
433
434 mCoffOffset = CoffAlign(mCoffOffset);
435 if (SectionCount == 0) {
436 mDataOffset = mCoffOffset;
437 }
438
439 //
440 // The HII resource sections.
441 //
442 mHiiRsrcOffset = mCoffOffset;
443 for (i = 0; i < mEhdr->e_shnum; i++) {
444 Elf_Shdr *shdr = GetShdrByIndex(i);
445 if (IsHiiRsrcShdr(shdr)) {
446 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
447 // the alignment field is valid
448 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
449 // if the section address is aligned we must align PE/COFF
450 mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
451 } else {
452 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
453 }
454 }
455 if (shdr->sh_size != 0) {
456 mHiiRsrcOffset = mCoffOffset;
457 mCoffSectionsOffset[i] = mCoffOffset;
458 mCoffOffset += shdr->sh_size;
459 mCoffOffset = CoffAlign(mCoffOffset);
460 SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);
461 }
462 break;
463 }
464 }
465
466 mRelocOffset = mCoffOffset;
467
468 //
469 // Allocate base Coff file. Will be expanded later for relocations.
470 //
471 mCoffFile = (UINT8 *)malloc(mCoffOffset);
472 memset(mCoffFile, 0, mCoffOffset);
473
474 //
475 // Fill headers.
476 //
477 DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;
478 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
479 DosHdr->e_lfanew = mNtHdrOffset;
480
481 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);
482
483 NtHdr->Pe32.Signature = EFI_IMAGE_NT_SIGNATURE;
484
485 switch (mEhdr->e_machine) {
486 case EM_386:
487 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
488 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
489 break;
490 case EM_ARM:
491 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_ARMT;
492 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
493 break;
494 default:
495 VerboseMsg ("%s unknown e_machine type. Assume IA-32", (UINTN)mEhdr->e_machine);
496 NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
497 NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
498 }
499
500 NtHdr->Pe32.FileHeader.NumberOfSections = mCoffNbrSections;
501 NtHdr->Pe32.FileHeader.TimeDateStamp = (UINT32) time(NULL);
502 mImageTimeStamp = NtHdr->Pe32.FileHeader.TimeDateStamp;
503 NtHdr->Pe32.FileHeader.PointerToSymbolTable = 0;
504 NtHdr->Pe32.FileHeader.NumberOfSymbols = 0;
505 NtHdr->Pe32.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32.OptionalHeader);
506 NtHdr->Pe32.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE
507 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
508 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
509 | EFI_IMAGE_FILE_32BIT_MACHINE;
510
511 NtHdr->Pe32.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;
512 NtHdr->Pe32.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;
513 NtHdr->Pe32.OptionalHeader.SizeOfUninitializedData = 0;
514 NtHdr->Pe32.OptionalHeader.AddressOfEntryPoint = CoffEntry;
515
516 NtHdr->Pe32.OptionalHeader.BaseOfCode = mTextOffset;
517
518 NtHdr->Pe32.OptionalHeader.BaseOfData = mDataOffset;
519 NtHdr->Pe32.OptionalHeader.ImageBase = 0;
520 NtHdr->Pe32.OptionalHeader.SectionAlignment = mCoffAlignment;
521 NtHdr->Pe32.OptionalHeader.FileAlignment = mCoffAlignment;
522 NtHdr->Pe32.OptionalHeader.SizeOfImage = 0;
523
524 NtHdr->Pe32.OptionalHeader.SizeOfHeaders = mTextOffset;
525 NtHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
526
527 //
528 // Section headers.
529 //
530 if ((mDataOffset - mTextOffset) > 0) {
531 CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,
532 EFI_IMAGE_SCN_CNT_CODE
533 | EFI_IMAGE_SCN_MEM_EXECUTE
534 | EFI_IMAGE_SCN_MEM_READ);
535 } else {
536 // Don't make a section of size 0.
537 NtHdr->Pe32.FileHeader.NumberOfSections--;
538 }
539
540 if ((mHiiRsrcOffset - mDataOffset) > 0) {
541 CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,
542 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
543 | EFI_IMAGE_SCN_MEM_WRITE
544 | EFI_IMAGE_SCN_MEM_READ);
545 } else {
546 // Don't make a section of size 0.
547 NtHdr->Pe32.FileHeader.NumberOfSections--;
548 }
549
550 if ((mRelocOffset - mHiiRsrcOffset) > 0) {
551 CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,
552 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
553 | EFI_IMAGE_SCN_MEM_READ);
554
555 NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;
556 NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;
557 } else {
558 // Don't make a section of size 0.
559 NtHdr->Pe32.FileHeader.NumberOfSections--;
560 }
561
562 }
563
564 STATIC
565 BOOLEAN
566 WriteSections32 (
567 SECTION_FILTER_TYPES FilterType
568 )
569 {
570 UINT32 Idx;
571 Elf_Shdr *SecShdr;
572 UINT32 SecOffset;
573 BOOLEAN (*Filter)(Elf_Shdr *);
574
575 //
576 // Initialize filter pointer
577 //
578 switch (FilterType) {
579 case SECTION_TEXT:
580 Filter = IsTextShdr;
581 break;
582 case SECTION_HII:
583 Filter = IsHiiRsrcShdr;
584 break;
585 case SECTION_DATA:
586 Filter = IsDataShdr;
587 break;
588 default:
589 return FALSE;
590 }
591
592 //
593 // First: copy sections.
594 //
595 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {
596 Elf_Shdr *Shdr = GetShdrByIndex(Idx);
597 if ((*Filter)(Shdr)) {
598 switch (Shdr->sh_type) {
599 case SHT_PROGBITS:
600 /* Copy. */
601 memcpy(mCoffFile + mCoffSectionsOffset[Idx],
602 (UINT8*)mEhdr + Shdr->sh_offset,
603 Shdr->sh_size);
604 break;
605
606 case SHT_NOBITS:
607 memset(mCoffFile + mCoffSectionsOffset[Idx], 0, Shdr->sh_size);
608 break;
609
610 default:
611 //
612 // Ignore for unkown section type.
613 //
614 VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type);
615 break;
616 }
617 }
618 }
619
620 //
621 // Second: apply relocations.
622 //
623 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {
624 //
625 // Determine if this is a relocation section.
626 //
627 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
628 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {
629 continue;
630 }
631
632 //
633 // Relocation section found. Now extract section information that the relocations
634 // apply to in the ELF data and the new COFF data.
635 //
636 SecShdr = GetShdrByIndex(RelShdr->sh_info);
637 SecOffset = mCoffSectionsOffset[RelShdr->sh_info];
638
639 //
640 // Only process relocations for the current filter type.
641 //
642 if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
643 UINT32 RelOffset;
644
645 //
646 // Determine the symbol table referenced by the relocation data.
647 //
648 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
649 UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;
650
651 //
652 // Process all relocation entries for this section.
653 //
654 for (RelOffset = 0; RelOffset < RelShdr->sh_size; RelOffset += RelShdr->sh_entsize) {
655 //
656 // Set pointer to relocation entry
657 //
658 Elf_Rel *Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelOffset);
659
660 //
661 // Set pointer to symbol table entry associated with the relocation entry.
662 //
663 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
664
665 Elf_Shdr *SymShdr;
666 UINT8 *Targ;
667 UINT16 Address;
668
669 //
670 // Check section header index found in symbol table and get the section
671 // header location.
672 //
673 if (Sym->st_shndx == SHN_UNDEF
674 || Sym->st_shndx == SHN_ABS
675 || Sym->st_shndx > mEhdr->e_shnum) {
676 Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName);
677 }
678 SymShdr = GetShdrByIndex(Sym->st_shndx);
679
680 //
681 // Convert the relocation data to a pointer into the coff file.
682 //
683 // Note:
684 // r_offset is the virtual address of the storage unit to be relocated.
685 // sh_addr is the virtual address for the base of the section.
686 //
687 Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);
688
689 //
690 // Determine how to handle each relocation type based on the machine type.
691 //
692 if (mEhdr->e_machine == EM_386) {
693 switch (ELF_R_TYPE(Rel->r_info)) {
694 case R_386_NONE:
695 break;
696 case R_386_32:
697 //
698 // Absolute relocation.
699 // Converts Targ from a absolute virtual address to the absolute
700 // COFF address.
701 //
702 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr
703 + mCoffSectionsOffset[Sym->st_shndx];
704 break;
705 case R_386_PC32:
706 //
707 // Relative relocation: Symbol - Ip + Addend
708 //
709 *(UINT32 *)Targ = *(UINT32 *)Targ
710 + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
711 - (SecOffset - SecShdr->sh_addr);
712 break;
713 default:
714 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
715 }
716 } else if (mEhdr->e_machine == EM_ARM) {
717 switch (ELF32_R_TYPE(Rel->r_info)) {
718 case R_ARM_RBASE:
719 // No relocation - no action required
720 // break skipped
721
722 case R_ARM_PC24:
723 case R_ARM_REL32:
724 case R_ARM_XPC25:
725 case R_ARM_THM_PC22:
726 case R_ARM_THM_JUMP19:
727 case R_ARM_CALL:
728 case R_ARM_JMP24:
729 case R_ARM_THM_JUMP24:
730 case R_ARM_PREL31:
731 case R_ARM_MOVW_PREL_NC:
732 case R_ARM_MOVT_PREL:
733 case R_ARM_THM_MOVW_PREL_NC:
734 case R_ARM_THM_MOVT_PREL:
735 case R_ARM_THM_JMP6:
736 case R_ARM_THM_ALU_PREL_11_0:
737 case R_ARM_THM_PC12:
738 case R_ARM_REL32_NOI:
739 case R_ARM_ALU_PC_G0_NC:
740 case R_ARM_ALU_PC_G0:
741 case R_ARM_ALU_PC_G1_NC:
742 case R_ARM_ALU_PC_G1:
743 case R_ARM_ALU_PC_G2:
744 case R_ARM_LDR_PC_G1:
745 case R_ARM_LDR_PC_G2:
746 case R_ARM_LDRS_PC_G0:
747 case R_ARM_LDRS_PC_G1:
748 case R_ARM_LDRS_PC_G2:
749 case R_ARM_LDC_PC_G0:
750 case R_ARM_LDC_PC_G1:
751 case R_ARM_LDC_PC_G2:
752 case R_ARM_GOT_PREL:
753 case R_ARM_THM_JUMP11:
754 case R_ARM_THM_JUMP8:
755 case R_ARM_TLS_GD32:
756 case R_ARM_TLS_LDM32:
757 case R_ARM_TLS_IE32:
758 // Thease are all PC-relative relocations and don't require modification
759 // GCC does not seem to have the concept of a application that just needs to get relocated.
760 break;
761
762 case R_ARM_THM_MOVW_ABS_NC:
763 // MOVW is only lower 16-bits of the addres
764 Address = (UINT16)(Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);
765 ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
766 break;
767
768 case R_ARM_THM_MOVT_ABS:
769 // MOVT is only upper 16-bits of the addres
770 Address = (UINT16)((Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]) >> 16);
771 ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
772 break;
773
774 case R_ARM_ABS32:
775 case R_ARM_RABS32:
776 //
777 // Absolute relocation.
778 //
779 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];
780 break;
781
782 default:
783 Error (NULL, 0, 3000, "Invalid", "WriteSections (): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));
784 }
785 }
786 }
787 }
788 }
789
790 return TRUE;
791 }
792
793 UINTN gMovwOffset = 0;
794
795 STATIC
796 VOID
797 WriteRelocations32 (
798 VOID
799 )
800 {
801 UINT32 Index;
802 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
803 EFI_IMAGE_DATA_DIRECTORY *Dir;
804 BOOLEAN FoundRelocations;
805 Elf_Dyn *Dyn;
806 Elf_Rel *Rel;
807 UINTN RelElementSize;
808 UINTN RelSize;
809 UINTN RelOffset;
810 UINTN K;
811 Elf32_Phdr *DynamicSegment;
812
813 for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {
814 Elf_Shdr *RelShdr = GetShdrByIndex(Index);
815 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {
816 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);
817 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
818 UINT32 RelIdx;
819
820 FoundRelocations = TRUE;
821 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
822 Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);
823
824 if (mEhdr->e_machine == EM_386) {
825 switch (ELF_R_TYPE(Rel->r_info)) {
826 case R_386_NONE:
827 case R_386_PC32:
828 //
829 // No fixup entry required.
830 //
831 break;
832 case R_386_32:
833 //
834 // Creates a relative relocation entry from the absolute entry.
835 //
836 CoffAddFixup(mCoffSectionsOffset[RelShdr->sh_info]
837 + (Rel->r_offset - SecShdr->sh_addr),
838 EFI_IMAGE_REL_BASED_HIGHLOW);
839 break;
840 default:
841 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
842 }
843 } else if (mEhdr->e_machine == EM_ARM) {
844 switch (ELF32_R_TYPE(Rel->r_info)) {
845 case R_ARM_RBASE:
846 // No relocation - no action required
847 // break skipped
848
849 case R_ARM_PC24:
850 case R_ARM_REL32:
851 case R_ARM_XPC25:
852 case R_ARM_THM_PC22:
853 case R_ARM_THM_JUMP19:
854 case R_ARM_CALL:
855 case R_ARM_JMP24:
856 case R_ARM_THM_JUMP24:
857 case R_ARM_PREL31:
858 case R_ARM_MOVW_PREL_NC:
859 case R_ARM_MOVT_PREL:
860 case R_ARM_THM_MOVW_PREL_NC:
861 case R_ARM_THM_MOVT_PREL:
862 case R_ARM_THM_JMP6:
863 case R_ARM_THM_ALU_PREL_11_0:
864 case R_ARM_THM_PC12:
865 case R_ARM_REL32_NOI:
866 case R_ARM_ALU_PC_G0_NC:
867 case R_ARM_ALU_PC_G0:
868 case R_ARM_ALU_PC_G1_NC:
869 case R_ARM_ALU_PC_G1:
870 case R_ARM_ALU_PC_G2:
871 case R_ARM_LDR_PC_G1:
872 case R_ARM_LDR_PC_G2:
873 case R_ARM_LDRS_PC_G0:
874 case R_ARM_LDRS_PC_G1:
875 case R_ARM_LDRS_PC_G2:
876 case R_ARM_LDC_PC_G0:
877 case R_ARM_LDC_PC_G1:
878 case R_ARM_LDC_PC_G2:
879 case R_ARM_GOT_PREL:
880 case R_ARM_THM_JUMP11:
881 case R_ARM_THM_JUMP8:
882 case R_ARM_TLS_GD32:
883 case R_ARM_TLS_LDM32:
884 case R_ARM_TLS_IE32:
885 // Thease are all PC-relative relocations and don't require modification
886 break;
887
888 case R_ARM_THM_MOVW_ABS_NC:
889 CoffAddFixup (
890 mCoffSectionsOffset[RelShdr->sh_info]
891 + (Rel->r_offset - SecShdr->sh_addr),
892 EFI_IMAGE_REL_BASED_ARM_MOV32T
893 );
894
895 // PE/COFF treats MOVW/MOVT relocation as single 64-bit instruction
896 // Track this address so we can log an error for unsupported sequence of MOVW/MOVT
897 gMovwOffset = mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr);
898 break;
899
900 case R_ARM_THM_MOVT_ABS:
901 if ((gMovwOffset + 4) != (mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr))) {
902 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));
903 }
904 break;
905
906 case R_ARM_ABS32:
907 case R_ARM_RABS32:
908 CoffAddFixup (
909 mCoffSectionsOffset[RelShdr->sh_info]
910 + (Rel->r_offset - SecShdr->sh_addr),
911 EFI_IMAGE_REL_BASED_HIGHLOW
912 );
913 break;
914
915 default:
916 Error (NULL, 0, 3000, "Invalid", "WriteRelocations(): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));
917 }
918 } else {
919 Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);
920 }
921 }
922 }
923 }
924 }
925
926 if (!FoundRelocations && (mEhdr->e_machine == EM_ARM)) {
927 /* Try again, but look for PT_DYNAMIC instead of SHT_REL */
928
929 for (Index = 0; Index < mEhdr->e_phnum; Index++) {
930 RelElementSize = 0;
931 RelSize = 0;
932 RelOffset = 0;
933
934 DynamicSegment = GetPhdrByIndex (Index);
935
936 if (DynamicSegment->p_type == PT_DYNAMIC) {
937 Dyn = (Elf32_Dyn *) ((UINT8 *)mEhdr + DynamicSegment->p_offset);
938
939 while (Dyn->d_tag != DT_NULL) {
940 switch (Dyn->d_tag) {
941 case DT_REL:
942 RelOffset = Dyn->d_un.d_val;
943 break;
944
945 case DT_RELSZ:
946 RelSize = Dyn->d_un.d_val;
947 break;
948
949 case DT_RELENT:
950 RelElementSize = Dyn->d_un.d_val;
951 break;
952
953 default:
954 break;
955 }
956 Dyn++;
957 }
958 if (( RelOffset == 0 ) || ( RelSize == 0 ) || ( RelElementSize == 0 )) {
959 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName);
960 }
961
962 for (Index = 0; Index < mEhdr->e_shnum; Index++) {
963 Elf_Shdr *shdr = GetShdrByIndex(Index);
964
965 //
966 // The PT_DYNAMIC section contains DT_REL relocations whose r_offset
967 // field is relative to the base of a segment (or the entire image),
968 // and not to the base of an ELF input section as is the case for
969 // SHT_REL sections. This means that we cannot fix up such relocations
970 // unless we cross-reference ELF sections and segments, considering
971 // that the output placement recorded in mCoffSectionsOffset[] is
972 // section based, not segment based.
973 //
974 // Fortunately, there is a simple way around this: we require that the
975 // in-memory layout of the ELF and PE/COFF versions of the binary is
976 // identical. That way, r_offset will retain its validity as a PE/COFF
977 // image offset, and we can record it in the COFF fixup table
978 // unmodified.
979 //
980 if (shdr->sh_addr != mCoffSectionsOffset[Index]) {
981 Error (NULL, 0, 3000,
982 "Invalid", "%s: PT_DYNAMIC relocations require identical ELF and PE/COFF section offsets.",
983 mInImageName);
984 }
985 }
986
987 for (K = 0; K < RelSize; K += RelElementSize) {
988
989 if (DynamicSegment->p_paddr == 0) {
990 // Older versions of the ARM ELF (SWS ESPC 0003 B-02) specification define DT_REL
991 // as an offset in the dynamic segment. p_paddr is defined to be zero for ARM tools
992 Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + DynamicSegment->p_offset + RelOffset + K);
993 } else {
994 // This is how it reads in the generic ELF specification
995 Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + RelOffset + K);
996 }
997
998 switch (ELF32_R_TYPE (Rel->r_info)) {
999 case R_ARM_RBASE:
1000 break;
1001
1002 case R_ARM_RABS32:
1003 CoffAddFixup (Rel->r_offset, EFI_IMAGE_REL_BASED_HIGHLOW);
1004 break;
1005
1006 default:
1007 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations, unkown type %d.", mInImageName, ELF32_R_TYPE (Rel->r_info));
1008 break;
1009 }
1010 }
1011 break;
1012 }
1013 }
1014 }
1015
1016 //
1017 // Pad by adding empty entries.
1018 //
1019 while (mCoffOffset & (mCoffAlignment - 1)) {
1020 CoffAddFixupEntry(0);
1021 }
1022
1023 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
1024 Dir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1025 Dir->Size = mCoffOffset - mRelocOffset;
1026 if (Dir->Size == 0) {
1027 // If no relocations, null out the directory entry and don't add the .reloc section
1028 Dir->VirtualAddress = 0;
1029 NtHdr->Pe32.FileHeader.NumberOfSections--;
1030 } else {
1031 Dir->VirtualAddress = mRelocOffset;
1032 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,
1033 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
1034 | EFI_IMAGE_SCN_MEM_DISCARDABLE
1035 | EFI_IMAGE_SCN_MEM_READ);
1036 }
1037
1038 }
1039
1040 STATIC
1041 VOID
1042 WriteDebug32 (
1043 VOID
1044 )
1045 {
1046 UINT32 Len;
1047 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
1048 EFI_IMAGE_DATA_DIRECTORY *DataDir;
1049 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
1050 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
1051
1052 Len = strlen(mInImageName) + 1;
1053
1054 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);
1055 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
1056 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;
1057 Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
1058 Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
1059
1060 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
1061 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
1062 strcpy ((char *)(Nb10 + 1), mInImageName);
1063
1064
1065 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
1066 DataDir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
1067 DataDir->VirtualAddress = mDebugOffset;
1068 DataDir->Size = Dir->SizeOfData + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
1069 }
1070
1071 STATIC
1072 VOID
1073 SetImageSize32 (
1074 VOID
1075 )
1076 {
1077 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
1078
1079 //
1080 // Set image size
1081 //
1082 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
1083 NtHdr->Pe32.OptionalHeader.SizeOfImage = mCoffOffset;
1084 }
1085
1086 STATIC
1087 VOID
1088 CleanUp32 (
1089 VOID
1090 )
1091 {
1092 if (mCoffSectionsOffset != NULL) {
1093 free (mCoffSectionsOffset);
1094 }
1095 }
1096
1097