]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Tools/CCode/Source/FwImage/fwimage.c
Fix the unalignment issue for RODATA section when converting ELF image to PE image.
[mirror_edk2.git] / Tools / CCode / Source / FwImage / fwimage.c
index 92bfd16a6fd2dd5a5bce069c9ff79f183831d1af..a4ae10c4c26dcbd23a4008fd12433dd652301aec 100644 (file)
@@ -1,6 +1,6 @@
 /*++\r
 \r
-Copyright (c) 2004, Intel Corporation                                                         \r
+Copyright (c) 2004 - 2007, Intel Corporation                                                         \r
 All rights reserved. This program and the accompanying materials                          \r
 are licensed and made available under the terms and conditions of the BSD License         \r
 which accompanies this distribution.  The full text of the license may be found at        \r
@@ -21,6 +21,15 @@ Abstract:
 \r
 #include "WinNtInclude.h"\r
 \r
+//\r
+// List of OS and CPU which support ELF to PE conversion\r
+//\r
+#if defined(linux)
+#if defined(i386)
+#define HAVE_ELF
+#endif
+#endif
+
 #ifndef __GNUC__\r
 #include <windows.h>\r
 #endif\r
@@ -28,6 +37,10 @@ Abstract:
 #include <stdlib.h>\r
 #include <string.h>\r
 #include <time.h>\r
+
+#ifdef HAVE_ELF
+#include <elf.h>
+#endif
 \r
 #include <Common/UefiBaseTypes.h>\r
 #include <Common/EfiImage.h>\r
@@ -35,7 +48,12 @@ Abstract:
 #include "CommonLib.h"\r
 #include "EfiUtilityMsgs.c"\r
 \r
-#define UTILITY_NAME  "FwImage"\r
+//\r
+// Version of this utility\r
+//\r
+#define UTILITY_NAME "FwImage"\r
+#define UTILITY_MAJOR_VERSION 1\r
+#define UTILITY_MINOR_VERSION 0\r
 \r
 #ifdef __GNUC__\r
 typedef unsigned long ULONG;\r
@@ -44,12 +62,29 @@ typedef unsigned char *PUCHAR;
 typedef unsigned short USHORT;\r
 #endif\r
 \r
+PUCHAR            InImageName;\r
+\r
+static\r
+void\r
+Version (\r
+  VOID\r
+  )\r
+{\r
+  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);\r
+  printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");\r
+}\r
+\r
+\r
 VOID\r
 Usage (\r
   VOID\r
   )\r
 {\r
-  printf ("Usage: " UTILITY_NAME "  {-t time-date} [BASE|SEC|PEI_CORE|PEIM|DXE_CORE|DXE_DRIVER|DXE_RUNTIME_DRIVER|DXE_SAL_DRIVER|DXE_SMM_DRIVER|TOOL|UEFI_DRIVER|UEFI_APPLICATION|USER_DEFINED] peimage [outimage]");\r
+  Version();\r
+  printf ("\nUsage: " UTILITY_NAME "  {-t time-date} {-h|--help|-?|/?|-V|--version} \n\\r
+         [BASE|SEC|PEI_CORE|PEIM|DXE_CORE|DXE_DRIVER|DXE_RUNTIME_DRIVER|\n\\r
+         DXE_SAL_DRIVER|DXE_SMM_DRIVER|TOOL|UEFI_DRIVER|UEFI_APPLICATION|\n\\r
+         USER_DEFINED] peimage [outimage]\n");\r
 }\r
 \r
 static\r
@@ -124,6 +159,556 @@ FWriteFile (
   return STATUS_SUCCESS;\r
 }\r
 \r
+#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
+  )
+{\r
+  //
+  // 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;
+\r
+  //\r
+  // Find the section header table\r
+  // 
+  ShdrBase = (Elf_Shdr *)((UINT8 *)Ehdr + Ehdr->e_shoff);
+
+  CoffSectionsOffset = (UINT32 *)malloc(Ehdr->e_shnum * sizeof (UINT32));\r
+
+  memset(CoffSectionsOffset, 0, Ehdr->e_shnum * sizeof(UINT32));\r
+  return 1;
+}
+
+int
+IsTextShdr(
+  Elf_Shdr *Shdr
+  )
+{
+  return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC;
+}
+\r
+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)) {\r
+      //\r
+      // Align the coff offset\r
+      // \r
+      CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
+      /* Relocate entry.  */
+      if ((Ehdr->e_entry >= shdr->sh_addr) && \r
+          (Ehdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
+        CoffEntry = CoffOffset + Ehdr->e_entry - shdr->sh_addr;
+      }
+      CoffSectionsOffset[i] = CoffOffset;\r
+      CoffOffset += shdr->sh_size;
+    }\r
+  }\r
+  CoffOffset = CoffAlign(CoffOffset);
+\r
+  //
+  //  Then data sections.
+  //
+  DataOffset = CoffOffset;
+  for (i = 0; i < Ehdr->e_shnum; i++) {
+    Elf_Shdr *shdr = GetShdrByIndex(i);
+    if (IsDataShdr(shdr)) {
+      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\r
 main (\r
   int  argc,\r
@@ -185,6 +770,22 @@ Returns:
   TimeStamp         = 0;\r
   TimeStampPresent  = FALSE;\r
 \r
+  if (argc == 1) {\r
+    Usage();\r
+    return STATUS_ERROR;\r
+  }\r
+  \r
+  if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||\r
+      (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {\r
+    Usage();\r
+    return STATUS_ERROR;\r
+  }\r
+  \r
+  if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {\r
+    Version();\r
+    return STATUS_ERROR;\r
+  }\r
\r
   //\r
   // Look for -t time-date option first. If the time is "0", then\r
   // skip it.\r
@@ -237,6 +838,8 @@ Returns:
     return STATUS_ERROR;\r
   }\r
 \r
+  InImageName = argv[2];\r
+\r
   if (argc == 4) {\r
     OutImageName = argv[3];\r
   }\r
@@ -287,27 +890,32 @@ Returns:
   //\r
   // open source file\r
   //\r
-  fpIn = fopen (argv[2], "rb");\r
+  fpIn = fopen (InImageName, "rb");\r
   if (!fpIn) {\r
-    Error (NULL, 0, 0, argv[2], "failed to open input file for reading");\r
+    Error (NULL, 0, 0, InImageName, "failed to open input file for reading");\r
     return STATUS_ERROR;\r
   }\r
 \r
   FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);\r
 \r
+#ifdef HAVE_ELF
+  if (IsElfHeader(FileBuffer)) {
+    ConvertElf(&FileBuffer, &FileLength);
+  }
+#endif
   //\r
   // Read the dos & pe hdrs of the image\r
   //\r
   DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;\r
   if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
-    Error (NULL, 0, 0, argv[2], "DOS header signature not found in source image");\r
+    Error (NULL, 0, 0, InImageName, "DOS header signature not found in source image");\r
     fclose (fpIn);\r
     return STATUS_ERROR;\r
   }\r
 \r
   PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);\r
   if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
-    Error (NULL, 0, 0, argv[2], "PE header signature not found in source image");\r
+    Error (NULL, 0, 0, InImageName, "PE header signature not found in source image");\r
     fclose (fpIn);\r
     return STATUS_ERROR;\r
   }\r
@@ -315,7 +923,7 @@ Returns:
   //\r
   // open output file\r
   //\r
-  strcpy (outname, argv[2]);\r
+  strcpy (outname, InImageName);\r
   pe = NULL;\r
   for (p = outname; *p; p++) {\r
     if (*p == '.') {\r
@@ -353,7 +961,7 @@ Returns:
   }\r
 \r
   //\r
-  // Path the PE header\r
+  // Patch the PE header\r
   //\r
   PeHdr->OptionalHeader.Subsystem = (USHORT) Type;\r
   if (TimeStampPresent) {\r