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