]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFw/Elf32Convert.c
Sync EDKII BaseTools to BaseTools project r2006.
[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
756ad8f8 635 // break skipped
40d841f6
LG
636
637 case R_ARM_PC24:
638 case R_ARM_XPC25:
639 case R_ARM_THM_PC22:
640 case R_ARM_THM_JUMP19:
641 case R_ARM_CALL:
642 case R_ARM_JMP24:
756ad8f8
LG
643 case R_ARM_THM_JUMP24:
644 case R_ARM_PREL31:
645 case R_ARM_MOVW_PREL_NC:
646 case R_ARM_MOVT_PREL:
647 case R_ARM_THM_MOVW_PREL_NC:
648 case R_ARM_THM_MOVT_PREL:
649 case R_ARM_THM_JMP6:
650 case R_ARM_THM_ALU_PREL_11_0:
651 case R_ARM_THM_PC12:
652 case R_ARM_REL32_NOI:
653 case R_ARM_ALU_PC_G0_NC:\r
654 case R_ARM_ALU_PC_G0:\r
655 case R_ARM_ALU_PC_G1_NC:\r
656 case R_ARM_ALU_PC_G1:\r
657 case R_ARM_ALU_PC_G2:\r
658 case R_ARM_LDR_PC_G1:\r
659 case R_ARM_LDR_PC_G2:\r
660 case R_ARM_LDRS_PC_G0:\r
661 case R_ARM_LDRS_PC_G1:\r
662 case R_ARM_LDRS_PC_G2:\r
663 case R_ARM_LDC_PC_G0:\r
664 case R_ARM_LDC_PC_G1:\r
665 case R_ARM_LDC_PC_G2:
666 case R_ARM_GOT_PREL:
667 case R_ARM_THM_JUMP11:
668 case R_ARM_THM_JUMP8:
669 case R_ARM_TLS_GD32:
670 case R_ARM_TLS_LDM32:
671 case R_ARM_TLS_IE32:
40d841f6
LG
672 // Thease are all PC-relative relocations and don't require modification
673 // GCC does not seem to have the concept of a application that just needs to get relocated.
674 break;
675
676 case R_ARM_THM_MOVW_ABS_NC:
677 // MOVW is only lower 16-bits of the addres
678 Address = (UINT16)(Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);
679 ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
680 break;
681
682 case R_ARM_THM_MOVT_ABS:
683 // MOVT is only upper 16-bits of the addres
684 Address = (UINT16)((Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]) >> 16);
685 ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
686 break;
687
688 case R_ARM_ABS32:
689 case R_ARM_RABS32:
690 //
691 // Absolute relocation.
692 //
693 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];
694 break;
695
696 default:
697 Error (NULL, 0, 3000, "Invalid", "WriteSections (): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));
698 }
699 }
700 }
701 }
702 }
703
704 return TRUE;
705}
706
707STATIC
708VOID
709WriteRelocations32 (
710 VOID
711 )
712{
713 UINT32 Index;
714 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
715 EFI_IMAGE_DATA_DIRECTORY *Dir;
716 BOOLEAN FoundRelocations;
717 Elf_Dyn *Dyn;
718 Elf_Rel *Rel;
719 UINTN RelElementSize;
720 UINTN RelSize;
721 UINTN RelOffset;
722 UINTN K;
723 UINT8 *Targ;
724 Elf32_Phdr *DynamicSegment;
725 Elf32_Phdr *TargetSegment;
726 Elf_Sym *Sym;
727 Elf_Shdr *SymtabShdr;
728 UINT8 *Symtab;
729
730
731 for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {
732 Elf_Shdr *RelShdr = GetShdrByIndex(Index);
733 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {
734 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);
735 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
736 UINT32 RelIdx;
737
738 SymtabShdr = GetShdrByIndex (RelShdr->sh_link);
739 Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;
740 FoundRelocations = TRUE;
741 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
742 Elf_Rel *Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);
743 Elf_Shdr *SymShdr;
744
745 Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
746 SymShdr = GetShdrByIndex (Sym->st_shndx);
747
748 if (mEhdr->e_machine == EM_386) {
749 switch (ELF_R_TYPE(Rel->r_info)) {
750 case R_386_NONE:
751 case R_386_PC32:
752 //
753 // No fixup entry required.
754 //
755 break;
756 case R_386_32:
757 //
758 // Creates a relative relocation entry from the absolute entry.
759 //
760 CoffAddFixup(mCoffSectionsOffset[RelShdr->sh_info]
761 + (Rel->r_offset - SecShdr->sh_addr),
762 EFI_IMAGE_REL_BASED_HIGHLOW);
763 break;
764 default:
765 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
766 }
767 } else if (mEhdr->e_machine == EM_ARM) {
768 switch (ELF32_R_TYPE(Rel->r_info)) {
756ad8f8 769 case R_ARM_RBASE:
40d841f6 770 // No relocation - no action required
756ad8f8
LG
771 // break skipped
772
40d841f6
LG
773 case R_ARM_PC24:
774 case R_ARM_XPC25:
775 case R_ARM_THM_PC22:
776 case R_ARM_THM_JUMP19:
777 case R_ARM_CALL:
778 case R_ARM_JMP24:
756ad8f8
LG
779 case R_ARM_THM_JUMP24:
780 case R_ARM_PREL31:
781 case R_ARM_MOVW_PREL_NC:
782 case R_ARM_MOVT_PREL:
783 case R_ARM_THM_MOVW_PREL_NC:
784 case R_ARM_THM_MOVT_PREL:
785 case R_ARM_THM_JMP6:
786 case R_ARM_THM_ALU_PREL_11_0:
787 case R_ARM_THM_PC12:
788 case R_ARM_REL32_NOI:
789 case R_ARM_ALU_PC_G0_NC:\r
790 case R_ARM_ALU_PC_G0:\r
791 case R_ARM_ALU_PC_G1_NC:\r
792 case R_ARM_ALU_PC_G1:\r
793 case R_ARM_ALU_PC_G2:\r
794 case R_ARM_LDR_PC_G1:\r
795 case R_ARM_LDR_PC_G2:\r
796 case R_ARM_LDRS_PC_G0:\r
797 case R_ARM_LDRS_PC_G1:\r
798 case R_ARM_LDRS_PC_G2:\r
799 case R_ARM_LDC_PC_G0:\r
800 case R_ARM_LDC_PC_G1:\r
801 case R_ARM_LDC_PC_G2:
802 case R_ARM_GOT_PREL:
803 case R_ARM_THM_JUMP11:
804 case R_ARM_THM_JUMP8:
805 case R_ARM_TLS_GD32:
806 case R_ARM_TLS_LDM32:
807 case R_ARM_TLS_IE32:
40d841f6
LG
808 // Thease are all PC-relative relocations and don't require modification
809 break;
810
811 case R_ARM_THM_MOVW_ABS_NC:
812 CoffAddFixup (
813 mCoffSectionsOffset[RelShdr->sh_info]
814 + (Rel->r_offset - SecShdr->sh_addr),
815 EFI_IMAGE_REL_BASED_ARM_THUMB_MOVW
816 );
817 break;
818
819 case R_ARM_THM_MOVT_ABS:
820 CoffAddFixup (
821 mCoffSectionsOffset[RelShdr->sh_info]
822 + (Rel->r_offset - SecShdr->sh_addr),
823 EFI_IMAGE_REL_BASED_ARM_THUMB_MOVT
824 );
825
826 // The relocation entry needs to contain the lower 16-bits so we can do math
827 CoffAddFixupEntry ((UINT16)(Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]));
828 break;
829
830 case R_ARM_ABS32:
831 case R_ARM_RABS32:
832 CoffAddFixup (
833 mCoffSectionsOffset[RelShdr->sh_info]
834 + (Rel->r_offset - SecShdr->sh_addr),
835 EFI_IMAGE_REL_BASED_HIGHLOW
836 );
837 break;
838
839 default:
840 Error (NULL, 0, 3000, "Invalid", "WriteRelocations(): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));
841 }
842 } else {
843 Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);
844 }
845 }
846 }
847 }
848 }
849
850 if (!FoundRelocations && (mEhdr->e_machine == EM_ARM)) {
851 /* Try again, but look for PT_DYNAMIC instead of SHT_REL */
852
853 for (Index = 0; Index < mEhdr->e_phnum; Index++) {
854 RelElementSize = 0;
855 RelSize = 0;
856 RelOffset = 0;
857
858 DynamicSegment = GetPhdrByIndex (Index);
859
860 if (DynamicSegment->p_type == PT_DYNAMIC) {
861 Dyn = (Elf32_Dyn *) ((UINT8 *)mEhdr + DynamicSegment->p_offset);
862
863 while (Dyn->d_tag != DT_NULL) {
864 switch (Dyn->d_tag) {
865 case DT_REL:
866 RelOffset = Dyn->d_un.d_val;
867 break;
868
869 case DT_RELSZ:
870 RelSize = Dyn->d_un.d_val;
871 break;
872
873 case DT_RELENT:
874 RelElementSize = Dyn->d_un.d_val;
875 break;
876
877 default:
878 break;
879 }
880 Dyn++;
881 }
882 if (( RelOffset == 0 ) || ( RelSize == 0 ) || ( RelElementSize == 0 )) {
883 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName);
884 }
885
886 for (K = 0; K < RelSize; K += RelElementSize) {
887
888 if (DynamicSegment->p_paddr == 0) {
889 // Older versions of the ARM ELF (SWS ESPC 0003 B-02) specification define DT_REL
890 // as an offset in the dynamic segment. p_paddr is defined to be zero for ARM tools
891 Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + DynamicSegment->p_offset + RelOffset + K);
892 } else {
893 // This is how it reads in the generic ELF specification
894 Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + RelOffset + K);
895 }
896
897 switch (ELF32_R_TYPE (Rel->r_info)) {
898 case R_ARM_RBASE:
899 break;
900
901 case R_ARM_RABS32:
902 TargetSegment = GetPhdrByIndex (ELF32_R_SYM (Rel->r_info) - 1);
903
904 // Note: r_offset in a memory address. Convert it to a pointer in the coff file.
905 Targ = mCoffFile + mCoffSectionsOffset[ ELF32_R_SYM( Rel->r_info ) ] + Rel->r_offset - TargetSegment->p_vaddr;
906
907 *(UINT32 *)Targ = *(UINT32 *)Targ + mCoffSectionsOffset [ELF32_R_SYM( Rel->r_info )];
908
909 CoffAddFixup (mCoffSectionsOffset[ELF32_R_SYM (Rel->r_info)] + (Rel->r_offset - TargetSegment->p_vaddr), EFI_IMAGE_REL_BASED_HIGHLOW);
910 break;
911
912 default:
913 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations, unkown type %d.", mInImageName, ELF32_R_TYPE (Rel->r_info));
914 break;
915 }
916 }
917 break;
918 }
919 }
920 }
921
922 //
923 // Pad by adding empty entries.
924 //
925 while (mCoffOffset & (mCoffAlignment - 1)) {
926 CoffAddFixupEntry(0);
927 }
928
929 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
930 Dir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
931 Dir->Size = mCoffOffset - mRelocOffset;
932 if (Dir->Size == 0) {
933 // If no relocations, null out the directory entry and don't add the .reloc section
934 Dir->VirtualAddress = 0;
935 NtHdr->Pe32.FileHeader.NumberOfSections--;
936 } else {
937 Dir->VirtualAddress = mRelocOffset;
938 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,
939 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
940 | EFI_IMAGE_SCN_MEM_DISCARDABLE
941 | EFI_IMAGE_SCN_MEM_READ);
942 }
943
944}
945
946STATIC
947VOID
948WriteDebug32 (
949 VOID
950 )
951{
952 UINT32 Len;
953 UINT32 DebugOffset;
954 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
955 EFI_IMAGE_DATA_DIRECTORY *DataDir;
956 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
957 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
958
959 Len = strlen(mInImageName) + 1;
960 DebugOffset = mCoffOffset;
961
962 mCoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)
963 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)
964 + Len;
965 mCoffOffset = CoffAlign(mCoffOffset);
966
967 mCoffFile = realloc(mCoffFile, mCoffOffset);
968 memset(mCoffFile + DebugOffset, 0, mCoffOffset - DebugOffset);
969
970 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + DebugOffset);
971 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
972 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;
973 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
974 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
975
976 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
977 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
978 strcpy ((char *)(Nb10 + 1), mInImageName);
979
980
981 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
982 DataDir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
983 DataDir->VirtualAddress = DebugOffset;
984 DataDir->Size = mCoffOffset - DebugOffset;
985 if (DataDir->Size == 0) {
986 // If no debug, null out the directory entry and don't add the .debug section
987 DataDir->VirtualAddress = 0;
988 NtHdr->Pe32.FileHeader.NumberOfSections--;
989 } else {
990 DataDir->VirtualAddress = DebugOffset;
991 CreateSectionHeader (".debug", DebugOffset, mCoffOffset - DebugOffset,
992 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
993 | EFI_IMAGE_SCN_MEM_DISCARDABLE
994 | EFI_IMAGE_SCN_MEM_READ);
995
996 }
997}
998
999STATIC
1000VOID
1001SetImageSize32 (
1002 VOID
1003 )
1004{
1005 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
1006
1007 //
1008 // Set image size
1009 //
1010 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
1011 NtHdr->Pe32.OptionalHeader.SizeOfImage = mCoffOffset;
1012}
1013
1014STATIC
1015VOID
1016CleanUp32 (
1017 VOID
1018 )
1019{
1020 if (mCoffSectionsOffset != NULL) {
1021 free (mCoffSectionsOffset);
1022 }
1023}
1024
1025