]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFw/Elf32Convert.c
SecurityPkg Variable: Remove mStorageData buffer allocation and use Scratch buffer...
[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;
40d841f6
LG
741
742 for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {
743 Elf_Shdr *RelShdr = GetShdrByIndex(Index);
744 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {
745 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);
746 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
747 UINT32 RelIdx;
748
40d841f6
LG
749 FoundRelocations = TRUE;
750 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
751 Elf_Rel *Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);
40d841f6 752
40d841f6
LG
753 if (mEhdr->e_machine == EM_386) {
754 switch (ELF_R_TYPE(Rel->r_info)) {
755 case R_386_NONE:
756 case R_386_PC32:
757 //
758 // No fixup entry required.
759 //
760 break;
761 case R_386_32:
762 //
763 // Creates a relative relocation entry from the absolute entry.
764 //
765 CoffAddFixup(mCoffSectionsOffset[RelShdr->sh_info]
766 + (Rel->r_offset - SecShdr->sh_addr),
767 EFI_IMAGE_REL_BASED_HIGHLOW);
768 break;
769 default:
770 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
771 }
772 } else if (mEhdr->e_machine == EM_ARM) {
773 switch (ELF32_R_TYPE(Rel->r_info)) {
756ad8f8 774 case R_ARM_RBASE:
40d841f6 775 // No relocation - no action required
756ad8f8
LG
776 // break skipped
777
40d841f6
LG
778 case R_ARM_PC24:
779 case R_ARM_XPC25:
780 case R_ARM_THM_PC22:
781 case R_ARM_THM_JUMP19:
782 case R_ARM_CALL:
783 case R_ARM_JMP24:
756ad8f8
LG
784 case R_ARM_THM_JUMP24:
785 case R_ARM_PREL31:
786 case R_ARM_MOVW_PREL_NC:
787 case R_ARM_MOVT_PREL:
788 case R_ARM_THM_MOVW_PREL_NC:
789 case R_ARM_THM_MOVT_PREL:
790 case R_ARM_THM_JMP6:
791 case R_ARM_THM_ALU_PREL_11_0:
792 case R_ARM_THM_PC12:
793 case R_ARM_REL32_NOI:
da92f276
LG
794 case R_ARM_ALU_PC_G0_NC:
795 case R_ARM_ALU_PC_G0:
796 case R_ARM_ALU_PC_G1_NC:
797 case R_ARM_ALU_PC_G1:
798 case R_ARM_ALU_PC_G2:
799 case R_ARM_LDR_PC_G1:
800 case R_ARM_LDR_PC_G2:
801 case R_ARM_LDRS_PC_G0:
802 case R_ARM_LDRS_PC_G1:
803 case R_ARM_LDRS_PC_G2:
804 case R_ARM_LDC_PC_G0:
805 case R_ARM_LDC_PC_G1:
756ad8f8
LG
806 case R_ARM_LDC_PC_G2:
807 case R_ARM_GOT_PREL:
808 case R_ARM_THM_JUMP11:
809 case R_ARM_THM_JUMP8:
810 case R_ARM_TLS_GD32:
811 case R_ARM_TLS_LDM32:
812 case R_ARM_TLS_IE32:
40d841f6
LG
813 // Thease are all PC-relative relocations and don't require modification
814 break;
815
816 case R_ARM_THM_MOVW_ABS_NC:
817 CoffAddFixup (
818 mCoffSectionsOffset[RelShdr->sh_info]
819 + (Rel->r_offset - SecShdr->sh_addr),
da92f276 820 EFI_IMAGE_REL_BASED_ARM_MOV32T
40d841f6 821 );
da92f276
LG
822
823 // PE/COFF treats MOVW/MOVT relocation as single 64-bit instruction
824 // Track this address so we can log an error for unsupported sequence of MOVW/MOVT
825 gMovwOffset = mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr);
40d841f6
LG
826 break;
827
828 case R_ARM_THM_MOVT_ABS:
da92f276
LG
829 if ((gMovwOffset + 4) != (mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr))) {
830 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));
831 }
40d841f6
LG
832 break;
833
834 case R_ARM_ABS32:
835 case R_ARM_RABS32:
836 CoffAddFixup (
837 mCoffSectionsOffset[RelShdr->sh_info]
838 + (Rel->r_offset - SecShdr->sh_addr),
839 EFI_IMAGE_REL_BASED_HIGHLOW
840 );
841 break;
842
843 default:
844 Error (NULL, 0, 3000, "Invalid", "WriteRelocations(): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));
845 }
846 } else {
847 Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);
848 }
849 }
850 }
851 }
852 }
853
854 if (!FoundRelocations && (mEhdr->e_machine == EM_ARM)) {
855 /* Try again, but look for PT_DYNAMIC instead of SHT_REL */
856
857 for (Index = 0; Index < mEhdr->e_phnum; Index++) {
858 RelElementSize = 0;
859 RelSize = 0;
860 RelOffset = 0;
861
862 DynamicSegment = GetPhdrByIndex (Index);
863
864 if (DynamicSegment->p_type == PT_DYNAMIC) {
865 Dyn = (Elf32_Dyn *) ((UINT8 *)mEhdr + DynamicSegment->p_offset);
866
867 while (Dyn->d_tag != DT_NULL) {
868 switch (Dyn->d_tag) {
869 case DT_REL:
870 RelOffset = Dyn->d_un.d_val;
871 break;
872
873 case DT_RELSZ:
874 RelSize = Dyn->d_un.d_val;
875 break;
876
877 case DT_RELENT:
878 RelElementSize = Dyn->d_un.d_val;
879 break;
880
881 default:
882 break;
883 }
884 Dyn++;
885 }
886 if (( RelOffset == 0 ) || ( RelSize == 0 ) || ( RelElementSize == 0 )) {
887 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName);
888 }
889
890 for (K = 0; K < RelSize; K += RelElementSize) {
891
892 if (DynamicSegment->p_paddr == 0) {
893 // Older versions of the ARM ELF (SWS ESPC 0003 B-02) specification define DT_REL
894 // as an offset in the dynamic segment. p_paddr is defined to be zero for ARM tools
895 Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + DynamicSegment->p_offset + RelOffset + K);
896 } else {
897 // This is how it reads in the generic ELF specification
898 Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + RelOffset + K);
899 }
900
901 switch (ELF32_R_TYPE (Rel->r_info)) {
902 case R_ARM_RBASE:
903 break;
904
905 case R_ARM_RABS32:
906 TargetSegment = GetPhdrByIndex (ELF32_R_SYM (Rel->r_info) - 1);
907
908 // Note: r_offset in a memory address. Convert it to a pointer in the coff file.
909 Targ = mCoffFile + mCoffSectionsOffset[ ELF32_R_SYM( Rel->r_info ) ] + Rel->r_offset - TargetSegment->p_vaddr;
910
911 *(UINT32 *)Targ = *(UINT32 *)Targ + mCoffSectionsOffset [ELF32_R_SYM( Rel->r_info )];
912
913 CoffAddFixup (mCoffSectionsOffset[ELF32_R_SYM (Rel->r_info)] + (Rel->r_offset - TargetSegment->p_vaddr), EFI_IMAGE_REL_BASED_HIGHLOW);
914 break;
915
916 default:
917 Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations, unkown type %d.", mInImageName, ELF32_R_TYPE (Rel->r_info));
918 break;
919 }
920 }
921 break;
922 }
923 }
924 }
925
926 //
927 // Pad by adding empty entries.
928 //
929 while (mCoffOffset & (mCoffAlignment - 1)) {
930 CoffAddFixupEntry(0);
931 }
932
933 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
934 Dir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
935 Dir->Size = mCoffOffset - mRelocOffset;
936 if (Dir->Size == 0) {
937 // If no relocations, null out the directory entry and don't add the .reloc section
938 Dir->VirtualAddress = 0;
939 NtHdr->Pe32.FileHeader.NumberOfSections--;
940 } else {
941 Dir->VirtualAddress = mRelocOffset;
942 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,
943 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
944 | EFI_IMAGE_SCN_MEM_DISCARDABLE
945 | EFI_IMAGE_SCN_MEM_READ);
946 }
947
948}
949
950STATIC
951VOID
952WriteDebug32 (
953 VOID
954 )
955{
956 UINT32 Len;
957 UINT32 DebugOffset;
958 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
959 EFI_IMAGE_DATA_DIRECTORY *DataDir;
960 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
961 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
962
963 Len = strlen(mInImageName) + 1;
964 DebugOffset = mCoffOffset;
965
966 mCoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)
967 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)
968 + Len;
969 mCoffOffset = CoffAlign(mCoffOffset);
970
971 mCoffFile = realloc(mCoffFile, mCoffOffset);
972 memset(mCoffFile + DebugOffset, 0, mCoffOffset - DebugOffset);
973
974 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + DebugOffset);
975 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
976 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;
977 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
978 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
979
980 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
981 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
982 strcpy ((char *)(Nb10 + 1), mInImageName);
983
984
985 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
986 DataDir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
987 DataDir->VirtualAddress = DebugOffset;
988 DataDir->Size = mCoffOffset - DebugOffset;
989 if (DataDir->Size == 0) {
990 // If no debug, null out the directory entry and don't add the .debug section
991 DataDir->VirtualAddress = 0;
992 NtHdr->Pe32.FileHeader.NumberOfSections--;
993 } else {
994 DataDir->VirtualAddress = DebugOffset;
995 CreateSectionHeader (".debug", DebugOffset, mCoffOffset - DebugOffset,
996 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
997 | EFI_IMAGE_SCN_MEM_DISCARDABLE
998 | EFI_IMAGE_SCN_MEM_READ);
999
1000 }
1001}
1002
1003STATIC
1004VOID
1005SetImageSize32 (
1006 VOID
1007 )
1008{
1009 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
1010
1011 //
1012 // Set image size
1013 //
1014 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
1015 NtHdr->Pe32.OptionalHeader.SizeOfImage = mCoffOffset;
1016}
1017
1018STATIC
1019VOID
1020CleanUp32 (
1021 VOID
1022 )
1023{
1024 if (mCoffSectionsOffset != NULL) {
1025 free (mCoffSectionsOffset);
1026 }
1027}
1028
1029