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