automagically convert ELF to PE/COFF (i386 only)
[mirror_edk2.git] / Tools / CCode / Source / FwImage / fwimage.c
1 /*++
2
3 Copyright (c) 2004, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 fwimage.c
15
16 Abstract:
17
18 Converts a pe32+ image to an FW image type
19
20 --*/
21
22 #include "WinNtInclude.h"
23
24 //
25 // List of OS and CPU which support ELF to PE conversion
26 //
27 #if defined(linux)
28 #if defined(i386)
29 #define HAVE_ELF
30 #endif
31 #endif
32
33 #ifndef __GNUC__
34 #include <windows.h>
35 #endif
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40
41 #ifdef HAVE_ELF
42 #include <elf.h>
43 #endif
44
45 #include <Common/UefiBaseTypes.h>
46 #include <Common/EfiImage.h>
47
48 #include "CommonLib.h"
49 #include "EfiUtilityMsgs.c"
50
51 //
52 // Version of this utility
53 //
54 #define UTILITY_NAME "FwImage"
55 #define UTILITY_MAJOR_VERSION 1
56 #define UTILITY_MINOR_VERSION 0
57
58 #ifdef __GNUC__
59 typedef unsigned long ULONG;
60 typedef unsigned char UCHAR;
61 typedef unsigned char *PUCHAR;
62 typedef unsigned short USHORT;
63 #endif
64
65 PUCHAR InImageName;
66
67 static
68 void
69 Version (
70 VOID
71 )
72 {
73 printf ("%s v%d.%d -EDK Utility for Converting a pe32+ image to an FW image type.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
74 printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");
75 }
76
77
78 VOID
79 Usage (
80 VOID
81 )
82 {
83 Version();
84 printf ("\nUsage: " UTILITY_NAME " {-t time-date} {-h|--help|-?|/?|-V|--version} \n\
85 [BASE|SEC|PEI_CORE|PEIM|DXE_CORE|DXE_DRIVER|DXE_RUNTIME_DRIVER|\n\
86 DXE_SAL_DRIVER|DXE_SMM_DRIVER|TOOL|UEFI_DRIVER|UEFI_APPLICATION|\n\
87 USER_DEFINED] peimage [outimage]\n");
88 }
89
90 static
91 STATUS
92 FCopyFile (
93 FILE *in,
94 FILE *out
95 )
96 {
97 ULONG filesize;
98 ULONG offset;
99 ULONG length;
100 UCHAR Buffer[8 * 1024];
101
102 fseek (in, 0, SEEK_END);
103 filesize = ftell (in);
104
105 fseek (in, 0, SEEK_SET);
106 fseek (out, 0, SEEK_SET);
107
108 offset = 0;
109 while (offset < filesize) {
110 length = sizeof (Buffer);
111 if (filesize - offset < length) {
112 length = filesize - offset;
113 }
114
115 fread (Buffer, length, 1, in);
116 fwrite (Buffer, length, 1, out);
117 offset += length;
118 }
119
120 if ((ULONG) ftell (out) != filesize) {
121 Error (NULL, 0, 0, "write error", NULL);
122 return STATUS_ERROR;
123 }
124
125 return STATUS_SUCCESS;
126 }
127
128 static
129 STATUS
130 FReadFile (
131 FILE *in,
132 VOID **Buffer,
133 UINTN *Length
134 )
135 {
136 fseek (in, 0, SEEK_END);
137 *Length = ftell (in);
138 *Buffer = malloc (*Length);
139 fseek (in, 0, SEEK_SET);
140 fread (*Buffer, *Length, 1, in);
141 return STATUS_SUCCESS;
142 }
143
144 static
145 STATUS
146 FWriteFile (
147 FILE *out,
148 VOID *Buffer,
149 UINTN Length
150 )
151 {
152 fseek (out, 0, SEEK_SET);
153 fwrite (Buffer, Length, 1, out);
154 if ((ULONG) ftell (out) != Length) {
155 Error (NULL, 0, 0, "write error", NULL);
156 return STATUS_ERROR;
157 }
158 free (Buffer);
159 return STATUS_SUCCESS;
160 }
161
162 #ifdef HAVE_ELF
163 INTN
164 IsElfHeader(
165 UINT8 *FileBuffer
166 )
167 {
168 return (FileBuffer[EI_MAG0] == ELFMAG0
169 && FileBuffer[EI_MAG1] == ELFMAG1
170 && FileBuffer[EI_MAG2] == ELFMAG2
171 && FileBuffer[EI_MAG3] == ELFMAG3);
172 }
173
174 typedef Elf32_Shdr Elf_Shdr;
175 typedef Elf32_Ehdr Elf_Ehdr;
176 typedef Elf32_Rel Elf_Rel;
177 typedef Elf32_Sym Elf_Sym;
178 #define ELFCLASS ELFCLASS32
179 #define ELF_R_TYPE(r) ELF32_R_TYPE(r)
180 #define ELF_R_SYM(r) ELF32_R_SYM(r)
181
182 //
183 // Well known ELF structures.
184 //
185 Elf_Ehdr *Ehdr;
186 Elf_Shdr *ShdrBase;
187
188 //
189 // PE section alignment.
190 //
191 const UINT32 CoffAlignment = 0x20;
192 const UINT32 CoffNbrSections = 4;
193
194 //
195 // Current offset in coff file.
196 //
197 UINT32 CoffOffset;
198
199 //
200 // Result Coff file in memory.
201 //
202 UINT8 *CoffFile;
203
204 //
205 // Offset in Coff file of headers and sections.
206 //
207 UINT32 NtHdrOffset;
208 UINT32 TableOffset;
209 UINT32 TextOffset;
210 UINT32 DataOffset;
211 UINT32 RelocOffset;
212
213 //
214 // ELF sections to offset in Coff file.
215 //
216 UINT32 *CoffSectionsOffset;
217
218 EFI_IMAGE_BASE_RELOCATION *CoffBaseRel;
219 UINT16 *CoffEntryRel;
220
221 UINT32
222 CoffAlign(
223 UINT32 Offset
224 )
225 {
226 return (Offset + CoffAlignment - 1) & ~(CoffAlignment - 1);
227 }
228
229 Elf_Shdr *
230 GetShdrByIndex(
231 UINT32 Num
232 )
233 {
234 if (Num >= Ehdr->e_shnum)
235 return NULL;
236 return (Elf_Shdr*)((UINT8*)ShdrBase + Num * Ehdr->e_shentsize);
237 }
238
239 INTN
240 CheckElfHeader(
241 VOID
242 )
243 {
244 //
245 // Note: Magic has already been tested.
246 //
247 if (Ehdr->e_ident[EI_CLASS] != ELFCLASS)
248 return 0;
249 if (Ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
250 return 0;
251 if (Ehdr->e_type != ET_EXEC)
252 return 0;
253 if (Ehdr->e_machine != EM_386)
254 return 0;
255 if (Ehdr->e_version != EV_CURRENT)
256 return 0;
257
258 ShdrBase = (Elf_Shdr *)((UINT8 *)Ehdr + Ehdr->e_shoff);
259
260 CoffSectionsOffset = (UINT32 *)malloc(Ehdr->e_shnum * sizeof (UINT32));
261 memset(CoffSectionsOffset, 0, Ehdr->e_shnum * sizeof(UINT32));
262 return 1;
263 }
264
265 int
266 IsTextShdr(
267 Elf_Shdr *Shdr
268 )
269 {
270 return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC;
271 }
272
273 int
274 IsDataShdr(
275 Elf_Shdr *Shdr
276 )
277 {
278 return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);
279 }
280
281 void
282 CreateSectionHeader(
283 const char *Name,
284 UINT32 Offset,
285 UINT32 Size,
286 UINT32 Flags
287 )
288 {
289 EFI_IMAGE_SECTION_HEADER *Hdr;
290 Hdr = (EFI_IMAGE_SECTION_HEADER*)(CoffFile + TableOffset);
291
292 strcpy(Hdr->Name, Name);
293 Hdr->Misc.VirtualSize = Size;
294 Hdr->VirtualAddress = Offset;
295 Hdr->SizeOfRawData = Size;
296 Hdr->PointerToRawData = Offset;
297 Hdr->PointerToRelocations = 0;
298 Hdr->PointerToLinenumbers = 0;
299 Hdr->NumberOfRelocations = 0;
300 Hdr->NumberOfLinenumbers = 0;
301 Hdr->Characteristics = Flags;
302
303 TableOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
304 }
305
306 void
307 ScanSections(
308 VOID
309 )
310 {
311 UINT32 i;
312 EFI_IMAGE_DOS_HEADER *DosHdr;
313 EFI_IMAGE_NT_HEADERS *NtHdr;
314 UINT32 CoffEntry = 0;
315
316 CoffOffset = 0;
317
318 //
319 // Coff file start with a DOS header.
320 //
321 CoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;
322 NtHdrOffset = CoffOffset;
323 CoffOffset += sizeof(EFI_IMAGE_NT_HEADERS);
324 TableOffset = CoffOffset;
325 CoffOffset += CoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);
326
327 //
328 // First text sections.
329 //
330 CoffOffset = CoffAlign(CoffOffset);
331 TextOffset = CoffOffset;
332 for (i = 0; i < Ehdr->e_shnum; i++) {
333 Elf_Shdr *shdr = GetShdrByIndex(i);
334 if (IsTextShdr(shdr)) {
335 /* Relocate entry. */
336 if (Ehdr->e_entry >= shdr->sh_addr
337 && Ehdr->e_entry < shdr->sh_addr + shdr->sh_size) {
338 CoffEntry = CoffOffset + Ehdr->e_entry - shdr->sh_addr;
339 }
340 CoffSectionsOffset[i] = CoffOffset;
341 CoffOffset += shdr->sh_size;
342 }
343 }
344 CoffOffset = CoffAlign(CoffOffset);
345
346 //
347 // Then data sections.
348 //
349 DataOffset = CoffOffset;
350 for (i = 0; i < Ehdr->e_shnum; i++) {
351 Elf_Shdr *shdr = GetShdrByIndex(i);
352 if (IsDataShdr(shdr)) {
353 CoffSectionsOffset[i] = CoffOffset;
354 CoffOffset += shdr->sh_size;
355 }
356 }
357 CoffOffset = CoffAlign(CoffOffset);
358
359 RelocOffset = CoffOffset;
360
361 //
362 // Allocate base Coff file. Will be expanded later for relocations.
363 //
364 CoffFile = (UINT8 *)malloc(CoffOffset);
365 memset(CoffFile, 0, CoffOffset);
366
367 //
368 // Fill headers.
369 //
370 DosHdr = (EFI_IMAGE_DOS_HEADER *)CoffFile;
371 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
372 DosHdr->e_lfanew = NtHdrOffset;
373
374 NtHdr = (EFI_IMAGE_NT_HEADERS*)(CoffFile + NtHdrOffset);
375
376 NtHdr->Signature = EFI_IMAGE_NT_SIGNATURE;
377
378 NtHdr->FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
379 NtHdr->FileHeader.NumberOfSections = CoffNbrSections;
380 NtHdr->FileHeader.TimeDateStamp = time(NULL);
381 NtHdr->FileHeader.PointerToSymbolTable = 0;
382 NtHdr->FileHeader.NumberOfSymbols = 0;
383 NtHdr->FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->OptionalHeader);
384 NtHdr->FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE
385 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
386 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
387 | EFI_IMAGE_FILE_32BIT_MACHINE;
388
389 NtHdr->OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
390 NtHdr->OptionalHeader.SizeOfCode = DataOffset - TextOffset;
391 NtHdr->OptionalHeader.SizeOfInitializedData = RelocOffset - DataOffset;
392 NtHdr->OptionalHeader.SizeOfUninitializedData = 0;
393 NtHdr->OptionalHeader.AddressOfEntryPoint = CoffEntry;
394 NtHdr->OptionalHeader.BaseOfCode = TextOffset;
395
396 NtHdr->OptionalHeader.BaseOfData = DataOffset;
397 NtHdr->OptionalHeader.ImageBase = 0;
398 NtHdr->OptionalHeader.SectionAlignment = CoffAlignment;
399 NtHdr->OptionalHeader.FileAlignment = CoffAlignment;
400 NtHdr->OptionalHeader.SizeOfImage = 0;
401
402 NtHdr->OptionalHeader.SizeOfHeaders = TextOffset;
403 NtHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
404
405 //
406 // Section headers.
407 //
408 CreateSectionHeader (".text", TextOffset, DataOffset - TextOffset,
409 EFI_IMAGE_SCN_CNT_CODE
410 | EFI_IMAGE_SCN_MEM_EXECUTE
411 | EFI_IMAGE_SCN_MEM_READ);
412 CreateSectionHeader (".data", DataOffset, RelocOffset - DataOffset,
413 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
414 | EFI_IMAGE_SCN_MEM_WRITE
415 | EFI_IMAGE_SCN_MEM_READ);
416 }
417
418 void
419 WriteSections(
420 int (*Filter)(Elf_Shdr *)
421 )
422 {
423 UINT32 Idx;
424
425 //
426 // First: copy sections.
427 //
428 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
429 Elf_Shdr *Shdr = GetShdrByIndex(Idx);
430 if ((*Filter)(Shdr)) {
431 switch (Shdr->sh_type) {
432 case SHT_PROGBITS:
433 /* Copy. */
434 memcpy(CoffFile + CoffSectionsOffset[Idx],
435 (UINT8*)Ehdr + Shdr->sh_offset,
436 Shdr->sh_size);
437 break;
438 case SHT_NOBITS:
439 memset(CoffFile + CoffSectionsOffset[Idx], 0, Shdr->sh_size);
440 break;
441 default:
442 Error (NULL, 0, 0, InImageName, "unhandle section type %x",
443 (UINTN)Shdr->sh_type);
444 }
445 }
446 }
447
448 //
449 // Second: apply relocations.
450 //
451 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
452 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
453 if (RelShdr->sh_type != SHT_REL)
454 continue;
455 Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
456 UINT32 SecOffset = CoffSectionsOffset[RelShdr->sh_info];
457 if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
458 UINT32 RelIdx;
459 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
460 UINT8 *Symtab = (UINT8*)Ehdr + SymtabShdr->sh_offset;
461
462 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
463 Elf_Rel *Rel = (Elf_Rel *)((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
464 Elf_Sym *Sym = (Elf_Sym *)
465 (Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
466 Elf_Shdr *SymShdr;
467 UINT8 *Targ;
468
469 if (Sym->st_shndx == SHN_UNDEF
470 || Sym->st_shndx == SHN_ABS
471 || Sym->st_shndx > Ehdr->e_shnum) {
472 Error (NULL, 0, 0, InImageName, "bad symbol definition");
473 }
474 SymShdr = GetShdrByIndex(Sym->st_shndx);
475
476 //
477 // Note: r_offset in a memory address.
478 // Convert it to a pointer in the coff file.
479 //
480 Targ = CoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);
481
482 switch (ELF_R_TYPE(Rel->r_info)) {
483 case R_386_NONE:
484 break;
485 case R_386_32:
486 //
487 // Absolute relocation.
488 //
489 *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr
490 + CoffSectionsOffset[Sym->st_shndx];
491 break;
492 case R_386_PC32:
493 //
494 // Relative relocation: Symbol - Ip + Addend
495 //
496 *(UINT32 *)Targ = *(UINT32 *)Targ
497 + (CoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
498 - (SecOffset - SecShdr->sh_addr);
499 break;
500 default:
501 Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
502 ELF_R_TYPE(Rel->r_info));
503 }
504 }
505 }
506 }
507 }
508
509 void
510 CoffAddFixupEntry(
511 UINT16 Val
512 )
513 {
514 *CoffEntryRel = Val;
515 CoffEntryRel++;
516 CoffBaseRel->SizeOfBlock += 2;
517 CoffOffset += 2;
518 }
519
520 void
521 CoffAddFixup(
522 UINT32 Offset,
523 UINT8 Type
524 )
525 {
526 if (CoffBaseRel == NULL
527 || CoffBaseRel->VirtualAddress != (Offset & ~0xfff)) {
528 if (CoffBaseRel != NULL) {
529 //
530 // Add a null entry (is it required ?)
531 //
532 CoffAddFixupEntry (0);
533 //
534 // Pad for alignment.
535 //
536 if (CoffOffset % 4 != 0)
537 CoffAddFixupEntry (0);
538 }
539
540 CoffFile = realloc
541 (CoffFile,
542 CoffOffset + sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
543 memset(CoffFile + CoffOffset, 0,
544 sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
545
546 CoffBaseRel = (EFI_IMAGE_BASE_RELOCATION*)(CoffFile + CoffOffset);
547 CoffBaseRel->VirtualAddress = Offset & ~0xfff;
548 CoffBaseRel->SizeOfBlock = sizeof(EFI_IMAGE_BASE_RELOCATION);
549
550 CoffEntryRel = (UINT16 *)(CoffBaseRel + 1);
551 CoffOffset += sizeof(EFI_IMAGE_BASE_RELOCATION);
552 }
553
554 //
555 // Fill the entry.
556 //
557 CoffAddFixupEntry((Type << 12) | (Offset & 0xfff));
558 }
559
560 void
561 WriteRelocations(
562 VOID
563 )
564 {
565 UINT32 Idx;
566 EFI_IMAGE_NT_HEADERS *NtHdr;
567 EFI_IMAGE_DATA_DIRECTORY *Dir;
568
569 for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
570 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
571 if (RelShdr->sh_type == SHT_REL) {
572 Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
573 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
574 UINT32 RelIdx;
575 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
576 Elf_Rel *Rel = (Elf_Rel *)
577 ((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
578 switch (ELF_R_TYPE(Rel->r_info)) {
579 case R_386_NONE:
580 case R_386_PC32:
581 break;
582 case R_386_32:
583 CoffAddFixup(CoffSectionsOffset[RelShdr->sh_info]
584 + (Rel->r_offset - SecShdr->sh_addr),
585 EFI_IMAGE_REL_BASED_HIGHLOW);
586 break;
587 default:
588 Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
589 ELF_R_TYPE(Rel->r_info));
590 }
591 }
592 }
593 }
594 }
595
596 //
597 // Pad by adding empty entries.
598 //
599 while (CoffOffset & (CoffAlignment - 1)) {
600 CoffAddFixupEntry(0);
601 }
602
603 CreateSectionHeader (".reloc", RelocOffset, CoffOffset - RelocOffset,
604 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
605 | EFI_IMAGE_SCN_MEM_DISCARDABLE
606 | EFI_IMAGE_SCN_MEM_READ);
607
608 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
609 Dir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
610 Dir->VirtualAddress = RelocOffset;
611 Dir->Size = CoffOffset - RelocOffset;
612 }
613
614 void
615 WriteDebug(
616 VOID
617 )
618 {
619 UINT32 Len = strlen(InImageName) + 1;
620 UINT32 DebugOffset = CoffOffset;
621 EFI_IMAGE_NT_HEADERS *NtHdr;
622 EFI_IMAGE_DATA_DIRECTORY *DataDir;
623 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
624 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
625
626 CoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)
627 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)
628 + Len;
629 CoffOffset = CoffAlign(CoffOffset);
630
631 CoffFile = realloc
632 (CoffFile, CoffOffset);
633 memset(CoffFile + DebugOffset, 0, CoffOffset - DebugOffset);
634
635 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(CoffFile + DebugOffset);
636 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
637 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + Len;
638 Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
639 Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
640
641 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
642 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
643 strcpy ((PUCHAR)(Nb10 + 1), InImageName);
644
645 CreateSectionHeader (".debug", DebugOffset, CoffOffset - DebugOffset,
646 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
647 | EFI_IMAGE_SCN_MEM_DISCARDABLE
648 | EFI_IMAGE_SCN_MEM_READ);
649
650 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
651 DataDir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
652 DataDir->VirtualAddress = DebugOffset;
653 DataDir->Size = CoffOffset - DebugOffset;
654 }
655
656 void
657 ConvertElf (
658 UINT8 **FileBuffer,
659 UINTN *FileLength
660 )
661 {
662 EFI_IMAGE_NT_HEADERS *NtHdr;
663
664 //
665 // Check header, read section table.
666 //
667 Ehdr = (Elf32_Ehdr*)*FileBuffer;
668 if (!CheckElfHeader())
669 return;
670
671 //
672 // Compute sections new address.
673 //
674 ScanSections();
675
676 //
677 // Write and relocate sections.
678 //
679 WriteSections(IsTextShdr);
680 WriteSections(IsDataShdr);
681
682 //
683 // Translate and write relocations.
684 //
685 WriteRelocations();
686
687 //
688 // Write debug info.
689 //
690 WriteDebug();
691
692 NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
693 NtHdr->OptionalHeader.SizeOfImage = CoffOffset;
694
695 //
696 // Replace.
697 //
698 free(*FileBuffer);
699 *FileBuffer = CoffFile;
700 *FileLength = CoffOffset;
701 }
702 #endif // HAVE_ELF
703
704 int
705 main (
706 int argc,
707 char *argv[]
708 )
709 /*++
710
711 Routine Description:
712
713 Main function.
714
715 Arguments:
716
717 argc - Number of command line parameters.
718 argv - Array of pointers to command line parameter strings.
719
720 Returns:
721 STATUS_SUCCESS - Utility exits successfully.
722 STATUS_ERROR - Some error occurred during execution.
723
724 --*/
725 {
726 ULONG Type;
727 PUCHAR Ext;
728 PUCHAR p;
729 PUCHAR pe;
730 PUCHAR OutImageName;
731 UCHAR outname[500];
732 FILE *fpIn;
733 FILE *fpOut;
734 VOID *ZeroBuffer;
735 EFI_IMAGE_DOS_HEADER *DosHdr;
736 EFI_IMAGE_NT_HEADERS *PeHdr;
737 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;
738 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;
739 time_t TimeStamp;
740 struct tm TimeStruct;
741 EFI_IMAGE_DOS_HEADER BackupDosHdr;
742 ULONG Index;
743 ULONG Index1;
744 ULONG Index2;
745 ULONG Index3;
746 BOOLEAN TimeStampPresent;
747 UINTN AllignedRelocSize;
748 UINTN Delta;
749 EFI_IMAGE_SECTION_HEADER *SectionHeader;
750 UINT8 *FileBuffer;
751 UINTN FileLength;
752 RUNTIME_FUNCTION *RuntimeFunction;
753 UNWIND_INFO *UnwindInfo;
754
755 SetUtilityName (UTILITY_NAME);
756 //
757 // Assign to fix compile warning
758 //
759 OutImageName = NULL;
760 Type = 0;
761 Ext = 0;
762 TimeStamp = 0;
763 TimeStampPresent = FALSE;
764
765 if (argc < 1) {
766 Usage();
767 return STATUS_ERROR;
768 }
769
770 if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||
771 (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {
772 Usage();
773 return STATUS_ERROR;
774 }
775
776 if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {
777 Version();
778 return STATUS_ERROR;
779 }
780
781 //
782 // Look for -t time-date option first. If the time is "0", then
783 // skip it.
784 //
785 if ((argc > 2) && !strcmp (argv[1], "-t")) {
786 TimeStampPresent = TRUE;
787 if (strcmp (argv[2], "0") != 0) {
788 //
789 // Convert the string to a value
790 //
791 memset ((char *) &TimeStruct, 0, sizeof (TimeStruct));
792 if (sscanf(
793 argv[2], "%d/%d/%d,%d:%d:%d",
794 &TimeStruct.tm_mon, /* months since January - [0,11] */
795 &TimeStruct.tm_mday, /* day of the month - [1,31] */
796 &TimeStruct.tm_year, /* years since 1900 */
797 &TimeStruct.tm_hour, /* hours since midnight - [0,23] */
798 &TimeStruct.tm_min, /* minutes after the hour - [0,59] */
799 &TimeStruct.tm_sec /* seconds after the minute - [0,59] */
800 ) != 6) {
801 Error (NULL, 0, 0, argv[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");
802 return STATUS_ERROR;
803 }
804 //
805 // Now fixup some of the fields
806 //
807 TimeStruct.tm_mon--;
808 TimeStruct.tm_year -= 1900;
809 //
810 // Sanity-check values?
811 // Convert
812 //
813 TimeStamp = mktime (&TimeStruct);
814 if (TimeStamp == (time_t) - 1) {
815 Error (NULL, 0, 0, argv[2], "failed to convert time");
816 return STATUS_ERROR;
817 }
818 }
819 //
820 // Skip over the args
821 //
822 argc -= 2;
823 argv += 2;
824 }
825 //
826 // Check for enough args
827 //
828 if (argc < 3) {
829 Usage ();
830 return STATUS_ERROR;
831 }
832
833 InImageName = argv[2];
834
835 if (argc == 4) {
836 OutImageName = argv[3];
837 }
838 //
839 // Get new image type
840 //
841 p = argv[1];
842 if (*p == '/' || *p == '\\') {
843 p += 1;
844 }
845
846 if (stricmp (p, "app") == 0 || stricmp (p, "UEFI_APPLICATION") == 0) {
847 Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
848 Ext = ".efi";
849
850 } else if (stricmp (p, "bsdrv") == 0 || stricmp (p, "DXE_DRIVER") == 0) {
851 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
852 Ext = ".efi";
853
854 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_RUNTIME_DRIVER") == 0) {
855 Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
856 Ext = ".efi";
857
858 } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_SAL_DRIVER") == 0) {
859 Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
860 Ext = ".efi";
861 } else if (stricmp (p, "SEC") == 0) {
862 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
863 Ext = ".sec";
864 } else if (stricmp (p, "peim") == 0 ||
865 stricmp (p, "BASE") == 0 ||
866 stricmp (p, "PEI_CORE") == 0 ||
867 stricmp (p, "PEIM") == 0 ||
868 stricmp (p, "DXE_SMM_DRIVER") == 0 ||
869 stricmp (p, "TOOL") == 0 ||
870 stricmp (p, "UEFI_APPLICATION") == 0 ||
871 stricmp (p, "USER_DEFINED") == 0 ||
872 stricmp (p, "UEFI_DRIVER") == 0 ||
873 stricmp (p, "DXE_CORE") == 0
874 ) {
875 Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
876 Ext = ".pei";
877 } else {
878 printf ("%s", p);
879 Usage ();
880 return STATUS_ERROR;
881 }
882 //
883 // open source file
884 //
885 fpIn = fopen (InImageName, "rb");
886 if (!fpIn) {
887 Error (NULL, 0, 0, InImageName, "failed to open input file for reading");
888 return STATUS_ERROR;
889 }
890
891 FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);
892
893 #ifdef HAVE_ELF
894 if (IsElfHeader(FileBuffer)) {
895 ConvertElf(&FileBuffer, &FileLength);
896 }
897 #endif
898 //
899 // Read the dos & pe hdrs of the image
900 //
901 DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;
902 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
903 Error (NULL, 0, 0, InImageName, "DOS header signature not found in source image");
904 fclose (fpIn);
905 return STATUS_ERROR;
906 }
907
908 PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);
909 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {
910 Error (NULL, 0, 0, InImageName, "PE header signature not found in source image");
911 fclose (fpIn);
912 return STATUS_ERROR;
913 }
914
915 //
916 // open output file
917 //
918 strcpy (outname, InImageName);
919 pe = NULL;
920 for (p = outname; *p; p++) {
921 if (*p == '.') {
922 pe = p;
923 }
924 }
925
926 if (!pe) {
927 pe = p;
928 }
929
930 strcpy (pe, Ext);
931
932 if (!OutImageName) {
933 OutImageName = outname;
934 }
935
936 fpOut = fopen (OutImageName, "w+b");
937 if (!fpOut) {
938 Error (NULL, 0, 0, OutImageName, "could not open output file for writing");
939 fclose (fpIn);
940 return STATUS_ERROR;
941 }
942
943 //
944 // Zero all unused fields of the DOS header
945 //
946 memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));
947 memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));
948 DosHdr->e_magic = BackupDosHdr.e_magic;
949 DosHdr->e_lfanew = BackupDosHdr.e_lfanew;
950
951 for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {
952 FileBuffer[Index] = DosHdr->e_cp;
953 }
954
955 //
956 // Patch the PE header
957 //
958 PeHdr->OptionalHeader.Subsystem = (USHORT) Type;
959 if (TimeStampPresent) {
960 PeHdr->FileHeader.TimeDateStamp = (UINT32) TimeStamp;
961 }
962
963 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
964 Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;
965 Optional32->MajorLinkerVersion = 0;
966 Optional32->MinorLinkerVersion = 0;
967 Optional32->MajorOperatingSystemVersion = 0;
968 Optional32->MinorOperatingSystemVersion = 0;
969 Optional32->MajorImageVersion = 0;
970 Optional32->MinorImageVersion = 0;
971 Optional32->MajorSubsystemVersion = 0;
972 Optional32->MinorSubsystemVersion = 0;
973 Optional32->Win32VersionValue = 0;
974 Optional32->CheckSum = 0;
975 Optional32->SizeOfStackReserve = 0;
976 Optional32->SizeOfStackCommit = 0;
977 Optional32->SizeOfHeapReserve = 0;
978 Optional32->SizeOfHeapCommit = 0;
979
980 //
981 // Strip zero padding at the end of the .reloc section
982 //
983 if (Optional32->NumberOfRvaAndSizes >= 6) {
984 if (Optional32->DataDirectory[5].Size != 0) {
985 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
986 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
987 //
988 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
989 //
990 if (SectionHeader->VirtualAddress == Optional32->DataDirectory[5].VirtualAddress) {
991 SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[5].Size;
992 AllignedRelocSize = (Optional32->DataDirectory[5].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));
993 //
994 // Check to see if there is zero padding at the end of the base relocations
995 //
996 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
997 //
998 // Check to see if the base relocations are at the end of the file
999 //
1000 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {
1001 //
1002 // All the required conditions are met to strip the zero padding of the end of the base relocations section
1003 //
1004 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
1005 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
1006 SectionHeader->SizeOfRawData = AllignedRelocSize;
1007 FileLength = Optional32->SizeOfImage;
1008 }
1009 }
1010 }
1011 }
1012 }
1013 }
1014 }
1015 if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1016 Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;
1017 Optional64->MajorLinkerVersion = 0;
1018 Optional64->MinorLinkerVersion = 0;
1019 Optional64->MajorOperatingSystemVersion = 0;
1020 Optional64->MinorOperatingSystemVersion = 0;
1021 Optional64->MajorImageVersion = 0;
1022 Optional64->MinorImageVersion = 0;
1023 Optional64->MajorSubsystemVersion = 0;
1024 Optional64->MinorSubsystemVersion = 0;
1025 Optional64->Win32VersionValue = 0;
1026 Optional64->CheckSum = 0;
1027 Optional64->SizeOfStackReserve = 0;
1028 Optional64->SizeOfStackCommit = 0;
1029 Optional64->SizeOfHeapReserve = 0;
1030 Optional64->SizeOfHeapCommit = 0;
1031
1032 //
1033 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty
1034 //
1035 if (PeHdr->FileHeader.Machine == 0x8664) { // X64
1036 if (Optional64->NumberOfRvaAndSizes >= 4) {
1037 if (Optional64->NumberOfRvaAndSizes < 7 || (Optional64->NumberOfRvaAndSizes >= 7 && Optional64->DataDirectory[6].Size == 0)) {
1038 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
1039 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
1040 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[3].VirtualAddress) {
1041 RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData);
1042 for (Index1 = 0; Index1 < Optional64->DataDirectory[3].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) {
1043 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
1044 for (Index2 = 0; Index2 < PeHdr->FileHeader.NumberOfSections; Index2++, SectionHeader++) {
1045 if (RuntimeFunction->UnwindInfoAddress > SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) {
1046 UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress));
1047 if (UnwindInfo->Version == 1) {
1048 memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16));
1049 memset (UnwindInfo, 0, sizeof (UNWIND_INFO));
1050 }
1051 }
1052 }
1053 memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION));
1054 }
1055
1056 break;
1057 }
1058 }
1059 Optional64->DataDirectory[3].Size = 0;
1060 Optional64->DataDirectory[3].VirtualAddress = 0;
1061 }
1062 }
1063 }
1064
1065 //
1066 // Strip zero padding at the end of the .reloc section
1067 //
1068 if (Optional64->NumberOfRvaAndSizes >= 6) {
1069 if (Optional64->DataDirectory[5].Size != 0) {
1070 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
1071 for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
1072 //
1073 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
1074 //
1075 if (SectionHeader->VirtualAddress == Optional64->DataDirectory[5].VirtualAddress) {
1076 SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[5].Size;
1077 AllignedRelocSize = (Optional64->DataDirectory[5].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));
1078 //
1079 // Check to see if there is zero padding at the end of the base relocations
1080 //
1081 if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
1082 //
1083 // Check to see if the base relocations are at the end of the file
1084 //
1085 if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {
1086 //
1087 // All the required conditions are met to strip the zero padding of the end of the base relocations section
1088 //
1089 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
1090 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
1091 SectionHeader->SizeOfRawData = AllignedRelocSize;
1092 FileLength = Optional64->SizeOfImage;
1093 }
1094 }
1095 }
1096 }
1097 }
1098 }
1099 }
1100
1101 FWriteFile (fpOut, FileBuffer, FileLength);
1102
1103 //
1104 // Done
1105 //
1106 fclose (fpIn);
1107 fclose (fpOut);
1108 //
1109 // printf ("Created %s\n", OutImageName);
1110 //
1111 return STATUS_SUCCESS;
1112 }