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