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