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