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