git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2555 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1133 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1133 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| Copyright (c) 2004 - 2007, Intel Corporation                                                         
 | |
| All rights reserved. This program and the accompanying materials                          
 | |
| are licensed and made available under the terms and conditions of the BSD License         
 | |
| which accompanies this distribution.  The full text of the license may be found at        
 | |
| http://opensource.org/licenses/bsd-license.php                                            
 | |
|                                                                                           
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|     fwimage.c
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|     Converts a pe32+ image to an FW image type
 | |
| 
 | |
| --*/
 | |
| 
 | |
| #include "WinNtInclude.h"
 | |
| 
 | |
| //
 | |
| // List of OS and CPU which support ELF to PE conversion
 | |
| //
 | |
| #if defined(linux)
 | |
| #if defined (__i386__) || defined(__x86_64__)
 | |
| #define HAVE_ELF
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #ifndef __GNUC__
 | |
| #include <windows.h>
 | |
| #endif
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <time.h>
 | |
| 
 | |
| #ifdef HAVE_ELF
 | |
| #include <elf.h>
 | |
| #endif
 | |
| 
 | |
| #include <Common/UefiBaseTypes.h>
 | |
| #include <Common/EfiImage.h>
 | |
| 
 | |
| #include "CommonLib.h"
 | |
| #include "EfiUtilityMsgs.c"
 | |
| 
 | |
| //
 | |
| // Version of this utility
 | |
| //
 | |
| #define UTILITY_NAME "FwImage"
 | |
| #define UTILITY_MAJOR_VERSION 1
 | |
| #define UTILITY_MINOR_VERSION 0
 | |
| 
 | |
| #ifdef __GNUC__
 | |
| typedef unsigned long ULONG;
 | |
| typedef unsigned char UCHAR;
 | |
| typedef unsigned char *PUCHAR;
 | |
| typedef unsigned short USHORT;
 | |
| #endif
 | |
| 
 | |
| PUCHAR            InImageName;
 | |
| 
 | |
| static
 | |
| void
 | |
| Version (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   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);
 | |
|   printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");
 | |
| }
 | |
| 
 | |
| 
 | |
| VOID
 | |
| Usage (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   Version();
 | |
|   printf ("\nUsage: " UTILITY_NAME "  {-t time-date} {-h|--help|-?|/?|-V|--version} \n\
 | |
|          [BASE|SEC|PEI_CORE|PEIM|DXE_CORE|DXE_DRIVER|DXE_RUNTIME_DRIVER|\n\
 | |
|          DXE_SAL_DRIVER|DXE_SMM_DRIVER|TOOL|UEFI_DRIVER|UEFI_APPLICATION|\n\
 | |
|          USER_DEFINED] peimage [outimage]\n");
 | |
| }
 | |
| 
 | |
| static
 | |
| STATUS
 | |
| FCopyFile (
 | |
|   FILE    *in,
 | |
|   FILE    *out
 | |
|   )
 | |
| {
 | |
|   ULONG filesize;
 | |
|   ULONG offset;
 | |
|   ULONG length;
 | |
|   UCHAR Buffer[8 * 1024];
 | |
| 
 | |
|   fseek (in, 0, SEEK_END);
 | |
|   filesize = ftell (in);
 | |
| 
 | |
|   fseek (in, 0, SEEK_SET);
 | |
|   fseek (out, 0, SEEK_SET);
 | |
| 
 | |
|   offset = 0;
 | |
|   while (offset < filesize) {
 | |
|     length = sizeof (Buffer);
 | |
|     if (filesize - offset < length) {
 | |
|       length = filesize - offset;
 | |
|     }
 | |
| 
 | |
|     fread (Buffer, length, 1, in);
 | |
|     fwrite (Buffer, length, 1, out);
 | |
|     offset += length;
 | |
|   }
 | |
| 
 | |
|   if ((ULONG) ftell (out) != filesize) {
 | |
|     Error (NULL, 0, 0, "write error", NULL);
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
| 
 | |
|   return STATUS_SUCCESS;
 | |
| }
 | |
| 
 | |
| static
 | |
| STATUS
 | |
| FReadFile (
 | |
|   FILE    *in,
 | |
|   VOID    **Buffer,
 | |
|   UINTN   *Length
 | |
|   )
 | |
| {
 | |
|   fseek (in, 0, SEEK_END);
 | |
|   *Length = ftell (in);
 | |
|   *Buffer = malloc (*Length);
 | |
|   fseek (in, 0, SEEK_SET);
 | |
|   fread (*Buffer, *Length, 1, in);
 | |
|   return STATUS_SUCCESS;
 | |
| }
 | |
| 
 | |
| static
 | |
| STATUS
 | |
| FWriteFile (
 | |
|   FILE    *out,
 | |
|   VOID    *Buffer,
 | |
|   UINTN   Length
 | |
|   )
 | |
| {
 | |
|   fseek (out, 0, SEEK_SET);
 | |
|   fwrite (Buffer, Length, 1, out);
 | |
|   if ((ULONG) ftell (out) != Length) {
 | |
|     Error (NULL, 0, 0, "write error", NULL);
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
|   free (Buffer);
 | |
|   return STATUS_SUCCESS;
 | |
| }
 | |
| 
 | |
| #ifdef HAVE_ELF
 | |
| INTN
 | |
| IsElfHeader(
 | |
|   UINT8	*FileBuffer
 | |
| )
 | |
| {
 | |
|   return (FileBuffer[EI_MAG0] == ELFMAG0
 | |
| 	  && FileBuffer[EI_MAG1] == ELFMAG1
 | |
| 	  && FileBuffer[EI_MAG2] == ELFMAG2
 | |
| 	  && FileBuffer[EI_MAG3] == ELFMAG3);
 | |
| }
 | |
| 
 | |
| typedef Elf32_Shdr Elf_Shdr;
 | |
| typedef Elf32_Ehdr Elf_Ehdr;
 | |
| typedef Elf32_Rel Elf_Rel;
 | |
| typedef Elf32_Sym Elf_Sym;
 | |
| #define ELFCLASS ELFCLASS32
 | |
| #define ELF_R_TYPE(r) ELF32_R_TYPE(r)
 | |
| #define ELF_R_SYM(r) ELF32_R_SYM(r)
 | |
| 
 | |
| //
 | |
| // Well known ELF structures.
 | |
| //
 | |
| Elf_Ehdr *Ehdr;
 | |
| Elf_Shdr *ShdrBase;
 | |
| 
 | |
| //
 | |
| // PE section alignment.
 | |
| //
 | |
| const UINT32 CoffAlignment = 0x20;
 | |
| const UINT32 CoffNbrSections = 4;
 | |
| 
 | |
| //
 | |
| // Current offset in coff file.
 | |
| //
 | |
| UINT32 CoffOffset;
 | |
| 
 | |
| //
 | |
| // Result Coff file in memory.
 | |
| //
 | |
| UINT8 *CoffFile;
 | |
| 
 | |
| //
 | |
| // Offset in Coff file of headers and sections.
 | |
| //
 | |
| UINT32 NtHdrOffset;
 | |
| UINT32 TableOffset;
 | |
| UINT32 TextOffset;
 | |
| UINT32 DataOffset;
 | |
| UINT32 RelocOffset;
 | |
| 
 | |
| //
 | |
| // ELF sections to offset in Coff file.
 | |
| //
 | |
| UINT32 *CoffSectionsOffset;
 | |
| 
 | |
| EFI_IMAGE_BASE_RELOCATION *CoffBaseRel;
 | |
| UINT16 *CoffEntryRel;
 | |
| 
 | |
| UINT32
 | |
| CoffAlign(
 | |
|   UINT32 Offset
 | |
|   )
 | |
| {
 | |
|   return (Offset + CoffAlignment - 1) & ~(CoffAlignment - 1);
 | |
| }
 | |
| 
 | |
| Elf_Shdr *
 | |
| GetShdrByIndex(
 | |
|   UINT32 Num
 | |
|   )
 | |
| {
 | |
|   if (Num >= Ehdr->e_shnum)
 | |
|     return NULL;
 | |
|   return (Elf_Shdr*)((UINT8*)ShdrBase + Num * Ehdr->e_shentsize);
 | |
| }
 | |
| 
 | |
| INTN
 | |
| CheckElfHeader(
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Note: Magic has already been tested.
 | |
|   //
 | |
|   if (Ehdr->e_ident[EI_CLASS] != ELFCLASS)
 | |
|     return 0;
 | |
|   if (Ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
 | |
|     return 0;
 | |
|   if (Ehdr->e_type != ET_EXEC)
 | |
|     return 0;
 | |
|   if (Ehdr->e_machine != EM_386)
 | |
|     return 0;
 | |
|   if (Ehdr->e_version != EV_CURRENT)
 | |
|     return 0;
 | |
| 
 | |
|   //
 | |
|   // Find the section header table
 | |
|   // 
 | |
|   ShdrBase = (Elf_Shdr *)((UINT8 *)Ehdr + Ehdr->e_shoff);
 | |
| 
 | |
|   CoffSectionsOffset = (UINT32 *)malloc(Ehdr->e_shnum * sizeof (UINT32));
 | |
| 
 | |
|   memset(CoffSectionsOffset, 0, Ehdr->e_shnum * sizeof(UINT32));
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| int
 | |
| IsTextShdr(
 | |
|   Elf_Shdr *Shdr
 | |
|   )
 | |
| {
 | |
|   return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC;
 | |
| }
 | |
| 
 | |
| int
 | |
| IsDataShdr(
 | |
|   Elf_Shdr *Shdr
 | |
|   )
 | |
| {
 | |
|   return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);
 | |
| }
 | |
| 
 | |
| void
 | |
| CreateSectionHeader(
 | |
|   const char *Name,
 | |
|   UINT32     Offset,
 | |
|   UINT32     Size,
 | |
|   UINT32     Flags
 | |
|   )
 | |
| {
 | |
|   EFI_IMAGE_SECTION_HEADER *Hdr;
 | |
|   Hdr = (EFI_IMAGE_SECTION_HEADER*)(CoffFile + TableOffset);
 | |
| 
 | |
|   strcpy(Hdr->Name, Name);
 | |
|   Hdr->Misc.VirtualSize = Size;
 | |
|   Hdr->VirtualAddress = Offset;
 | |
|   Hdr->SizeOfRawData = Size;
 | |
|   Hdr->PointerToRawData = Offset;
 | |
|   Hdr->PointerToRelocations = 0;
 | |
|   Hdr->PointerToLinenumbers = 0;
 | |
|   Hdr->NumberOfRelocations = 0;
 | |
|   Hdr->NumberOfLinenumbers = 0;
 | |
|   Hdr->Characteristics = Flags;
 | |
| 
 | |
|   TableOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
 | |
| }
 | |
| 
 | |
| void
 | |
| ScanSections(
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT32 i;
 | |
|   EFI_IMAGE_DOS_HEADER *DosHdr;
 | |
|   EFI_IMAGE_NT_HEADERS *NtHdr;
 | |
|   UINT32 CoffEntry = 0;
 | |
| 
 | |
|   CoffOffset = 0;
 | |
| 
 | |
|   //
 | |
|   // Coff file start with a DOS header.
 | |
|   //
 | |
|   CoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;
 | |
|   NtHdrOffset = CoffOffset;
 | |
|   CoffOffset += sizeof(EFI_IMAGE_NT_HEADERS);
 | |
|   TableOffset = CoffOffset;
 | |
|   CoffOffset += CoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);
 | |
| 
 | |
|   //
 | |
|   // First text sections.
 | |
|   //
 | |
|   CoffOffset = CoffAlign(CoffOffset);
 | |
|   TextOffset = CoffOffset;
 | |
|   for (i = 0; i < Ehdr->e_shnum; i++) {
 | |
|     Elf_Shdr *shdr = GetShdrByIndex(i);
 | |
|     if (IsTextShdr(shdr)) {
 | |
|       //
 | |
|       // Align the coff offset to meet with the alignment requirement of section
 | |
|       // itself.
 | |
|       // 
 | |
|       if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
 | |
|         CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
 | |
|       }
 | |
| 
 | |
|       /* Relocate entry.  */
 | |
|       if ((Ehdr->e_entry >= shdr->sh_addr) && 
 | |
|           (Ehdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
 | |
|         CoffEntry = CoffOffset + Ehdr->e_entry - shdr->sh_addr;
 | |
|       }
 | |
|       CoffSectionsOffset[i] = CoffOffset;
 | |
|       CoffOffset += shdr->sh_size;
 | |
|     }
 | |
|   }
 | |
|   CoffOffset = CoffAlign(CoffOffset);
 | |
| 
 | |
|   //
 | |
|   //  Then data sections.
 | |
|   //
 | |
|   DataOffset = CoffOffset;
 | |
|   for (i = 0; i < Ehdr->e_shnum; i++) {
 | |
|     Elf_Shdr *shdr = GetShdrByIndex(i);
 | |
|     if (IsDataShdr(shdr)) {
 | |
|       //
 | |
|       // Align the coff offset to meet with the alignment requirement of section
 | |
|       // itself.
 | |
|       // 
 | |
|       if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
 | |
|         CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
 | |
|       }
 | |
|      
 | |
|       CoffSectionsOffset[i] = CoffOffset;
 | |
|       CoffOffset += shdr->sh_size;
 | |
|     }
 | |
|   }
 | |
|   CoffOffset = CoffAlign(CoffOffset);
 | |
| 
 | |
|   RelocOffset = CoffOffset;  
 | |
| 
 | |
|   //
 | |
|   // Allocate base Coff file.  Will be expanded later for relocations. 
 | |
|   //
 | |
|   CoffFile = (UINT8 *)malloc(CoffOffset);
 | |
|   memset(CoffFile, 0, CoffOffset);
 | |
| 
 | |
|   //
 | |
|   // Fill headers.
 | |
|   //
 | |
|   DosHdr = (EFI_IMAGE_DOS_HEADER *)CoffFile;
 | |
|   DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
 | |
|   DosHdr->e_lfanew = NtHdrOffset;
 | |
| 
 | |
|   NtHdr = (EFI_IMAGE_NT_HEADERS*)(CoffFile + NtHdrOffset);
 | |
| 
 | |
|   NtHdr->Signature = EFI_IMAGE_NT_SIGNATURE;
 | |
| 
 | |
|   NtHdr->FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
 | |
|   NtHdr->FileHeader.NumberOfSections = CoffNbrSections;
 | |
|   NtHdr->FileHeader.TimeDateStamp = time(NULL);
 | |
|   NtHdr->FileHeader.PointerToSymbolTable = 0;
 | |
|   NtHdr->FileHeader.NumberOfSymbols = 0;
 | |
|   NtHdr->FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->OptionalHeader);
 | |
|   NtHdr->FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE
 | |
|     | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
 | |
|     | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
 | |
|     | EFI_IMAGE_FILE_32BIT_MACHINE;
 | |
|   
 | |
|   NtHdr->OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
 | |
|   NtHdr->OptionalHeader.SizeOfCode = DataOffset - TextOffset;
 | |
|   NtHdr->OptionalHeader.SizeOfInitializedData = RelocOffset - DataOffset;
 | |
|   NtHdr->OptionalHeader.SizeOfUninitializedData = 0;
 | |
|   NtHdr->OptionalHeader.AddressOfEntryPoint = CoffEntry;
 | |
|   NtHdr->OptionalHeader.BaseOfCode = TextOffset;
 | |
| 
 | |
|   NtHdr->OptionalHeader.BaseOfData = DataOffset;
 | |
|   NtHdr->OptionalHeader.ImageBase = 0;
 | |
|   NtHdr->OptionalHeader.SectionAlignment = CoffAlignment;
 | |
|   NtHdr->OptionalHeader.FileAlignment = CoffAlignment;
 | |
|   NtHdr->OptionalHeader.SizeOfImage = 0;
 | |
| 
 | |
|   NtHdr->OptionalHeader.SizeOfHeaders = TextOffset;
 | |
|   NtHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
 | |
| 
 | |
|   //
 | |
|   // Section headers.
 | |
|   //
 | |
|   CreateSectionHeader (".text", TextOffset, DataOffset - TextOffset,
 | |
| 		       EFI_IMAGE_SCN_CNT_CODE
 | |
| 		       | EFI_IMAGE_SCN_MEM_EXECUTE
 | |
| 		       | EFI_IMAGE_SCN_MEM_READ);
 | |
|   CreateSectionHeader (".data", DataOffset, RelocOffset - DataOffset,
 | |
| 		       EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
 | |
| 		       | EFI_IMAGE_SCN_MEM_WRITE
 | |
| 		       | EFI_IMAGE_SCN_MEM_READ);
 | |
| }
 | |
| 
 | |
| void
 | |
| WriteSections(
 | |
|   int	 (*Filter)(Elf_Shdr *)
 | |
|   )
 | |
| {
 | |
|   UINT32 Idx;
 | |
| 
 | |
|   //
 | |
|   // First: copy sections.
 | |
|   //
 | |
|   for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
 | |
|     Elf_Shdr *Shdr = GetShdrByIndex(Idx);
 | |
|     if ((*Filter)(Shdr)) {
 | |
|       switch (Shdr->sh_type) {
 | |
|       case SHT_PROGBITS:
 | |
| 	/* Copy.  */
 | |
| 	memcpy(CoffFile + CoffSectionsOffset[Idx],
 | |
| 	       (UINT8*)Ehdr + Shdr->sh_offset,
 | |
| 	       Shdr->sh_size);
 | |
| 	break;
 | |
|       case SHT_NOBITS:
 | |
| 	memset(CoffFile + CoffSectionsOffset[Idx], 0, Shdr->sh_size);
 | |
| 	break;
 | |
|       default:
 | |
| 	Error (NULL, 0, 0, InImageName, "unhandle section type %x",
 | |
| 	       (UINTN)Shdr->sh_type);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Second: apply relocations.
 | |
|   //
 | |
|   for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
 | |
|     Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
 | |
|     if (RelShdr->sh_type != SHT_REL)
 | |
|       continue;
 | |
|     Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
 | |
|     UINT32 SecOffset = CoffSectionsOffset[RelShdr->sh_info];
 | |
|     if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
 | |
|       UINT32 RelIdx;
 | |
|       Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
 | |
|       UINT8 *Symtab = (UINT8*)Ehdr + SymtabShdr->sh_offset;
 | |
| 
 | |
|       for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
 | |
| 	Elf_Rel *Rel = (Elf_Rel *)((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
 | |
| 	Elf_Sym *Sym = (Elf_Sym *)
 | |
| 	  (Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
 | |
| 	Elf_Shdr *SymShdr;
 | |
| 	UINT8 *Targ;
 | |
| 
 | |
| 	if (Sym->st_shndx == SHN_UNDEF
 | |
| 	    || Sym->st_shndx == SHN_ABS
 | |
| 	    || Sym->st_shndx > Ehdr->e_shnum) {
 | |
| 	  Error (NULL, 0, 0, InImageName, "bad symbol definition");
 | |
| 	}
 | |
| 	SymShdr = GetShdrByIndex(Sym->st_shndx);
 | |
| 
 | |
| 	//
 | |
| 	// Note: r_offset in a memory address.
 | |
| 	//  Convert it to a pointer in the coff file.
 | |
| 	//
 | |
| 	Targ = CoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);
 | |
| 
 | |
| 	switch (ELF_R_TYPE(Rel->r_info)) {
 | |
| 	case R_386_NONE:
 | |
| 	  break;
 | |
| 	case R_386_32:
 | |
| 	  //
 | |
| 	  // Absolute relocation.
 | |
| 	  //
 | |
| 	  *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr
 | |
| 	    + CoffSectionsOffset[Sym->st_shndx];
 | |
| 	  break;
 | |
| 	case R_386_PC32:
 | |
| 	  //
 | |
| 	  // Relative relocation: Symbol - Ip + Addend
 | |
| 	  //
 | |
| 	  *(UINT32 *)Targ = *(UINT32 *)Targ
 | |
| 	    + (CoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
 | |
| 	    - (SecOffset - SecShdr->sh_addr);
 | |
| 	  break;
 | |
| 	default:
 | |
| 	  Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
 | |
| 		 ELF_R_TYPE(Rel->r_info));
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| CoffAddFixupEntry(
 | |
|   UINT16 Val
 | |
|   )
 | |
| {
 | |
|   *CoffEntryRel = Val;
 | |
|   CoffEntryRel++;
 | |
|   CoffBaseRel->SizeOfBlock += 2;
 | |
|   CoffOffset += 2;
 | |
| }
 | |
| 
 | |
| void
 | |
| CoffAddFixup(
 | |
|   UINT32 Offset,
 | |
|   UINT8  Type
 | |
|   )
 | |
| {
 | |
|   if (CoffBaseRel == NULL
 | |
|       || CoffBaseRel->VirtualAddress != (Offset & ~0xfff)) {
 | |
|     if (CoffBaseRel != NULL) {
 | |
|       //
 | |
|       // Add a null entry (is it required ?)
 | |
|       //
 | |
|       CoffAddFixupEntry (0);
 | |
|       //
 | |
|       // Pad for alignment.
 | |
|       //
 | |
|       if (CoffOffset % 4 != 0)
 | |
| 	CoffAddFixupEntry (0);
 | |
|     }
 | |
|       
 | |
|     CoffFile = realloc
 | |
|       (CoffFile,
 | |
|        CoffOffset + sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
 | |
|     memset(CoffFile + CoffOffset, 0,
 | |
| 	   sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
 | |
| 
 | |
|     CoffBaseRel = (EFI_IMAGE_BASE_RELOCATION*)(CoffFile + CoffOffset);
 | |
|     CoffBaseRel->VirtualAddress = Offset & ~0xfff;
 | |
|     CoffBaseRel->SizeOfBlock = sizeof(EFI_IMAGE_BASE_RELOCATION);
 | |
| 
 | |
|     CoffEntryRel = (UINT16 *)(CoffBaseRel + 1);
 | |
|     CoffOffset += sizeof(EFI_IMAGE_BASE_RELOCATION);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Fill the entry.
 | |
|   //
 | |
|   CoffAddFixupEntry((Type << 12) | (Offset & 0xfff));
 | |
| }
 | |
| 
 | |
| void
 | |
| WriteRelocations(
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT32 Idx;
 | |
|   EFI_IMAGE_NT_HEADERS *NtHdr;
 | |
|   EFI_IMAGE_DATA_DIRECTORY *Dir;
 | |
| 
 | |
|   for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
 | |
|     Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
 | |
|     if (RelShdr->sh_type == SHT_REL) {
 | |
|       Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
 | |
|       if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
 | |
| 	UINT32 RelIdx;
 | |
| 	for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
 | |
| 	  Elf_Rel *Rel = (Elf_Rel *)
 | |
| 	    ((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
 | |
| 	  switch (ELF_R_TYPE(Rel->r_info)) {
 | |
| 	  case R_386_NONE:
 | |
| 	  case R_386_PC32:
 | |
| 	    break;
 | |
| 	  case R_386_32:
 | |
| 	    CoffAddFixup(CoffSectionsOffset[RelShdr->sh_info]
 | |
| 			 + (Rel->r_offset - SecShdr->sh_addr),
 | |
| 			 EFI_IMAGE_REL_BASED_HIGHLOW);
 | |
| 	    break;
 | |
| 	  default:
 | |
| 	    Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
 | |
| 		   ELF_R_TYPE(Rel->r_info));
 | |
| 	  }
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Pad by adding empty entries. 
 | |
|   //
 | |
|   while (CoffOffset & (CoffAlignment - 1)) {
 | |
|     CoffAddFixupEntry(0);
 | |
|   }
 | |
| 
 | |
|   CreateSectionHeader (".reloc", RelocOffset, CoffOffset - RelocOffset,
 | |
| 		       EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
 | |
| 		       | EFI_IMAGE_SCN_MEM_DISCARDABLE
 | |
| 		       | EFI_IMAGE_SCN_MEM_READ);
 | |
| 
 | |
|   NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
 | |
|   Dir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
 | |
|   Dir->VirtualAddress = RelocOffset;
 | |
|   Dir->Size = CoffOffset - RelocOffset;
 | |
| }
 | |
| 
 | |
| void
 | |
| WriteDebug(
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT32 Len = strlen(InImageName) + 1;
 | |
|   UINT32 DebugOffset = CoffOffset;
 | |
|   EFI_IMAGE_NT_HEADERS *NtHdr;
 | |
|   EFI_IMAGE_DATA_DIRECTORY *DataDir;
 | |
|   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
 | |
|   EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
 | |
| 
 | |
|   CoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)
 | |
|     + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)
 | |
|     + Len;
 | |
|   CoffOffset = CoffAlign(CoffOffset);
 | |
| 
 | |
|   CoffFile = realloc
 | |
|     (CoffFile, CoffOffset);
 | |
|   memset(CoffFile + DebugOffset, 0, CoffOffset - DebugOffset);
 | |
|   
 | |
|   Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(CoffFile + DebugOffset);
 | |
|   Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
 | |
|   Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + Len;
 | |
|   Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
 | |
|   Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
 | |
|   
 | |
|   Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
 | |
|   Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
 | |
|   strcpy ((PUCHAR)(Nb10 + 1), InImageName);
 | |
| 
 | |
|   CreateSectionHeader (".debug", DebugOffset, CoffOffset - DebugOffset,
 | |
| 		       EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
 | |
| 		       | EFI_IMAGE_SCN_MEM_DISCARDABLE
 | |
| 		       | EFI_IMAGE_SCN_MEM_READ);
 | |
| 
 | |
|   NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
 | |
|   DataDir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
 | |
|   DataDir->VirtualAddress = DebugOffset;
 | |
|   DataDir->Size = CoffOffset - DebugOffset;
 | |
| }
 | |
| 
 | |
| void
 | |
| ConvertElf (
 | |
|   UINT8	**FileBuffer,
 | |
|   UINTN *FileLength
 | |
|   )
 | |
| {
 | |
|   EFI_IMAGE_NT_HEADERS *NtHdr;
 | |
| 
 | |
|   //
 | |
|   // Check header, read section table.
 | |
|   //
 | |
|   Ehdr = (Elf32_Ehdr*)*FileBuffer;
 | |
|   if (!CheckElfHeader())
 | |
|     return;
 | |
| 
 | |
|   //
 | |
|   // Compute sections new address.
 | |
|   //
 | |
|   ScanSections();
 | |
| 
 | |
|   //
 | |
|   // Write and relocate sections.
 | |
|   //
 | |
|   WriteSections(IsTextShdr);
 | |
|   WriteSections(IsDataShdr);
 | |
| 
 | |
|   //
 | |
|   // Translate and write relocations.
 | |
|   //
 | |
|   WriteRelocations();
 | |
| 
 | |
|   //
 | |
|   // Write debug info.
 | |
|   //
 | |
|   WriteDebug();
 | |
| 
 | |
|   NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
 | |
|   NtHdr->OptionalHeader.SizeOfImage = CoffOffset;
 | |
| 
 | |
|   //
 | |
|   // Replace.
 | |
|   //
 | |
|   free(*FileBuffer);
 | |
|   *FileBuffer = CoffFile;
 | |
|   *FileLength = CoffOffset;
 | |
| }
 | |
| #endif // HAVE_ELF
 | |
| 
 | |
| int
 | |
| main (
 | |
|   int  argc,
 | |
|   char *argv[]
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Main function.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   argc - Number of command line parameters.
 | |
|   argv - Array of pointers to command line parameter strings.
 | |
| 
 | |
| Returns:
 | |
|   STATUS_SUCCESS - Utility exits successfully.
 | |
|   STATUS_ERROR   - Some error occurred during execution.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   ULONG             Type;
 | |
|   PUCHAR            Ext;
 | |
|   PUCHAR            p;
 | |
|   PUCHAR            pe;
 | |
|   PUCHAR            OutImageName;
 | |
|   UCHAR             outname[500];
 | |
|   FILE              *fpIn;
 | |
|   FILE              *fpOut;
 | |
|   VOID              *ZeroBuffer;
 | |
|   EFI_IMAGE_DOS_HEADER  *DosHdr;
 | |
|   EFI_IMAGE_NT_HEADERS  *PeHdr;
 | |
|   EFI_IMAGE_OPTIONAL_HEADER32  *Optional32;
 | |
|   EFI_IMAGE_OPTIONAL_HEADER64  *Optional64;
 | |
|   time_t            TimeStamp;
 | |
|   struct tm         TimeStruct;
 | |
|   EFI_IMAGE_DOS_HEADER  BackupDosHdr;
 | |
|   ULONG             Index;
 | |
|   ULONG             Index1;
 | |
|   ULONG             Index2;
 | |
|   ULONG             Index3;
 | |
|   BOOLEAN           TimeStampPresent;
 | |
|   UINTN                                 AllignedRelocSize;
 | |
|   UINTN                                 Delta;
 | |
|   EFI_IMAGE_SECTION_HEADER              *SectionHeader;
 | |
|   UINT8      *FileBuffer;
 | |
|   UINTN      FileLength;
 | |
|   RUNTIME_FUNCTION  *RuntimeFunction;
 | |
|   UNWIND_INFO       *UnwindInfo;
 | |
| 
 | |
|   SetUtilityName (UTILITY_NAME);
 | |
|   //
 | |
|   // Assign to fix compile warning
 | |
|   //
 | |
|   OutImageName      = NULL;
 | |
|   Type              = 0;
 | |
|   Ext               = 0;
 | |
|   TimeStamp         = 0;
 | |
|   TimeStampPresent  = FALSE;
 | |
| 
 | |
|   if (argc == 1) {
 | |
|     Usage();
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
|   
 | |
|   if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||
 | |
|       (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {
 | |
|     Usage();
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
|   
 | |
|   if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {
 | |
|     Version();
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
|  
 | |
|   //
 | |
|   // Look for -t time-date option first. If the time is "0", then
 | |
|   // skip it.
 | |
|   //
 | |
|   if ((argc > 2) && !strcmp (argv[1], "-t")) {
 | |
|     TimeStampPresent = TRUE;
 | |
|     if (strcmp (argv[2], "0") != 0) {
 | |
|       //
 | |
|       // Convert the string to a value
 | |
|       //
 | |
|       memset ((char *) &TimeStruct, 0, sizeof (TimeStruct));
 | |
|       if (sscanf(
 | |
|           argv[2], "%d/%d/%d,%d:%d:%d",
 | |
|           &TimeStruct.tm_mon,   /* months since January - [0,11] */
 | |
|           &TimeStruct.tm_mday,  /* day of the month - [1,31] */
 | |
|           &TimeStruct.tm_year,  /* years since 1900 */
 | |
|           &TimeStruct.tm_hour,  /* hours since midnight - [0,23] */
 | |
|           &TimeStruct.tm_min,   /* minutes after the hour - [0,59] */
 | |
|           &TimeStruct.tm_sec    /* seconds after the minute - [0,59] */
 | |
|             ) != 6) {
 | |
|         Error (NULL, 0, 0, argv[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");
 | |
|         return STATUS_ERROR;
 | |
|       }
 | |
|       //
 | |
|       // Now fixup some of the fields
 | |
|       //
 | |
|       TimeStruct.tm_mon--;
 | |
|       TimeStruct.tm_year -= 1900;
 | |
|       //
 | |
|       // Sanity-check values?
 | |
|       // Convert
 | |
|       //
 | |
|       TimeStamp = mktime (&TimeStruct);
 | |
|       if (TimeStamp == (time_t) - 1) {
 | |
|         Error (NULL, 0, 0, argv[2], "failed to convert time");
 | |
|         return STATUS_ERROR;
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // Skip over the args
 | |
|     //
 | |
|     argc -= 2;
 | |
|     argv += 2;
 | |
|   }
 | |
|   //
 | |
|   // Check for enough args
 | |
|   //
 | |
|   if (argc < 3) {
 | |
|     Usage ();
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
| 
 | |
|   InImageName = argv[2];
 | |
| 
 | |
|   if (argc == 4) {
 | |
|     OutImageName = argv[3];
 | |
|   }
 | |
|   //
 | |
|   // Get new image type
 | |
|   //
 | |
|   p = argv[1];
 | |
|   if (*p == '/' || *p == '\\') {
 | |
|     p += 1;
 | |
|   }
 | |
| 
 | |
|   if (stricmp (p, "app") == 0 || stricmp (p, "UEFI_APPLICATION") == 0) {
 | |
|     Type  = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
 | |
|     Ext   = ".efi";
 | |
| 
 | |
|   } else if (stricmp (p, "bsdrv") == 0 || stricmp (p, "DXE_DRIVER") == 0) {
 | |
|     Type  = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
 | |
|     Ext   = ".efi";
 | |
| 
 | |
|   } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_RUNTIME_DRIVER") == 0) {
 | |
|     Type  = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
 | |
|     Ext   = ".efi";
 | |
| 
 | |
|   } else if (stricmp (p, "rtdrv") == 0 || stricmp (p, "DXE_SAL_DRIVER") == 0) {
 | |
|     Type  = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
 | |
|     Ext   = ".efi";
 | |
|   } else if (stricmp (p, "SEC") == 0) {
 | |
|     Type  = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
 | |
|     Ext   = ".sec";
 | |
|   } else if (stricmp (p, "peim") == 0 ||
 | |
|            stricmp (p, "BASE") == 0 ||
 | |
|            stricmp (p, "PEI_CORE") == 0 ||
 | |
|            stricmp (p, "PEIM") == 0 ||
 | |
|            stricmp (p, "DXE_SMM_DRIVER") == 0 ||
 | |
|            stricmp (p, "TOOL") == 0 ||
 | |
|            stricmp (p, "UEFI_APPLICATION") == 0 ||
 | |
|            stricmp (p, "USER_DEFINED") == 0 ||
 | |
|            stricmp (p, "UEFI_DRIVER") == 0 ||
 | |
|            stricmp (p, "DXE_CORE") == 0
 | |
|           ) {
 | |
|     Type  = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
 | |
|     Ext   = ".pei";
 | |
|   } else {
 | |
|   	printf ("%s", p);
 | |
|     Usage ();
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
|   //
 | |
|   // open source file
 | |
|   //
 | |
|   fpIn = fopen (InImageName, "rb");
 | |
|   if (!fpIn) {
 | |
|     Error (NULL, 0, 0, InImageName, "failed to open input file for reading");
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
| 
 | |
|   FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);
 | |
| 
 | |
| #ifdef HAVE_ELF
 | |
|   if (IsElfHeader(FileBuffer)) {
 | |
|     ConvertElf(&FileBuffer, &FileLength);
 | |
|   }
 | |
| #endif
 | |
|   //
 | |
|   // Read the dos & pe hdrs of the image
 | |
|   //
 | |
|   DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;
 | |
|   if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
 | |
|     Error (NULL, 0, 0, InImageName, "DOS header signature not found in source image");
 | |
|     fclose (fpIn);
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
| 
 | |
|   PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);
 | |
|   if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {
 | |
|     Error (NULL, 0, 0, InImageName, "PE header signature not found in source image");
 | |
|     fclose (fpIn);
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // open output file
 | |
|   //
 | |
|   strcpy (outname, InImageName);
 | |
|   pe = NULL;
 | |
|   for (p = outname; *p; p++) {
 | |
|     if (*p == '.') {
 | |
|       pe = p;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!pe) {
 | |
|     pe = p;
 | |
|   }
 | |
| 
 | |
|   strcpy (pe, Ext);
 | |
| 
 | |
|   if (!OutImageName) {
 | |
|     OutImageName = outname;
 | |
|   }
 | |
| 
 | |
|   fpOut = fopen (OutImageName, "w+b");
 | |
|   if (!fpOut) {
 | |
|     Error (NULL, 0, 0, OutImageName, "could not open output file for writing");
 | |
|     fclose (fpIn);
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Zero all unused fields of the DOS header
 | |
|   //
 | |
|   memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));
 | |
|   memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));
 | |
|   DosHdr->e_magic  = BackupDosHdr.e_magic;
 | |
|   DosHdr->e_lfanew = BackupDosHdr.e_lfanew;
 | |
| 
 | |
|   for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {
 | |
|     FileBuffer[Index] = DosHdr->e_cp;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Patch the PE header
 | |
|   //
 | |
|   PeHdr->OptionalHeader.Subsystem = (USHORT) Type;
 | |
|   if (TimeStampPresent) {
 | |
|     PeHdr->FileHeader.TimeDateStamp = (UINT32) TimeStamp;
 | |
|   }
 | |
| 
 | |
|   if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
 | |
|     Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;
 | |
|     Optional32->MajorLinkerVersion          = 0;
 | |
|     Optional32->MinorLinkerVersion          = 0;
 | |
|     Optional32->MajorOperatingSystemVersion = 0;
 | |
|     Optional32->MinorOperatingSystemVersion = 0;
 | |
|     Optional32->MajorImageVersion           = 0;
 | |
|     Optional32->MinorImageVersion           = 0;
 | |
|     Optional32->MajorSubsystemVersion       = 0;
 | |
|     Optional32->MinorSubsystemVersion       = 0;
 | |
|     Optional32->Win32VersionValue           = 0;
 | |
|     Optional32->CheckSum                    = 0;
 | |
|     Optional32->SizeOfStackReserve = 0;
 | |
|     Optional32->SizeOfStackCommit  = 0;
 | |
|     Optional32->SizeOfHeapReserve  = 0;
 | |
|     Optional32->SizeOfHeapCommit   = 0;
 | |
| 
 | |
|     //
 | |
|     // Strip zero padding at the end of the .reloc section 
 | |
|     //
 | |
|     if (Optional32->NumberOfRvaAndSizes >= 6) {
 | |
|       if (Optional32->DataDirectory[5].Size != 0) {
 | |
|         SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
 | |
|         for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
 | |
|           //
 | |
|           // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
 | |
|           //
 | |
|           if (SectionHeader->VirtualAddress == Optional32->DataDirectory[5].VirtualAddress) {
 | |
|             SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[5].Size;
 | |
|             AllignedRelocSize = (Optional32->DataDirectory[5].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));
 | |
|             //
 | |
|             // Check to see if there is zero padding at the end of the base relocations
 | |
|             //
 | |
|             if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
 | |
|               //
 | |
|               // Check to see if the base relocations are at the end of the file
 | |
|               //
 | |
|               if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {
 | |
|                 //
 | |
|                 // All the required conditions are met to strip the zero padding of the end of the base relocations section
 | |
|                 //
 | |
|                 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
 | |
|                 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
 | |
|                 SectionHeader->SizeOfRawData = AllignedRelocSize;
 | |
|                 FileLength = Optional32->SizeOfImage;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } 
 | |
|   if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
 | |
|     Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;
 | |
|     Optional64->MajorLinkerVersion          = 0;
 | |
|     Optional64->MinorLinkerVersion          = 0;
 | |
|     Optional64->MajorOperatingSystemVersion = 0;
 | |
|     Optional64->MinorOperatingSystemVersion = 0;
 | |
|     Optional64->MajorImageVersion           = 0;
 | |
|     Optional64->MinorImageVersion           = 0;
 | |
|     Optional64->MajorSubsystemVersion       = 0;
 | |
|     Optional64->MinorSubsystemVersion       = 0;
 | |
|     Optional64->Win32VersionValue           = 0;
 | |
|     Optional64->CheckSum                    = 0;
 | |
|     Optional64->SizeOfStackReserve = 0;
 | |
|     Optional64->SizeOfStackCommit  = 0;
 | |
|     Optional64->SizeOfHeapReserve  = 0;
 | |
|     Optional64->SizeOfHeapCommit   = 0;
 | |
| 
 | |
|     //
 | |
|     // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty
 | |
|     //
 | |
|     if (PeHdr->FileHeader.Machine == 0x8664) { // X64
 | |
|       if (Optional64->NumberOfRvaAndSizes >= 4) {
 | |
|         if (Optional64->NumberOfRvaAndSizes < 7 || (Optional64->NumberOfRvaAndSizes >= 7 && Optional64->DataDirectory[6].Size == 0)) {
 | |
|           SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
 | |
|           for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
 | |
|             if (SectionHeader->VirtualAddress == Optional64->DataDirectory[3].VirtualAddress) {
 | |
|               RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData);
 | |
|               for (Index1 = 0; Index1 < Optional64->DataDirectory[3].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) {
 | |
|                 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
 | |
|                 for (Index2 = 0; Index2 < PeHdr->FileHeader.NumberOfSections; Index2++, SectionHeader++) {
 | |
|                   if (RuntimeFunction->UnwindInfoAddress > SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) {
 | |
|                     UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress));
 | |
|                     if (UnwindInfo->Version == 1) {
 | |
|                       memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16));
 | |
|                       memset (UnwindInfo, 0, sizeof (UNWIND_INFO));
 | |
|                     }
 | |
|                   }
 | |
|                 }
 | |
|                 memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION));
 | |
|               }
 | |
| 
 | |
|               break;
 | |
|             }
 | |
|           }
 | |
|           Optional64->DataDirectory[3].Size = 0;
 | |
|           Optional64->DataDirectory[3].VirtualAddress = 0;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Strip zero padding at the end of the .reloc section 
 | |
|     //
 | |
|     if (Optional64->NumberOfRvaAndSizes >= 6) {
 | |
|       if (Optional64->DataDirectory[5].Size != 0) {
 | |
|         SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);
 | |
|         for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {
 | |
|           //
 | |
|           // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
 | |
|           //
 | |
|           if (SectionHeader->VirtualAddress == Optional64->DataDirectory[5].VirtualAddress) {
 | |
|             SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[5].Size;
 | |
|             AllignedRelocSize = (Optional64->DataDirectory[5].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));
 | |
|             //
 | |
|             // Check to see if there is zero padding at the end of the base relocations
 | |
|             //
 | |
|             if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
 | |
|               //
 | |
|               // Check to see if the base relocations are at the end of the file
 | |
|               //
 | |
|               if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {
 | |
|                 //
 | |
|                 // All the required conditions are met to strip the zero padding of the end of the base relocations section
 | |
|                 //
 | |
|                 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
 | |
|                 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
 | |
|                 SectionHeader->SizeOfRawData = AllignedRelocSize;
 | |
|                 FileLength = Optional64->SizeOfImage;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FWriteFile (fpOut, FileBuffer, FileLength);
 | |
| 
 | |
|   //
 | |
|   // Done
 | |
|   //
 | |
|   fclose (fpIn);
 | |
|   fclose (fpOut);
 | |
|   //
 | |
|   // printf ("Created %s\n", OutImageName);
 | |
|   //
 | |
|   return STATUS_SUCCESS;
 | |
| }
 |