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