3 Copyright (c) 2004 - 2007, 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
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.
18 Converts a pe32+ image to an FW image type
22 #include "WinNtInclude.h"
25 // List of OS and CPU which support ELF to PE conversion
45 #include <Common/UefiBaseTypes.h>
46 #include <Common/EfiImage.h>
48 #include "CommonLib.h"
49 #include "EfiUtilityMsgs.c"
52 // Version of this utility
54 #define UTILITY_NAME "FwImage"
55 #define UTILITY_MAJOR_VERSION 1
56 #define UTILITY_MINOR_VERSION 0
59 typedef unsigned long ULONG
;
60 typedef unsigned char UCHAR
;
61 typedef unsigned char *PUCHAR
;
62 typedef unsigned short USHORT
;
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");
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");
100 UCHAR Buffer
[8 * 1024];
102 fseek (in
, 0, SEEK_END
);
103 filesize
= ftell (in
);
105 fseek (in
, 0, SEEK_SET
);
106 fseek (out
, 0, SEEK_SET
);
109 while (offset
< filesize
) {
110 length
= sizeof (Buffer
);
111 if (filesize
- offset
< length
) {
112 length
= filesize
- offset
;
115 fread (Buffer
, length
, 1, in
);
116 fwrite (Buffer
, length
, 1, out
);
120 if ((ULONG
) ftell (out
) != filesize
) {
121 Error (NULL
, 0, 0, "write error", NULL
);
125 return STATUS_SUCCESS
;
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
;
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
);
159 return STATUS_SUCCESS
;
168 return (FileBuffer
[EI_MAG0
] == ELFMAG0
169 && FileBuffer
[EI_MAG1
] == ELFMAG1
170 && FileBuffer
[EI_MAG2
] == ELFMAG2
171 && FileBuffer
[EI_MAG3
] == ELFMAG3
);
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)
183 // Well known ELF structures.
189 // PE section alignment.
191 const UINT32 CoffAlignment
= 0x20;
192 const UINT32 CoffNbrSections
= 4;
195 // Current offset in coff file.
200 // Result Coff file in memory.
205 // Offset in Coff file of headers and sections.
214 // ELF sections to offset in Coff file.
216 UINT32
*CoffSectionsOffset
;
218 EFI_IMAGE_BASE_RELOCATION
*CoffBaseRel
;
219 UINT16
*CoffEntryRel
;
226 return (Offset
+ CoffAlignment
- 1) & ~(CoffAlignment
- 1);
234 if (Num
>= Ehdr
->e_shnum
)
236 return (Elf_Shdr
*)((UINT8
*)ShdrBase
+ Num
* Ehdr
->e_shentsize
);
245 // Note: Magic has already been tested.
247 if (Ehdr
->e_ident
[EI_CLASS
] != ELFCLASS
)
249 if (Ehdr
->e_ident
[EI_DATA
] != ELFDATA2LSB
)
251 if (Ehdr
->e_type
!= ET_EXEC
)
253 if (Ehdr
->e_machine
!= EM_386
)
255 if (Ehdr
->e_version
!= EV_CURRENT
)
259 // Find the section header table
261 ShdrBase
= (Elf_Shdr
*)((UINT8
*)Ehdr
+ Ehdr
->e_shoff
);
263 CoffSectionsOffset
= (UINT32
*)malloc(Ehdr
->e_shnum
* sizeof (UINT32
));
265 memset(CoffSectionsOffset
, 0, Ehdr
->e_shnum
* sizeof(UINT32
));
274 return (Shdr
->sh_flags
& (SHF_WRITE
| SHF_ALLOC
)) == SHF_ALLOC
;
282 return (Shdr
->sh_flags
& (SHF_WRITE
| SHF_ALLOC
)) == (SHF_ALLOC
| SHF_WRITE
);
293 EFI_IMAGE_SECTION_HEADER
*Hdr
;
294 Hdr
= (EFI_IMAGE_SECTION_HEADER
*)(CoffFile
+ TableOffset
);
296 strcpy(Hdr
->Name
, Name
);
297 Hdr
->Misc
.VirtualSize
= Size
;
298 Hdr
->VirtualAddress
= Offset
;
299 Hdr
->SizeOfRawData
= Size
;
300 Hdr
->PointerToRawData
= Offset
;
301 Hdr
->PointerToRelocations
= 0;
302 Hdr
->PointerToLinenumbers
= 0;
303 Hdr
->NumberOfRelocations
= 0;
304 Hdr
->NumberOfLinenumbers
= 0;
305 Hdr
->Characteristics
= Flags
;
307 TableOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
316 EFI_IMAGE_DOS_HEADER
*DosHdr
;
317 EFI_IMAGE_NT_HEADERS
*NtHdr
;
318 UINT32 CoffEntry
= 0;
323 // Coff file start with a DOS header.
325 CoffOffset
= sizeof(EFI_IMAGE_DOS_HEADER
) + 0x40;
326 NtHdrOffset
= CoffOffset
;
327 CoffOffset
+= sizeof(EFI_IMAGE_NT_HEADERS
);
328 TableOffset
= CoffOffset
;
329 CoffOffset
+= CoffNbrSections
* sizeof(EFI_IMAGE_SECTION_HEADER
);
332 // First text sections.
334 CoffOffset
= CoffAlign(CoffOffset
);
335 TextOffset
= CoffOffset
;
336 for (i
= 0; i
< Ehdr
->e_shnum
; i
++) {
337 Elf_Shdr
*shdr
= GetShdrByIndex(i
);
338 if (IsTextShdr(shdr
)) {
340 // Align the coff offset to meet with the alignment requirement of section
343 if ((shdr
->sh_addralign
!= 0) && (shdr
->sh_addralign
!= 1)) {
344 CoffOffset
= (CoffOffset
+ shdr
->sh_addralign
- 1) & ~(shdr
->sh_addralign
- 1);
347 /* Relocate entry. */
348 if ((Ehdr
->e_entry
>= shdr
->sh_addr
) &&
349 (Ehdr
->e_entry
< shdr
->sh_addr
+ shdr
->sh_size
)) {
350 CoffEntry
= CoffOffset
+ Ehdr
->e_entry
- shdr
->sh_addr
;
352 CoffSectionsOffset
[i
] = CoffOffset
;
353 CoffOffset
+= shdr
->sh_size
;
356 CoffOffset
= CoffAlign(CoffOffset
);
359 // Then data sections.
361 DataOffset
= CoffOffset
;
362 for (i
= 0; i
< Ehdr
->e_shnum
; i
++) {
363 Elf_Shdr
*shdr
= GetShdrByIndex(i
);
364 if (IsDataShdr(shdr
)) {
366 // Align the coff offset to meet with the alignment requirement of section
369 if ((shdr
->sh_addralign
!= 0) && (shdr
->sh_addralign
!= 1)) {
370 CoffOffset
= (CoffOffset
+ shdr
->sh_addralign
- 1) & ~(shdr
->sh_addralign
- 1);
373 CoffSectionsOffset
[i
] = CoffOffset
;
374 CoffOffset
+= shdr
->sh_size
;
377 CoffOffset
= CoffAlign(CoffOffset
);
379 RelocOffset
= CoffOffset
;
382 // Allocate base Coff file. Will be expanded later for relocations.
384 CoffFile
= (UINT8
*)malloc(CoffOffset
);
385 memset(CoffFile
, 0, CoffOffset
);
390 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)CoffFile
;
391 DosHdr
->e_magic
= EFI_IMAGE_DOS_SIGNATURE
;
392 DosHdr
->e_lfanew
= NtHdrOffset
;
394 NtHdr
= (EFI_IMAGE_NT_HEADERS
*)(CoffFile
+ NtHdrOffset
);
396 NtHdr
->Signature
= EFI_IMAGE_NT_SIGNATURE
;
398 NtHdr
->FileHeader
.Machine
= EFI_IMAGE_MACHINE_IA32
;
399 NtHdr
->FileHeader
.NumberOfSections
= CoffNbrSections
;
400 NtHdr
->FileHeader
.TimeDateStamp
= time(NULL
);
401 NtHdr
->FileHeader
.PointerToSymbolTable
= 0;
402 NtHdr
->FileHeader
.NumberOfSymbols
= 0;
403 NtHdr
->FileHeader
.SizeOfOptionalHeader
= sizeof(NtHdr
->OptionalHeader
);
404 NtHdr
->FileHeader
.Characteristics
= EFI_IMAGE_FILE_EXECUTABLE_IMAGE
405 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
406 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
407 | EFI_IMAGE_FILE_32BIT_MACHINE
;
409 NtHdr
->OptionalHeader
.Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
410 NtHdr
->OptionalHeader
.SizeOfCode
= DataOffset
- TextOffset
;
411 NtHdr
->OptionalHeader
.SizeOfInitializedData
= RelocOffset
- DataOffset
;
412 NtHdr
->OptionalHeader
.SizeOfUninitializedData
= 0;
413 NtHdr
->OptionalHeader
.AddressOfEntryPoint
= CoffEntry
;
414 NtHdr
->OptionalHeader
.BaseOfCode
= TextOffset
;
416 NtHdr
->OptionalHeader
.BaseOfData
= DataOffset
;
417 NtHdr
->OptionalHeader
.ImageBase
= 0;
418 NtHdr
->OptionalHeader
.SectionAlignment
= CoffAlignment
;
419 NtHdr
->OptionalHeader
.FileAlignment
= CoffAlignment
;
420 NtHdr
->OptionalHeader
.SizeOfImage
= 0;
422 NtHdr
->OptionalHeader
.SizeOfHeaders
= TextOffset
;
423 NtHdr
->OptionalHeader
.NumberOfRvaAndSizes
= EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
428 CreateSectionHeader (".text", TextOffset
, DataOffset
- TextOffset
,
429 EFI_IMAGE_SCN_CNT_CODE
430 | EFI_IMAGE_SCN_MEM_EXECUTE
431 | EFI_IMAGE_SCN_MEM_READ
);
432 CreateSectionHeader (".data", DataOffset
, RelocOffset
- DataOffset
,
433 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
434 | EFI_IMAGE_SCN_MEM_WRITE
435 | EFI_IMAGE_SCN_MEM_READ
);
440 int (*Filter
)(Elf_Shdr
*)
446 // First: copy sections.
448 for (Idx
= 0; Idx
< Ehdr
->e_shnum
; Idx
++) {
449 Elf_Shdr
*Shdr
= GetShdrByIndex(Idx
);
450 if ((*Filter
)(Shdr
)) {
451 switch (Shdr
->sh_type
) {
454 memcpy(CoffFile
+ CoffSectionsOffset
[Idx
],
455 (UINT8
*)Ehdr
+ Shdr
->sh_offset
,
459 memset(CoffFile
+ CoffSectionsOffset
[Idx
], 0, Shdr
->sh_size
);
462 Error (NULL
, 0, 0, InImageName
, "unhandle section type %x",
463 (UINTN
)Shdr
->sh_type
);
469 // Second: apply relocations.
471 for (Idx
= 0; Idx
< Ehdr
->e_shnum
; Idx
++) {
472 Elf_Shdr
*RelShdr
= GetShdrByIndex(Idx
);
473 if (RelShdr
->sh_type
!= SHT_REL
)
475 Elf_Shdr
*SecShdr
= GetShdrByIndex(RelShdr
->sh_info
);
476 UINT32 SecOffset
= CoffSectionsOffset
[RelShdr
->sh_info
];
477 if (RelShdr
->sh_type
== SHT_REL
&& (*Filter
)(SecShdr
)) {
479 Elf_Shdr
*SymtabShdr
= GetShdrByIndex(RelShdr
->sh_link
);
480 UINT8
*Symtab
= (UINT8
*)Ehdr
+ SymtabShdr
->sh_offset
;
482 for (RelIdx
= 0; RelIdx
< RelShdr
->sh_size
; RelIdx
+= RelShdr
->sh_entsize
) {
483 Elf_Rel
*Rel
= (Elf_Rel
*)((UINT8
*)Ehdr
+ RelShdr
->sh_offset
+ RelIdx
);
484 Elf_Sym
*Sym
= (Elf_Sym
*)
485 (Symtab
+ ELF_R_SYM(Rel
->r_info
) * SymtabShdr
->sh_entsize
);
489 if (Sym
->st_shndx
== SHN_UNDEF
490 || Sym
->st_shndx
== SHN_ABS
491 || Sym
->st_shndx
> Ehdr
->e_shnum
) {
492 Error (NULL
, 0, 0, InImageName
, "bad symbol definition");
494 SymShdr
= GetShdrByIndex(Sym
->st_shndx
);
497 // Note: r_offset in a memory address.
498 // Convert it to a pointer in the coff file.
500 Targ
= CoffFile
+ SecOffset
+ (Rel
->r_offset
- SecShdr
->sh_addr
);
502 switch (ELF_R_TYPE(Rel
->r_info
)) {
507 // Absolute relocation.
509 *(UINT32
*)Targ
= *(UINT32
*)Targ
- SymShdr
->sh_addr
510 + CoffSectionsOffset
[Sym
->st_shndx
];
514 // Relative relocation: Symbol - Ip + Addend
516 *(UINT32
*)Targ
= *(UINT32
*)Targ
517 + (CoffSectionsOffset
[Sym
->st_shndx
] - SymShdr
->sh_addr
)
518 - (SecOffset
- SecShdr
->sh_addr
);
521 Error (NULL
, 0, 0, InImageName
, "unhandled relocation type %x",
522 ELF_R_TYPE(Rel
->r_info
));
536 CoffBaseRel
->SizeOfBlock
+= 2;
546 if (CoffBaseRel
== NULL
547 || CoffBaseRel
->VirtualAddress
!= (Offset
& ~0xfff)) {
548 if (CoffBaseRel
!= NULL
) {
550 // Add a null entry (is it required ?)
552 CoffAddFixupEntry (0);
554 // Pad for alignment.
556 if (CoffOffset
% 4 != 0)
557 CoffAddFixupEntry (0);
562 CoffOffset
+ sizeof(EFI_IMAGE_BASE_RELOCATION
) + 2*0x1000);
563 memset(CoffFile
+ CoffOffset
, 0,
564 sizeof(EFI_IMAGE_BASE_RELOCATION
) + 2*0x1000);
566 CoffBaseRel
= (EFI_IMAGE_BASE_RELOCATION
*)(CoffFile
+ CoffOffset
);
567 CoffBaseRel
->VirtualAddress
= Offset
& ~0xfff;
568 CoffBaseRel
->SizeOfBlock
= sizeof(EFI_IMAGE_BASE_RELOCATION
);
570 CoffEntryRel
= (UINT16
*)(CoffBaseRel
+ 1);
571 CoffOffset
+= sizeof(EFI_IMAGE_BASE_RELOCATION
);
577 CoffAddFixupEntry((Type
<< 12) | (Offset
& 0xfff));
586 EFI_IMAGE_NT_HEADERS
*NtHdr
;
587 EFI_IMAGE_DATA_DIRECTORY
*Dir
;
589 for (Idx
= 0; Idx
< Ehdr
->e_shnum
; Idx
++) {
590 Elf_Shdr
*RelShdr
= GetShdrByIndex(Idx
);
591 if (RelShdr
->sh_type
== SHT_REL
) {
592 Elf_Shdr
*SecShdr
= GetShdrByIndex(RelShdr
->sh_info
);
593 if (IsTextShdr(SecShdr
) || IsDataShdr(SecShdr
)) {
595 for (RelIdx
= 0; RelIdx
< RelShdr
->sh_size
; RelIdx
+= RelShdr
->sh_entsize
) {
596 Elf_Rel
*Rel
= (Elf_Rel
*)
597 ((UINT8
*)Ehdr
+ RelShdr
->sh_offset
+ RelIdx
);
598 switch (ELF_R_TYPE(Rel
->r_info
)) {
603 CoffAddFixup(CoffSectionsOffset
[RelShdr
->sh_info
]
604 + (Rel
->r_offset
- SecShdr
->sh_addr
),
605 EFI_IMAGE_REL_BASED_HIGHLOW
);
608 Error (NULL
, 0, 0, InImageName
, "unhandled relocation type %x",
609 ELF_R_TYPE(Rel
->r_info
));
617 // Pad by adding empty entries.
619 while (CoffOffset
& (CoffAlignment
- 1)) {
620 CoffAddFixupEntry(0);
623 CreateSectionHeader (".reloc", RelocOffset
, CoffOffset
- RelocOffset
,
624 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
625 | EFI_IMAGE_SCN_MEM_DISCARDABLE
626 | EFI_IMAGE_SCN_MEM_READ
);
628 NtHdr
= (EFI_IMAGE_NT_HEADERS
*)(CoffFile
+ NtHdrOffset
);
629 Dir
= &NtHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
630 Dir
->VirtualAddress
= RelocOffset
;
631 Dir
->Size
= CoffOffset
- RelocOffset
;
639 UINT32 Len
= strlen(InImageName
) + 1;
640 UINT32 DebugOffset
= CoffOffset
;
641 EFI_IMAGE_NT_HEADERS
*NtHdr
;
642 EFI_IMAGE_DATA_DIRECTORY
*DataDir
;
643 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*Dir
;
644 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
*Nb10
;
646 CoffOffset
+= sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)
647 + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
)
649 CoffOffset
= CoffAlign(CoffOffset
);
652 (CoffFile
, CoffOffset
);
653 memset(CoffFile
+ DebugOffset
, 0, CoffOffset
- DebugOffset
);
655 Dir
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(CoffFile
+ DebugOffset
);
656 Dir
->Type
= EFI_IMAGE_DEBUG_TYPE_CODEVIEW
;
657 Dir
->SizeOfData
= sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
) + Len
;
658 Dir
->RVA
= DebugOffset
+ sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
659 Dir
->FileOffset
= DebugOffset
+ sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
661 Nb10
= (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
*)(Dir
+ 1);
662 Nb10
->Signature
= CODEVIEW_SIGNATURE_NB10
;
663 strcpy ((PUCHAR
)(Nb10
+ 1), InImageName
);
665 CreateSectionHeader (".debug", DebugOffset
, CoffOffset
- DebugOffset
,
666 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
667 | EFI_IMAGE_SCN_MEM_DISCARDABLE
668 | EFI_IMAGE_SCN_MEM_READ
);
670 NtHdr
= (EFI_IMAGE_NT_HEADERS
*)(CoffFile
+ NtHdrOffset
);
671 DataDir
= &NtHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
];
672 DataDir
->VirtualAddress
= DebugOffset
;
673 DataDir
->Size
= CoffOffset
- DebugOffset
;
682 EFI_IMAGE_NT_HEADERS
*NtHdr
;
685 // Check header, read section table.
687 Ehdr
= (Elf32_Ehdr
*)*FileBuffer
;
688 if (!CheckElfHeader())
692 // Compute sections new address.
697 // Write and relocate sections.
699 WriteSections(IsTextShdr
);
700 WriteSections(IsDataShdr
);
703 // Translate and write relocations.
712 NtHdr
= (EFI_IMAGE_NT_HEADERS
*)(CoffFile
+ NtHdrOffset
);
713 NtHdr
->OptionalHeader
.SizeOfImage
= CoffOffset
;
719 *FileBuffer
= CoffFile
;
720 *FileLength
= CoffOffset
;
737 argc - Number of command line parameters.
738 argv - Array of pointers to command line parameter strings.
741 STATUS_SUCCESS - Utility exits successfully.
742 STATUS_ERROR - Some error occurred during execution.
755 EFI_IMAGE_DOS_HEADER
*DosHdr
;
756 EFI_IMAGE_NT_HEADERS
*PeHdr
;
757 EFI_IMAGE_OPTIONAL_HEADER32
*Optional32
;
758 EFI_IMAGE_OPTIONAL_HEADER64
*Optional64
;
760 struct tm TimeStruct
;
761 EFI_IMAGE_DOS_HEADER BackupDosHdr
;
766 BOOLEAN TimeStampPresent
;
767 UINTN AllignedRelocSize
;
769 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
772 RUNTIME_FUNCTION
*RuntimeFunction
;
773 UNWIND_INFO
*UnwindInfo
;
775 SetUtilityName (UTILITY_NAME
);
777 // Assign to fix compile warning
783 TimeStampPresent
= FALSE
;
790 if ((strcmp(argv
[1], "-h") == 0) || (strcmp(argv
[1], "--help") == 0) ||
791 (strcmp(argv
[1], "-?") == 0) || (strcmp(argv
[1], "/?") == 0)) {
796 if ((strcmp(argv
[1], "-V") == 0) || (strcmp(argv
[1], "--version") == 0)) {
802 // Look for -t time-date option first. If the time is "0", then
805 if ((argc
> 2) && !strcmp (argv
[1], "-t")) {
806 TimeStampPresent
= TRUE
;
807 if (strcmp (argv
[2], "0") != 0) {
809 // Convert the string to a value
811 memset ((char *) &TimeStruct
, 0, sizeof (TimeStruct
));
813 argv
[2], "%d/%d/%d,%d:%d:%d",
814 &TimeStruct
.tm_mon
, /* months since January - [0,11] */
815 &TimeStruct
.tm_mday
, /* day of the month - [1,31] */
816 &TimeStruct
.tm_year
, /* years since 1900 */
817 &TimeStruct
.tm_hour
, /* hours since midnight - [0,23] */
818 &TimeStruct
.tm_min
, /* minutes after the hour - [0,59] */
819 &TimeStruct
.tm_sec
/* seconds after the minute - [0,59] */
821 Error (NULL
, 0, 0, argv
[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");
825 // Now fixup some of the fields
828 TimeStruct
.tm_year
-= 1900;
830 // Sanity-check values?
833 TimeStamp
= mktime (&TimeStruct
);
834 if (TimeStamp
== (time_t) - 1) {
835 Error (NULL
, 0, 0, argv
[2], "failed to convert time");
840 // Skip over the args
846 // Check for enough args
853 InImageName
= argv
[2];
856 OutImageName
= argv
[3];
859 // Get new image type
862 if (*p
== '/' || *p
== '\\') {
866 if (stricmp (p
, "app") == 0 || stricmp (p
, "UEFI_APPLICATION") == 0) {
867 Type
= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
;
870 } else if (stricmp (p
, "bsdrv") == 0 || stricmp (p
, "DXE_DRIVER") == 0) {
871 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
874 } else if (stricmp (p
, "rtdrv") == 0 || stricmp (p
, "DXE_RUNTIME_DRIVER") == 0) {
875 Type
= EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
;
878 } else if (stricmp (p
, "rtdrv") == 0 || stricmp (p
, "DXE_SAL_DRIVER") == 0) {
879 Type
= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
;
881 } else if (stricmp (p
, "SEC") == 0) {
882 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
884 } else if (stricmp (p
, "peim") == 0 ||
885 stricmp (p
, "BASE") == 0 ||
886 stricmp (p
, "PEI_CORE") == 0 ||
887 stricmp (p
, "PEIM") == 0 ||
888 stricmp (p
, "DXE_SMM_DRIVER") == 0 ||
889 stricmp (p
, "TOOL") == 0 ||
890 stricmp (p
, "UEFI_APPLICATION") == 0 ||
891 stricmp (p
, "USER_DEFINED") == 0 ||
892 stricmp (p
, "UEFI_DRIVER") == 0 ||
893 stricmp (p
, "DXE_CORE") == 0
895 Type
= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
;
905 fpIn
= fopen (InImageName
, "rb");
907 Error (NULL
, 0, 0, InImageName
, "failed to open input file for reading");
911 FReadFile (fpIn
, (VOID
**)&FileBuffer
, &FileLength
);
914 if (IsElfHeader(FileBuffer
)) {
915 ConvertElf(&FileBuffer
, &FileLength
);
919 // Read the dos & pe hdrs of the image
921 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)FileBuffer
;
922 if (DosHdr
->e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
923 Error (NULL
, 0, 0, InImageName
, "DOS header signature not found in source image");
928 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)(FileBuffer
+ DosHdr
->e_lfanew
);
929 if (PeHdr
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
930 Error (NULL
, 0, 0, InImageName
, "PE header signature not found in source image");
938 strcpy (outname
, InImageName
);
940 for (p
= outname
; *p
; p
++) {
953 OutImageName
= outname
;
956 fpOut
= fopen (OutImageName
, "w+b");
958 Error (NULL
, 0, 0, OutImageName
, "could not open output file for writing");
964 // Zero all unused fields of the DOS header
966 memcpy (&BackupDosHdr
, DosHdr
, sizeof (EFI_IMAGE_DOS_HEADER
));
967 memset (DosHdr
, 0, sizeof (EFI_IMAGE_DOS_HEADER
));
968 DosHdr
->e_magic
= BackupDosHdr
.e_magic
;
969 DosHdr
->e_lfanew
= BackupDosHdr
.e_lfanew
;
971 for (Index
= sizeof (EFI_IMAGE_DOS_HEADER
); Index
< (ULONG
) DosHdr
->e_lfanew
; Index
++) {
972 FileBuffer
[Index
] = DosHdr
->e_cp
;
976 // Patch the PE header
978 PeHdr
->OptionalHeader
.Subsystem
= (USHORT
) Type
;
979 if (TimeStampPresent
) {
980 PeHdr
->FileHeader
.TimeDateStamp
= (UINT32
) TimeStamp
;
983 if (PeHdr
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
984 Optional32
= (EFI_IMAGE_OPTIONAL_HEADER32
*)&PeHdr
->OptionalHeader
;
985 Optional32
->MajorLinkerVersion
= 0;
986 Optional32
->MinorLinkerVersion
= 0;
987 Optional32
->MajorOperatingSystemVersion
= 0;
988 Optional32
->MinorOperatingSystemVersion
= 0;
989 Optional32
->MajorImageVersion
= 0;
990 Optional32
->MinorImageVersion
= 0;
991 Optional32
->MajorSubsystemVersion
= 0;
992 Optional32
->MinorSubsystemVersion
= 0;
993 Optional32
->Win32VersionValue
= 0;
994 Optional32
->CheckSum
= 0;
995 Optional32
->SizeOfStackReserve
= 0;
996 Optional32
->SizeOfStackCommit
= 0;
997 Optional32
->SizeOfHeapReserve
= 0;
998 Optional32
->SizeOfHeapCommit
= 0;
1001 // Strip zero padding at the end of the .reloc section
1003 if (Optional32
->NumberOfRvaAndSizes
>= 6) {
1004 if (Optional32
->DataDirectory
[5].Size
!= 0) {
1005 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->FileHeader
.SizeOfOptionalHeader
);
1006 for (Index
= 0; Index
< PeHdr
->FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
1008 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
1010 if (SectionHeader
->VirtualAddress
== Optional32
->DataDirectory
[5].VirtualAddress
) {
1011 SectionHeader
->Misc
.VirtualSize
= Optional32
->DataDirectory
[5].Size
;
1012 AllignedRelocSize
= (Optional32
->DataDirectory
[5].Size
+ Optional32
->FileAlignment
- 1) & (~(Optional32
->FileAlignment
- 1));
1014 // Check to see if there is zero padding at the end of the base relocations
1016 if (AllignedRelocSize
< SectionHeader
->SizeOfRawData
) {
1018 // Check to see if the base relocations are at the end of the file
1020 if (SectionHeader
->PointerToRawData
+ SectionHeader
->SizeOfRawData
== Optional32
->SizeOfImage
) {
1022 // All the required conditions are met to strip the zero padding of the end of the base relocations section
1024 Optional32
->SizeOfImage
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
1025 Optional32
->SizeOfInitializedData
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
1026 SectionHeader
->SizeOfRawData
= AllignedRelocSize
;
1027 FileLength
= Optional32
->SizeOfImage
;
1035 if (PeHdr
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
1036 Optional64
= (EFI_IMAGE_OPTIONAL_HEADER64
*)&PeHdr
->OptionalHeader
;
1037 Optional64
->MajorLinkerVersion
= 0;
1038 Optional64
->MinorLinkerVersion
= 0;
1039 Optional64
->MajorOperatingSystemVersion
= 0;
1040 Optional64
->MinorOperatingSystemVersion
= 0;
1041 Optional64
->MajorImageVersion
= 0;
1042 Optional64
->MinorImageVersion
= 0;
1043 Optional64
->MajorSubsystemVersion
= 0;
1044 Optional64
->MinorSubsystemVersion
= 0;
1045 Optional64
->Win32VersionValue
= 0;
1046 Optional64
->CheckSum
= 0;
1047 Optional64
->SizeOfStackReserve
= 0;
1048 Optional64
->SizeOfStackCommit
= 0;
1049 Optional64
->SizeOfHeapReserve
= 0;
1050 Optional64
->SizeOfHeapCommit
= 0;
1053 // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty
1055 if (PeHdr
->FileHeader
.Machine
== 0x8664) { // X64
1056 if (Optional64
->NumberOfRvaAndSizes
>= 4) {
1057 if (Optional64
->NumberOfRvaAndSizes
< 7 || (Optional64
->NumberOfRvaAndSizes
>= 7 && Optional64
->DataDirectory
[6].Size
== 0)) {
1058 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->FileHeader
.SizeOfOptionalHeader
);
1059 for (Index
= 0; Index
< PeHdr
->FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
1060 if (SectionHeader
->VirtualAddress
== Optional64
->DataDirectory
[3].VirtualAddress
) {
1061 RuntimeFunction
= (RUNTIME_FUNCTION
*)(FileBuffer
+ SectionHeader
->PointerToRawData
);
1062 for (Index1
= 0; Index1
< Optional64
->DataDirectory
[3].Size
/ sizeof (RUNTIME_FUNCTION
); Index1
++, RuntimeFunction
++) {
1063 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->FileHeader
.SizeOfOptionalHeader
);
1064 for (Index2
= 0; Index2
< PeHdr
->FileHeader
.NumberOfSections
; Index2
++, SectionHeader
++) {
1065 if (RuntimeFunction
->UnwindInfoAddress
> SectionHeader
->VirtualAddress
&& RuntimeFunction
->UnwindInfoAddress
< (SectionHeader
->VirtualAddress
+ SectionHeader
->SizeOfRawData
)) {
1066 UnwindInfo
= (UNWIND_INFO
*)(FileBuffer
+ SectionHeader
->PointerToRawData
+ (RuntimeFunction
->UnwindInfoAddress
- SectionHeader
->VirtualAddress
));
1067 if (UnwindInfo
->Version
== 1) {
1068 memset (UnwindInfo
+ 1, 0, UnwindInfo
->CountOfUnwindCodes
* sizeof (UINT16
));
1069 memset (UnwindInfo
, 0, sizeof (UNWIND_INFO
));
1073 memset (RuntimeFunction
, 0, sizeof (RUNTIME_FUNCTION
));
1079 Optional64
->DataDirectory
[3].Size
= 0;
1080 Optional64
->DataDirectory
[3].VirtualAddress
= 0;
1086 // Strip zero padding at the end of the .reloc section
1088 if (Optional64
->NumberOfRvaAndSizes
>= 6) {
1089 if (Optional64
->DataDirectory
[5].Size
!= 0) {
1090 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*)(FileBuffer
+ DosHdr
->e_lfanew
+ sizeof(UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + PeHdr
->FileHeader
.SizeOfOptionalHeader
);
1091 for (Index
= 0; Index
< PeHdr
->FileHeader
.NumberOfSections
; Index
++, SectionHeader
++) {
1093 // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
1095 if (SectionHeader
->VirtualAddress
== Optional64
->DataDirectory
[5].VirtualAddress
) {
1096 SectionHeader
->Misc
.VirtualSize
= Optional64
->DataDirectory
[5].Size
;
1097 AllignedRelocSize
= (Optional64
->DataDirectory
[5].Size
+ Optional64
->FileAlignment
- 1) & (~(Optional64
->FileAlignment
- 1));
1099 // Check to see if there is zero padding at the end of the base relocations
1101 if (AllignedRelocSize
< SectionHeader
->SizeOfRawData
) {
1103 // Check to see if the base relocations are at the end of the file
1105 if (SectionHeader
->PointerToRawData
+ SectionHeader
->SizeOfRawData
== Optional64
->SizeOfImage
) {
1107 // All the required conditions are met to strip the zero padding of the end of the base relocations section
1109 Optional64
->SizeOfImage
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
1110 Optional64
->SizeOfInitializedData
-= (SectionHeader
->SizeOfRawData
- AllignedRelocSize
);
1111 SectionHeader
->SizeOfRawData
= AllignedRelocSize
;
1112 FileLength
= Optional64
->SizeOfImage
;
1121 FWriteFile (fpOut
, FileBuffer
, FileLength
);
1129 // printf ("Created %s\n", OutImageName);
1131 return STATUS_SUCCESS
;