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