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