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