[efi] Use elf2efi utility in place of efilink
authorMichael Brown <mcb30@etherboot.org>
Wed, 7 Jan 2009 02:05:51 +0000 (02:05 +0000)
committerMichael Brown <mcb30@etherboot.org>
Wed, 7 Jan 2009 22:59:05 +0000 (22:59 +0000)
elf2efi converts a suitable ELF executable (containing relocation
information, and with appropriate virtual addresses) into an EFI
executable.  It is less tightly coupled with the gPXE build process
and, in particular, does not require the use of a hand-crafted PE
image header in efiprefix.S.

elf2efi correctly handles .bss sections, which significantly reduces
the size of the gPXE EFI executable.

16 files changed:
src/Makefile
src/Makefile.housekeeping
src/arch/i386/Makefile.efi
src/arch/i386/prefix/efiprefix.S [deleted file]
src/arch/i386/scripts/efi.lds [deleted file]
src/arch/x86/Makefile
src/arch/x86/prefix/efiprefix.c [new file with mode: 0644]
src/arch/x86/scripts/efi.lds [new file with mode: 0644]
src/arch/x86_64/Makefile.efi
src/arch/x86_64/prefix/efiprefix.S [deleted file]
src/arch/x86_64/scripts/efi.lds [deleted file]
src/include/gpxe/efi/efi.h
src/interface/efi/efi_init.c [moved from src/interface/efi/efi_entry.c with 95% similarity]
src/util/.gitignore
src/util/efilink.c [deleted file]
src/util/elf2efi.c [new file with mode: 0644]

index 67e36a2..015fcc4 100644 (file)
@@ -37,7 +37,8 @@ SYMCHECK      := $(PERL) ./util/symcheck.pl
 SORTOBJDUMP    := $(PERL) ./util/sortobjdump.pl
 NRV2B          := ./util/nrv2b
 ZBIN           := ./util/zbin
-EFILINK                := ./util/efilink
+ELF2EFI32      := ./util/elf2efi32
+ELF2EFI64      := ./util/elf2efi64
 DOXYGEN                := doxygen
 
 ###############################################################################
index 39771e3..2a1a1a2 100644 (file)
@@ -703,12 +703,17 @@ CLEANUP += $(ZBIN)
 
 ###############################################################################
 #
-# The EFI custom linker
+# The EFI image converter
 #
-$(EFILINK) : util/efilink.c $(MAKEDEPS)
+$(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS)
        $(QM)$(ECHO) "  [HOSTCC] $@"
-       $(Q)$(HOST_CC) -O2 -o $@ $< -lbfd -liberty
-CLEANUP += $(EFILINK)
+       $(Q)$(HOST_CC) -DMDE_CPU_IA32 -O2 -o $@ $< -lbfd -liberty
+CLEANUP += $(ELF2EFI32)
+
+$(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS)
+       $(QM)$(ECHO) "  [HOSTCC] $@"
+       $(Q)$(HOST_CC) -DMDE_CPU_X64 -O2 -o $@ $< -lbfd -liberty
+CLEANUP += $(ELF2EFI64)
 
 ###############################################################################
 #
index fec7a40..c75338c 100644 (file)
@@ -2,11 +2,11 @@
 
 # The EFI linker script
 #
-LDSCRIPT       = arch/i386/scripts/efi.lds
+LDSCRIPT       = arch/x86/scripts/efi.lds
 
-# Use a relocatable link; we perform final relocations in the efilink utility.
+# Retain relocation information for elf2efi
 #
-LDFLAGS                += -r -d -S
+LDFLAGS                += -q -S
 
 # Media types.
 #
@@ -14,12 +14,6 @@ NON_AUTO_MEDIA       += efi
 
 # Rule for building EFI files
 #
-$(BIN)/%.efi.tmp-reloc : $(BIN)/%.efi.tmp $(EFILINK)
-       $(QM)$(ECHO) "  [EFILINK] $@"
-       $(Q)# Check for unresolved symbols
-       $(Q)$(LD) -e 0 --no-warn-mismatch -o /dev/null $<
-       $(Q)$(EFILINK) $< $@
-
-$(BIN)/%.efi : $(BIN)/%.efi.tmp-reloc
+$(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI32)
        $(QM)$(ECHO) "  [FINISH] $@"
-       $(Q)$(OBJCOPY) -Obinary $< $@
+       $(Q)$(ELF2EFI32) $< $@
diff --git a/src/arch/i386/prefix/efiprefix.S b/src/arch/i386/prefix/efiprefix.S
deleted file mode 100644 (file)
index c4cf68e..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-       .text
-       .code32
-       .arch i386
-       .section ".prefix", "a", @progbits
-       .org 0x00
-
-       /* DOS (.com) header
-        *
-        * EFI executables seem to leave most of this empty
-        */
-mzhdr:
-       .ascii  "MZ"            /* Magic number */
-       .word   0               /* Bytes on last page of file */
-       .word   0               /* Pages in file */
-       .word   0               /* Relocations */
-       .word   0               /* Size of header in paragraphs */
-       .word   0               /* Minimum extra paragraphs needed */
-       .word   0               /* Maximum extra paragraphs needed */
-       .word   0               /* Initial (relative) SS value */
-       .word   0               /* Initial SP value */
-       .word   0               /* "Checksum" */
-       .word   0               /* Initial IP value */
-       .word   0               /* Initial (relative) CS value */
-       .word   0               /* File address of relocation table */
-       .word   0               /* Ovesrlay number */
-       .word   0, 0, 0, 0      /* Reserved words */
-       .word   0               /* OEM identifier (for e_oeminfo) */
-       .word   0               /* OEM information; e_oemid specific */
-       .word   0, 0, 0, 0, 0   /* Reserved words */
-       .word   0, 0, 0, 0, 0   /* Reserved words */
-       .long   pehdr_lma       /* File address of new exe header */
-       .size   mzhdr, . - mzhdr
-
-       /* PE header */
-       .org    0xc0 /* For compatibility with MS toolchain */
-pehdr:
-       .ascii  "PE\0\0"        /* Magic number */
-       .word   0x014c          /* CPU architecture: i386 */
-       .word   num_pe_sections /* Number of sections */
-       .long   0x10d1a884      /* Timestamp */
-       .long   0               /* Symbol table */
-       .long   0               /* Number of symbols */
-       .word   opthdr_size     /* Size of optional header */
-       .word   0x2102          /* Characteristics */
-       .size   pehdr, . - pehdr
-       .equ    pehdr_lma, pehdr - mzhdr
-
-       /* "Optional" header */
-opthdr:
-       .word   0x010b          /* Magic number */
-       .byte   0               /* Linker major version number */
-       .byte   0               /* Linker minor version number */
-       .long   _text_filesz    /* Size of text section */
-       .long   _data_filesz    /* Size of data section */
-       .long   _bss_filesz     /* Size of bss section */
-       .long   efi_entry_lma   /* Entry point */
-       .long   _text_lma       /* Text section start RVA */
-       .long   _data_lma       /* Data section start RVA */
-       .long   0               /* Image base address */
-       .long   _max_align      /* Section alignment */
-       .long   _max_align      /* File alignment */
-       .word   0               /* Operating system major version number */
-       .word   0               /* Operating system minor version number */
-       .word   0               /* Image major version number */
-       .word   0               /* Image minor version number */
-       .word   0               /* Subsystem major version number */
-       .word   0               /* Subsystem minor version number */
-       .long   0               /* Reserved */
-       .long   _filesz         /* Total image size */
-       .long   _prefix_filesz  /* Total header size */
-       .long   0               /* "Checksum" */
-       .word   0x0a            /* Subsystem: EFI */
-       .word   0               /* DLL characteristics */
-       .long   0               /* Size of stack reserve */
-       .long   0               /* Size of stack commit */
-       .long   0               /* Size of heap reserve */
-       .long   0               /* Size of heap commit */
-       .long   0               /* Loader flags */
-       .long   16              /* Number of data directory entries */
-       .long   0, 0            /* Export directory */
-       .long   0, 0            /* Import directory */
-       .long   0, 0            /* Resource directory */
-       .long   0, 0            /* Exception directory */
-       .long   0, 0            /* Security directory */
-       .long   _reloc_lma, _reloc_filesz /* Base relocation directory */
-       .long   debugdir_lma, debugdir_size /* Debug directory */
-       .long   0, 0            /* Description directory */
-       .long   0, 0            /* Special directory */
-       .long   0, 0            /* Thread storage directory */
-       .long   0, 0            /* Load configuration directory */
-       .long   0, 0            /* Bound import directory */
-       .long   0, 0            /* Import address table directory */
-       .long   0, 0            /* Delay import directory */
-       .long   0, 0            /* Reserved */
-       .long   0, 0            /* Reserved */
-       .size   opthdr, . - opthdr
-       .equ    opthdr_size, . - opthdr
-
-       /* PE sections */
-pe_sections:
-text_section:
-       .asciz  ".text"         /* Section name */
-       .align  8
-       .long   _text_filesz    /* Section size */
-       .long   _text_lma       /* Relative Virtual Address */
-       .long   _text_filesz    /* Section size (rounded up) */
-       .long   _text_lma       /* Pointer to raw data */
-       .long   0               /* Link-time relocations */
-       .long   0               /* Line numbers */
-       .word   0               /* Number of link-time relocations */
-       .word   0               /* Number of line numbers */
-       .long   0x68000020      /* Characteristics */
-rodata_section:
-       .asciz  ".rodata"       /* Section name */
-       .align  8
-       .long   _rodata_filesz  /* Section size */
-       .long   _rodata_lma     /* Relative Virtual Address */
-       .long   _rodata_filesz  /* Section size (rounded up) */
-       .long   _rodata_lma     /* Pointer to raw data */
-       .long   0               /* Link-time relocations */
-       .long   0               /* Line numbers */
-       .word   0               /* Number of link-time relocations */
-       .word   0               /* Number of line numbers */
-       .long   0x48000040      /* Characteristics */
-data_section:
-       .asciz  ".data"         /* Section name */
-       .align  8
-       .long   _data_filesz    /* Section size */
-       .long   _data_lma       /* Relative Virtual Address */
-       .long   _data_filesz    /* Section size (rounded up) */
-       .long   _data_lma       /* Pointer to raw data */
-       .long   0               /* Link-time relocations */
-       .long   0               /* Line numbers */
-       .word   0               /* Number of link-time relocations */
-       .word   0               /* Number of line numbers */
-       .long   0xc8000040      /* Characteristics */
-reloc_section:
-       .asciz  ".reloc"        /* Section name */
-       .align  8
-       .long   _reloc_filesz   /* Section size */
-       .long   _reloc_lma      /* Relative Virtual Address */
-       .long   _reloc_filesz   /* Section size (rounded up) */
-       .long   _reloc_lma      /* Pointer to raw data */
-       .long   0               /* Link-time relocations */
-       .long   0               /* Line numbers */
-       .word   0               /* Number of link-time relocations */
-       .word   0               /* Number of line numbers */
-       .long   0x42000040      /* Characteristics */
-
-pe_sections_end:
-       .size   pe_sections, . - pe_sections
-       .equ    num_pe_sections, ( ( . - pe_sections ) / 0x28 )
-
-       /* Debug directory */
-       .section ".rodata"
-       .globl  debugdir
-debugdir:
-       .long   0               /* Characteristics */
-       .long   0x10d1a884      /* Timestamp */
-       .word   0               /* Major version */
-       .word   0               /* Minor version */
-       .long   0x02            /* RSDS? */
-       .long   codeview_rsds_size /* Size of data */
-       .long   codeview_rsds_lma /* RVA */
-       .long   codeview_rsds_lma /* File offset */
-       .size   debugdir, . - debugdir
-       .equ    debugdir_size, . - debugdir
-       /* Codeview structure */
-       .globl  codeview_rsds
-codeview_rsds:
-       .ascii  "RSDS"          /* Magic number */
-       .long   0, 0, 0, 0, 0   /* Unused by EFI */
-       .asciz  "efiprefix.pdb"
-       .size   codeview_rsds, . - codeview_rsds
-       .equ    codeview_rsds_size, . - codeview_rsds
diff --git a/src/arch/i386/scripts/efi.lds b/src/arch/i386/scripts/efi.lds
deleted file mode 100644 (file)
index b6255a6..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/* -*- sh -*- */
-
-/*
- * Linker script for EFI images
- *
- */
-
-EXTERN ( efi_entry )
-
-SECTIONS {
-
-    /* The file starts at a virtual address of zero, and sections are
-     * contiguous.  Each section is aligned to at least _max_align,
-     * which defaults to 32.  Load addresses are equal to virtual
-     * addresses.
-     */
-
-    . = 0;
-    PROVIDE ( _max_align = 32 );
-
-    /*
-     * The prefix
-     *
-     */
-
-    .prefix : {
-       _prefix = .;
-       *(.prefix)
-       *(.prefix.*)
-       _mprefix = .;
-    } .bss.prefix (NOLOAD) : {
-       _eprefix = .;
-    }
-    _prefix_filesz     = ABSOLUTE ( _mprefix - _prefix );
-    _prefix_memsz      = ABSOLUTE ( _eprefix - _prefix );
-
-    /*
-     * The text section
-     *
-     */
-
-    . = ALIGN ( _max_align );
-    .text : {
-       _text = .;
-       *(.text)
-       *(.text.*)
-       _mtext = .;
-    } .bss.text (NOLOAD) : {
-       _etext = .;
-    }
-    _text_filesz       = ABSOLUTE ( _mtext - _text );
-    _text_memsz                = ABSOLUTE ( _etext - _text );
-
-    /*
-     * The rodata section
-     *
-     */
-
-    . = ALIGN ( _max_align );
-    .rodata : {
-       _rodata = .;
-       *(.rodata)
-       *(.rodata.*)
-       _mrodata = .;
-    } .bss.rodata (NOLOAD) : {
-       _erodata = .;
-    }
-    _rodata_filesz     = ABSOLUTE ( _mrodata - _rodata );
-    _rodata_memsz      = ABSOLUTE ( _erodata - _rodata );
-
-    /*
-     * The data section
-     *
-     */
-
-    . = ALIGN ( _max_align );
-    .data : {
-       _data = .;
-       *(.data)
-       *(.data.*)
-       *(SORT(.tbl.*))         /* Various tables.  See include/tables.h */
-       /* EFI seems to not support proper bss sections */
-       *(.bss)
-       *(.bss.*)
-       *(COMMON)
-       *(.stack)
-       *(.stack.*)
-       _mdata = .;
-    } .bss.data (NOLOAD) : {
-       _edata = .;
-    }
-    _data_filesz       = ABSOLUTE ( _mdata - _data );
-    _data_memsz                = ABSOLUTE ( _edata - _data );
-
-    /*
-     * The bss section
-     *
-     */
-
-    . = ALIGN ( _max_align );
-    .bss : { 
-       _bss = .;
-       /* EFI seems to not support proper bss sections */
-       _mbss = .;
-    } .bss.bss (NOLOAD) : {
-       _ebss = .;
-    }
-    _bss_filesz                = ABSOLUTE ( _mbss - _bss );
-    _bss_memsz         = ABSOLUTE ( _ebss - _bss );
-
-    /*
-     * The reloc section
-     *
-     */
-
-    . = ALIGN ( _max_align );
-    .reloc : {
-       _reloc = .;
-       /* Provide some dummy contents to force ld to include this
-        * section.  It will be created by the efilink utility.
-        */
-       . += 1;
-       _mreloc = .;
-    } .bss.reloc (NOLOAD) : {
-       _ereloc = .;
-    }
-    _reloc_filesz      = ABSOLUTE ( _mreloc - _reloc );
-    _reloc_memsz       = ABSOLUTE ( _ereloc - _reloc );
-
-    _filesz            = ABSOLUTE ( . );
-
-    /*
-     * Weak symbols that need zero values if not otherwise defined
-     *
-     */
-
-    .weak 0x0 : {
-       _weak = .;
-       *(.weak)
-       _eweak = .;
-    }
-    _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
-
-    /*
-     * Dispose of the comment and note sections to make the link map
-     * easier to read
-     *
-     */
-
-    /DISCARD/ : {
-       *(.comment)
-       *(.comment.*)
-       *(.note)
-       *(.note.*)
-       *(.eh_frame)
-       *(.eh_frame.*)
-       *(.rel)
-       *(.rel.*)
-    }
-
-    /*
-     * Load address calculations.
-     *
-     */
-
-    _prefix_lma                = ABSOLUTE ( _prefix );
-    _text_lma          = ABSOLUTE ( _text );
-    _rodata_lma                = ABSOLUTE ( _rodata );
-    _data_lma          = ABSOLUTE ( _data );
-    _bss_lma           = ABSOLUTE ( _bss );
-    _reloc_lma         = ABSOLUTE ( _reloc );
-
-    /*
-     * Load addresses required by the prefix
-     *
-     */
-    efi_entry_lma      = ABSOLUTE ( efi_entry );
-    debugdir_lma       = ABSOLUTE ( debugdir );
-    codeview_rsds_lma  = ABSOLUTE ( codeview_rsds );
-}
index 9ac75b4..a7c4bc0 100644 (file)
@@ -6,3 +6,4 @@ CFLAGS          += -Iarch/x86/include
 #
 SRCDIRS                += arch/x86/core
 SRCDIRS        += arch/x86/interface/efi
+SRCDIRS        += arch/x86/prefix
diff --git a/src/arch/x86/prefix/efiprefix.c b/src/arch/x86/prefix/efiprefix.c
new file mode 100644 (file)
index 0000000..b05b744
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include <gpxe/efi/efi.h>
+
+/**
+ * EFI entry point
+ *
+ * @v image_handle     Image handle
+ * @v systab           System table
+ * @ret efirc          EFI return status code
+ */
+EFI_STATUS EFIAPI _start ( EFI_HANDLE image_handle,
+                          EFI_SYSTEM_TABLE *systab ) {
+       EFI_STATUS efirc;
+
+       /* Initialise EFI environment */
+       if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 )
+               return efirc;
+
+       /* Call to main() */
+       return RC_TO_EFIRC ( main () );
+}
diff --git a/src/arch/x86/scripts/efi.lds b/src/arch/x86/scripts/efi.lds
new file mode 100644 (file)
index 0000000..bfe8173
--- /dev/null
@@ -0,0 +1,106 @@
+/* -*- sh -*- */
+
+/*
+ * Linker script for EFI images
+ *
+ */
+
+EXTERN ( _start )
+ENTRY ( _start )
+
+SECTIONS {
+
+    /* The file starts at a virtual address of zero, and sections are
+     * contiguous.  Each section is aligned to at least _max_align,
+     * which defaults to 32.  Load addresses are equal to virtual
+     * addresses.
+     */
+
+    _max_align = 32;
+
+    /* Allow plenty of space for file headers */
+    . = 0x1000;
+
+    /*
+     * The text section
+     *
+     */
+
+    . = ALIGN ( _max_align );
+    .text : {
+       _text = .;
+       *(.text)
+       *(.text.*)
+       _etext = .;
+    }
+
+    /*
+     * The rodata section
+     *
+     */
+
+    . = ALIGN ( _max_align );
+    .rodata : {
+       _rodata = .;
+       *(.rodata)
+       *(.rodata.*)
+       _erodata = .;
+    }
+
+    /*
+     * The data section
+     *
+     */
+
+    . = ALIGN ( _max_align );
+    .data : {
+       _data = .;
+       *(.data)
+       *(.data.*)
+       *(SORT(.tbl.*))         /* Various tables.  See include/tables.h */
+       _edata = .;
+    }
+
+    /*
+     * The bss section
+     *
+     */
+
+    . = ALIGN ( _max_align );
+    .bss : {
+       _bss = .;
+       *(.bss)
+       *(.bss.*)
+       *(COMMON)
+       _ebss = .;
+    }
+
+    /*
+     * Weak symbols that need zero values if not otherwise defined
+     *
+     */
+
+    .weak 0x0 : {
+       _weak = .;
+       *(.weak)
+       _eweak = .;
+    }
+    _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
+
+    /*
+     * Dispose of the comment and note sections to make the link map
+     * easier to read
+     *
+     */
+
+    /DISCARD/ : {
+       *(.comment)
+       *(.comment.*)
+       *(.note)
+       *(.note.*)
+       *(.eh_frame)
+       *(.eh_frame.*)
+       *(.rel)
+       *(.rel.*)
+    }
+}
index 9b9b373..928f5e9 100644 (file)
@@ -6,11 +6,11 @@ CFLAGS                += -mno-red-zone
 
 # The EFI linker script
 #
-LDSCRIPT       = arch/x86_64/scripts/efi.lds
+LDSCRIPT       = arch/x86/scripts/efi.lds
 
-# Use a relocatable link; we perform final relocations in the efilink utility.
+# Retain relocation information for elf2efi
 #
-LDFLAGS                += -r -d -S
+LDFLAGS                += -q -S
 
 # Media types.
 #
@@ -18,12 +18,6 @@ NON_AUTO_MEDIA       += efi
 
 # Rule for building EFI files
 #
-$(BIN)/%.efi.tmp-reloc : $(BIN)/%.efi.tmp $(EFILINK)
-       $(QM)$(ECHO) "  [EFILINK] $@"
-       $(Q)# Check for unresolved symbols
-       $(Q)$(LD) -e 0 --no-warn-mismatch -o /dev/null $<
-       $(Q)$(EFILINK) $< $@
-
-$(BIN)/%.efi : $(BIN)/%.efi.tmp-reloc
+$(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI64)
        $(QM)$(ECHO) "  [FINISH] $@"
-       $(Q)$(OBJCOPY) -Obinary $< $@
+       $(Q)$(ELF2EFI64) $< $@
diff --git a/src/arch/x86_64/prefix/efiprefix.S b/src/arch/x86_64/prefix/efiprefix.S
deleted file mode 100644 (file)
index a3b503b..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-       .text
-       .code32
-       .arch i386
-       .section ".prefix", "a", @progbits
-       .org 0x00
-
-       /* DOS (.com) header
-        *
-        * EFI executables seem to leave most of this empty
-        */
-mzhdr:
-       .ascii  "MZ"            /* Magic number */
-       .word   0               /* Bytes on last page of file */
-       .word   0               /* Pages in file */
-       .word   0               /* Relocations */
-       .word   0               /* Size of header in paragraphs */
-       .word   0               /* Minimum extra paragraphs needed */
-       .word   0               /* Maximum extra paragraphs needed */
-       .word   0               /* Initial (relative) SS value */
-       .word   0               /* Initial SP value */
-       .word   0               /* "Checksum" */
-       .word   0               /* Initial IP value */
-       .word   0               /* Initial (relative) CS value */
-       .word   0               /* File address of relocation table */
-       .word   0               /* Ovesrlay number */
-       .word   0, 0, 0, 0      /* Reserved words */
-       .word   0               /* OEM identifier (for e_oeminfo) */
-       .word   0               /* OEM information; e_oemid specific */
-       .word   0, 0, 0, 0, 0   /* Reserved words */
-       .word   0, 0, 0, 0, 0   /* Reserved words */
-       .long   pehdr_lma       /* File address of new exe header */
-       .size   mzhdr, . - mzhdr
-
-       /* PE header */
-       .org    0xc0 /* For compatibility with MS toolchain */
-pehdr:
-       .ascii  "PE\0\0"        /* Magic number */
-       .word   0x8664          /* CPU architecture: x86_64 */
-       .word   num_pe_sections /* Number of sections */
-       .long   0x10d1a884      /* Timestamp */
-       .long   0               /* Symbol table */
-       .long   0               /* Number of symbols */
-       .word   opthdr_size     /* Size of optional header */
-       .word   0x2002          /* Characteristics */
-       .size   pehdr, . - pehdr
-       .equ    pehdr_lma, pehdr - mzhdr
-
-       /* "Optional" header */
-opthdr:
-       .word   0x020b          /* Magic number */
-       .byte   0               /* Linker major version number */
-       .byte   0               /* Linker minor version number */
-       .long   _text_filesz    /* Size of text section */
-       .long   _data_filesz    /* Size of data section */
-       .long   _bss_filesz     /* Size of bss section */
-       .long   efi_entry_lma   /* Entry point */
-       .long   _text_lma       /* Text section start RVA */
-       .quad   0               /* Image base address */
-       .long   _max_align      /* Section alignment */
-       .long   _max_align      /* File alignment */
-       .word   0               /* Operating system major version number */
-       .word   0               /* Operating system minor version number */
-       .word   0               /* Image major version number */
-       .word   0               /* Image minor version number */
-       .word   0               /* Subsystem major version number */
-       .word   0               /* Subsystem minor version number */
-       .long   0               /* Reserved */
-       .long   _filesz         /* Total image size */
-       .long   _prefix_filesz  /* Total header size */
-       .long   0               /* "Checksum" */
-       .word   0x0a            /* Subsystem: EFI */
-       .word   0               /* DLL characteristics */
-       .quad   0               /* Size of stack reserve */
-       .quad   0               /* Size of stack commit */
-       .quad   0               /* Size of heap reserve */
-       .quad   0               /* Size of heap commit */
-       .long   0               /* Loader flags */
-       .long   16              /* Number of data directory entries */
-       .long   0, 0            /* Export directory */
-       .long   0, 0            /* Import directory */
-       .long   0, 0            /* Resource directory */
-       .long   0, 0            /* Exception directory */
-       .long   0, 0            /* Security directory */
-       .long   _reloc_lma, _reloc_filesz /* Base relocation directory */
-       .long   debugdir_lma, debugdir_size /* Debug directory */
-       .long   0, 0            /* Description directory */
-       .long   0, 0            /* Special directory */
-       .long   0, 0            /* Thread storage directory */
-       .long   0, 0            /* Load configuration directory */
-       .long   0, 0            /* Bound import directory */
-       .long   0, 0            /* Import address table directory */
-       .long   0, 0            /* Delay import directory */
-       .long   0, 0            /* Reserved */
-       .long   0, 0            /* Reserved */
-       .size   opthdr, . - opthdr
-       .equ    opthdr_size, . - opthdr
-
-       /* PE sections */
-pe_sections:
-text_section:
-       .asciz  ".text"         /* Section name */
-       .align  8
-       .long   _text_filesz    /* Section size */
-       .long   _text_lma       /* Relative Virtual Address */
-       .long   _text_filesz    /* Section size (rounded up) */
-       .long   _text_lma       /* Pointer to raw data */
-       .long   0               /* Link-time relocations */
-       .long   0               /* Line numbers */
-       .word   0               /* Number of link-time relocations */
-       .word   0               /* Number of line numbers */
-       .long   0x68000020      /* Characteristics */
-rodata_section:
-       .asciz  ".rodata"       /* Section name */
-       .align  8
-       .long   _rodata_filesz  /* Section size */
-       .long   _rodata_lma     /* Relative Virtual Address */
-       .long   _rodata_filesz  /* Section size (rounded up) */
-       .long   _rodata_lma     /* Pointer to raw data */
-       .long   0               /* Link-time relocations */
-       .long   0               /* Line numbers */
-       .word   0               /* Number of link-time relocations */
-       .word   0               /* Number of line numbers */
-       .long   0x48000040      /* Characteristics */
-data_section:
-       .asciz  ".data"         /* Section name */
-       .align  8
-       .long   _data_filesz    /* Section size */
-       .long   _data_lma       /* Relative Virtual Address */
-       .long   _data_filesz    /* Section size (rounded up) */
-       .long   _data_lma       /* Pointer to raw data */
-       .long   0               /* Link-time relocations */
-       .long   0               /* Line numbers */
-       .word   0               /* Number of link-time relocations */
-       .word   0               /* Number of line numbers */
-       .long   0xc8000040      /* Characteristics */
-reloc_section:
-       .asciz  ".reloc"        /* Section name */
-       .align  8
-       .long   _reloc_filesz   /* Section size */
-       .long   _reloc_lma      /* Relative Virtual Address */
-       .long   _reloc_filesz   /* Section size (rounded up) */
-       .long   _reloc_lma      /* Pointer to raw data */
-       .long   0               /* Link-time relocations */
-       .long   0               /* Line numbers */
-       .word   0               /* Number of link-time relocations */
-       .word   0               /* Number of line numbers */
-       .long   0x42000040      /* Characteristics */
-
-pe_sections_end:
-       .size   pe_sections, . - pe_sections
-       .equ    num_pe_sections, ( ( . - pe_sections ) / 0x28 )
-
-       /* Debug directory */
-       .section ".rodata"
-       .globl  debugdir
-debugdir:
-       .long   0               /* Characteristics */
-       .long   0x10d1a884      /* Timestamp */
-       .word   0               /* Major version */
-       .word   0               /* Minor version */
-       .long   0x02            /* RSDS? */
-       .long   codeview_rsds_size /* Size of data */
-       .long   codeview_rsds_lma /* RVA */
-       .long   codeview_rsds_lma /* File offset */
-       .size   debugdir, . - debugdir
-       .equ    debugdir_size, . - debugdir
-       /* Codeview structure */
-       .globl  codeview_rsds
-codeview_rsds:
-       .ascii  "RSDS"          /* Magic number */
-       .long   0, 0, 0, 0, 0   /* Unused by EFI */
-       .asciz  "efiprefix.pdb"
-       .size   codeview_rsds, . - codeview_rsds
-       .equ    codeview_rsds_size, . - codeview_rsds
diff --git a/src/arch/x86_64/scripts/efi.lds b/src/arch/x86_64/scripts/efi.lds
deleted file mode 100644 (file)
index 833905c..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/* -*- sh -*- */
-
-/*
- * Linker script for EFI images
- *
- */
-
-EXTERN ( efi_entry )
-
-SECTIONS {
-
-    /* The file starts at a virtual address of zero, and sections are
-     * contiguous.  Each section is aligned to at least _max_align,
-     * which defaults to 32.  Load addresses are equal to virtual
-     * addresses.
-     */
-
-    . = 0;
-    _max_align = 32;
-
-    /*
-     * The prefix
-     *
-     */
-
-    .prefix : {
-       _prefix = .;
-       *(.prefix)
-       *(.prefix.*)
-       _mprefix = .;
-    } .bss.prefix (NOLOAD) : {
-       _eprefix = .;
-    }
-    _prefix_filesz     = ABSOLUTE ( _mprefix - _prefix );
-    _prefix_memsz      = ABSOLUTE ( _eprefix - _prefix );
-
-    /*
-     * The text section
-     *
-     */
-
-    . = ALIGN ( _max_align );
-    .text : {
-       _text = .;
-       *(.text)
-       *(.text.*)
-       _mtext = .;
-    } .bss.text (NOLOAD) : {
-       _etext = .;
-    }
-    _text_filesz       = ABSOLUTE ( _mtext - _text );
-    _text_memsz                = ABSOLUTE ( _etext - _text );
-
-    /*
-     * The rodata section
-     *
-     */
-
-    . = ALIGN ( _max_align );
-    .rodata : {
-       _rodata = .;
-       *(.rodata)
-       *(.rodata.*)
-       _mrodata = .;
-    } .bss.rodata (NOLOAD) : {
-       _erodata = .;
-    }
-    _rodata_filesz     = ABSOLUTE ( _mrodata - _rodata );
-    _rodata_memsz      = ABSOLUTE ( _erodata - _rodata );
-
-    /*
-     * The data section
-     *
-     */
-
-    . = ALIGN ( _max_align );
-    .data : {
-       _data = .;
-       *(.data)
-       *(.data.*)
-       *(SORT(.tbl.*))         /* Various tables.  See include/tables.h */
-       /* EFI seems to not support proper bss sections */
-       *(.bss)
-       *(.bss.*)
-       *(COMMON)
-       *(.stack)
-       *(.stack.*)
-       _mdata = .;
-    } .bss.data (NOLOAD) : {
-       _edata = .;
-    }
-    _data_filesz       = ABSOLUTE ( _mdata - _data );
-    _data_memsz                = ABSOLUTE ( _edata - _data );
-
-    /*
-     * The bss section
-     *
-     */
-
-    . = ALIGN ( _max_align );
-    .bss : {
-       _bss = .;
-       /* EFI seems to not support proper bss sections */
-       _mbss = .;
-    } .bss.bss (NOLOAD) : {
-       _ebss = .;
-    }
-    _bss_filesz                = ABSOLUTE ( _mbss - _bss );
-    _bss_memsz         = ABSOLUTE ( _ebss - _bss );
-
-    /*
-     * The reloc section
-     *
-     */
-
-    . = ALIGN ( _max_align );
-    .reloc : {
-       _reloc = .;
-       /* Provide some dummy contents to force ld to include this
-        * section.  It will be created by the efilink utility.
-        */
-       BYTE(0);
-       _mreloc = .;
-    } .bss.reloc (NOLOAD) : {
-       _ereloc = .;
-    }
-    _reloc_filesz      = ABSOLUTE ( _mreloc - _reloc );
-    _reloc_memsz       = ABSOLUTE ( _ereloc - _reloc );
-
-    _filesz            = ABSOLUTE ( . );
-
-    /*
-     * Weak symbols that need zero values if not otherwise defined
-     *
-     */
-
-    .weak 0x0 : {
-       _weak = .;
-       *(.weak)
-       _eweak = .;
-    }
-    _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
-
-    /*
-     * Dispose of the comment and note sections to make the link map
-     * easier to read
-     *
-     */
-
-    /DISCARD/ : {
-       *(.comment)
-       *(.comment.*)
-       *(.note)
-       *(.note.*)
-       *(.eh_frame)
-       *(.eh_frame.*)
-       *(.rel)
-       *(.rel.*)
-    }
-
-    /*
-     * Load address calculations.
-     *
-     */
-
-    _prefix_lma                = ABSOLUTE ( _prefix );
-    _text_lma          = ABSOLUTE ( _text );
-    _rodata_lma                = ABSOLUTE ( _rodata );
-    _data_lma          = ABSOLUTE ( _data );
-    _bss_lma           = ABSOLUTE ( _bss );
-    _reloc_lma         = ABSOLUTE ( _reloc );
-
-    /*
-     * Load addresses required by the prefix
-     *
-     */
-    efi_entry_lma      = ABSOLUTE ( efi_entry );
-    debugdir_lma       = ABSOLUTE ( debugdir );
-    codeview_rsds_lma  = ABSOLUTE ( codeview_rsds );
-}
index b46d5ca..2f99514 100644 (file)
@@ -124,5 +124,7 @@ extern EFI_HANDLE efi_image_handle;
 extern EFI_SYSTEM_TABLE *efi_systab;
 
 extern const char * efi_strerror ( EFI_STATUS efirc );
+extern EFI_STATUS efi_init ( EFI_HANDLE image_handle,
+                            EFI_SYSTEM_TABLE *systab );
 
 #endif /* _EFI_H */
similarity index 95%
rename from src/interface/efi/efi_entry.c
rename to src/interface/efi/efi_init.c
index 7b670f8..6e54cf7 100644 (file)
@@ -16,7 +16,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <stdlib.h>
 #include <string.h>
 #include <gpxe/efi/efi.h>
 #include <gpxe/uuid.h>
@@ -58,14 +57,14 @@ static void * efi_find_table ( EFI_GUID *guid ) {
 }
 
 /**
- * EFI entry point
+ * Initialise EFI environment
  *
  * @v image_handle     Image handle
  * @v systab           System table
  * @ret efirc          EFI return status code
  */
-EFI_STATUS EFIAPI efi_entry ( EFI_HANDLE image_handle,
-                             EFI_SYSTEM_TABLE *systab ) {
+EFI_STATUS efi_init ( EFI_HANDLE image_handle,
+                     EFI_SYSTEM_TABLE *systab ) {
        EFI_BOOT_SERVICES *bs;
        struct efi_protocol *prot;
        struct efi_config_table *tab;
@@ -119,6 +118,5 @@ EFI_STATUS EFIAPI efi_entry ( EFI_HANDLE image_handle,
                }
        }
 
-       /* Call to main() */
-       return RC_TO_EFIRC ( main () );
+       return 0;
 }
index 7f9d755..07bfc5d 100644 (file)
@@ -2,4 +2,5 @@ nrv2b
 zbin
 hijack
 prototester
-efilink
+elf2efi32
+elf2efi64
diff --git a/src/util/efilink.c b/src/util/efilink.c
deleted file mode 100644 (file)
index 17b99d2..0000000
+++ /dev/null
@@ -1,515 +0,0 @@
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <bfd.h>
-
-struct bfd_file {
-       bfd *bfd;
-       asymbol **symtab;
-       long symcount;
-};
-
-struct pe_relocs {
-       struct pe_relocs *next;
-       unsigned long start_rva;
-       unsigned int used_relocs;
-       unsigned int total_relocs;
-       uint16_t *relocs;
-};
-
-/**
- * Allocate memory
- *
- * @v len              Length of memory to allocate
- * @ret ptr            Pointer to allocated memory
- */
-static void * xmalloc ( size_t len ) {
-       void *ptr;
-
-       ptr = malloc ( len );
-       if ( ! ptr ) {
-               fprintf ( stderr, "Could not allocate %zd bytes\n", len );
-               exit ( 1 );
-       }
-
-       return ptr;
-}
-
-/**
- * Generate entry in PE relocation table
- *
- * @v pe_reltab                PE relocation table
- * @v rva              RVA
- * @v size             Size of relocation entry
- */
-static void generate_pe_reloc ( struct pe_relocs **pe_reltab,
-                               unsigned long rva, size_t size ) {
-       unsigned long start_rva;
-       uint16_t reloc;
-       struct pe_relocs *pe_rel;
-       uint16_t *relocs;
-
-       /* Construct */
-       start_rva = ( rva & ~0xfff );
-       reloc = ( rva & 0xfff );
-       switch ( size ) {
-       case 8:
-               reloc |= 0xa000;
-               break;
-       case 4:
-               reloc |= 0x3000;
-               break;
-       case 2:
-               reloc |= 0x2000;
-               break;
-       default:
-               fprintf ( stderr, "Unsupported relocation size %zd\n", size );
-               exit ( 1 );
-       }
-
-       /* Locate or create PE relocation table */
-       for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
-               if ( pe_rel->start_rva == start_rva )
-                       break;
-       }
-       if ( ! pe_rel ) {
-               pe_rel = xmalloc ( sizeof ( *pe_rel ) );
-               memset ( pe_rel, 0, sizeof ( *pe_rel ) );
-               pe_rel->next = *pe_reltab;
-               *pe_reltab = pe_rel;
-               pe_rel->start_rva = start_rva;
-       }
-
-       /* Expand relocation list if necessary */
-       if ( pe_rel->used_relocs < pe_rel->total_relocs ) {
-               relocs = pe_rel->relocs;
-       } else {
-               pe_rel->total_relocs = ( pe_rel->total_relocs ?
-                                        ( pe_rel->total_relocs * 2 ) : 256 );
-               relocs = xmalloc ( pe_rel->total_relocs *
-                                  sizeof ( pe_rel->relocs[0] ) );
-               memset ( relocs, 0,
-                        pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) );
-               memcpy ( relocs, pe_rel->relocs,
-                        pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) );
-               free ( pe_rel->relocs );
-               pe_rel->relocs = relocs;
-       }
-
-       /* Store relocation */
-       pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc;
-}
-
-/**
- * Calculate size of binary PE relocation table
- *
- * @v pe_reltab                PE relocation table
- * @v buffer           Buffer to contain binary table, or NULL
- * @ret size           Size of binary table
- */
-static size_t output_pe_reltab ( struct pe_relocs *pe_reltab,
-                                void *buffer ) {
-       struct pe_relocs *pe_rel;
-       unsigned int num_relocs;
-       size_t size;
-       size_t total_size = 0;
-
-       for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
-               num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 );
-               size = ( sizeof ( uint32_t ) /* VirtualAddress */ +
-                        sizeof ( uint32_t ) /* SizeOfBlock */ +
-                        ( num_relocs * sizeof ( uint16_t ) ) );
-               if ( buffer ) {
-                       *( (uint32_t *) ( buffer + total_size + 0 ) )
-                               = pe_rel->start_rva;
-                       *( (uint32_t *) ( buffer + total_size + 4 ) ) = size;
-                       memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs,
-                                ( num_relocs * sizeof ( uint16_t ) ) );
-               }
-               total_size += size;
-       }
-
-       return total_size;
-}
-
-/**
- * Read symbol table
- *
- * @v bfd              BFD file
- */
-static void read_symtab ( struct bfd_file *bfd ) {
-       long symtab_size;
-
-       /* Get symbol table size */
-       symtab_size = bfd_get_symtab_upper_bound ( bfd->bfd );
-       if ( symtab_size < 0 ) {
-               bfd_perror ( "Could not get symbol table upper bound" );
-               exit ( 1 );
-       }
-
-       /* Allocate and read symbol table */
-       bfd->symtab = xmalloc ( symtab_size );
-       bfd->symcount = bfd_canonicalize_symtab ( bfd->bfd, bfd->symtab );
-       if ( bfd->symcount < 0 ) {
-               bfd_perror ( "Cannot read symbol table" );
-               exit ( 1 );
-       }
-}
-
-/**
- * Read relocation table
- *
- * @v bfd              BFD file
- * @v section          Section
- * @v symtab           Symbol table
- * @ret reltab         Relocation table
- */
-static arelent ** read_reltab ( struct bfd_file *bfd, asection *section ) {
-       long reltab_size;
-       arelent **reltab;
-       long numrels;
-
-       /* Get relocation table size */
-       reltab_size = bfd_get_reloc_upper_bound ( bfd->bfd, section );
-       if ( reltab_size < 0 ) {
-               bfd_perror ( "Could not get relocation table upper bound" );
-               exit ( 1 );
-       }
-
-       /* Allocate and read relocation table */
-       reltab = xmalloc ( reltab_size );
-       numrels = bfd_canonicalize_reloc ( bfd->bfd, section, reltab,
-                                          bfd->symtab );
-       if ( numrels < 0 ) {
-               bfd_perror ( "Cannot read relocation table" );
-               exit ( 1 );
-       }
-
-       return reltab;
-}
-
-
-/**
- * Open input BFD file
- *
- * @v filename         File name
- * @ret ibfd           BFD file
- */
-static struct bfd_file * open_input_bfd ( const char *filename ) {
-       struct bfd_file *ibfd;
-
-       /* Create BFD file */
-       ibfd = xmalloc ( sizeof ( *ibfd ) );
-       memset ( ibfd, 0, sizeof ( *ibfd ) );
-
-       /* Open the file */
-       ibfd->bfd = bfd_openr ( filename, NULL );
-       if ( ! ibfd->bfd ) {
-               fprintf ( stderr, "Cannot open %s: ", filename );
-               bfd_perror ( NULL );
-               exit ( 1 );
-       }
-
-       /* The call to bfd_check_format() must be present, otherwise
-        * we get a segfault from later BFD calls.
-        */
-       if ( bfd_check_format ( ibfd->bfd, bfd_object ) < 0 ) {
-               fprintf ( stderr, "%s is not an object file\n", filename );
-               exit ( 1 );
-       }
-
-       /* Read symbols and relocation entries */
-       read_symtab ( ibfd );
-
-       return ibfd;
-}
-
-/**
- * Open output BFD file
- *
- * @v filename         File name
- * @v ibfd             Input BFD file
- * @ret obfd           BFD file
- */
-static struct bfd_file * open_output_bfd ( const char *filename,
-                                          struct bfd_file *ibfd ) {
-       struct bfd_file *obfd;
-       asection *isection;
-       asection *osection;
-
-       /*
-        * Most of this code is based on what objcopy.c does.
-        *
-        */
-
-       /* Create BFD file */
-       obfd = xmalloc ( sizeof ( *obfd ) );
-       memset ( obfd, 0, sizeof ( *obfd ) );
-
-       /* Open the file */
-       obfd->bfd = bfd_openw ( filename, ibfd->bfd->xvec->name );
-       if ( ! obfd->bfd ) {
-               fprintf ( stderr, "Cannot open %s: ", filename );
-               bfd_perror ( NULL );
-               exit ( 1 );
-       }
-
-       /* Copy per-file data */
-       if ( ! bfd_set_arch_mach ( obfd->bfd, bfd_get_arch ( ibfd->bfd ),
-                                  bfd_get_mach ( ibfd->bfd ) ) ) {
-               bfd_perror ( "Cannot copy architecture" );
-               exit ( 1 );
-       }
-       if ( ! bfd_set_format ( obfd->bfd, bfd_get_format ( ibfd->bfd ) ) ) {
-               bfd_perror ( "Cannot copy format" );
-               exit ( 1 );
-       }
-       if ( ! bfd_copy_private_header_data ( ibfd->bfd, obfd->bfd ) ) {
-               bfd_perror ( "Cannot copy private header data" );
-               exit ( 1 );
-       }
-
-       /* Create sections */
-       for ( isection = ibfd->bfd->sections ; isection ;
-             isection = isection->next ) {
-               osection = bfd_make_section_anyway ( obfd->bfd,
-                                                    isection->name );
-               if ( ! osection ) {
-                       bfd_perror ( "Cannot create section" );
-                       exit ( 1 );
-               }
-               if ( ! bfd_set_section_flags ( obfd->bfd, osection,
-                                              isection->flags ) ) {
-                       bfd_perror ( "Cannot copy section flags" );
-                       exit ( 1 );
-               }
-               if ( ! bfd_set_section_size ( obfd->bfd, osection,
-                                bfd_section_size ( ibfd->bfd, isection ) ) ) {
-                       bfd_perror ( "Cannot copy section size" );
-                       exit ( 1 );
-               }
-               if ( ! bfd_set_section_vma ( obfd->bfd, osection,
-                                 bfd_section_vma ( ibfd->bfd, isection ) ) ) {
-                       bfd_perror ( "Cannot copy section VMA" );
-                       exit ( 1 );
-               }
-               osection->lma = bfd_section_lma ( ibfd->bfd, isection );
-               if ( ! bfd_set_section_alignment ( obfd->bfd, osection,
-                           bfd_section_alignment ( ibfd->bfd, isection ) ) ) {
-                       bfd_perror ( "Cannot copy section alignment" );
-                       exit ( 1 );
-               }
-               osection->entsize = isection->entsize;
-               isection->output_section = osection;
-               isection->output_offset = 0;
-               if ( ! bfd_copy_private_section_data ( ibfd->bfd, isection,
-                                                      obfd->bfd, osection ) ){
-                       bfd_perror ( "Cannot copy section private data" );
-                       exit ( 1 );
-               }
-       }
-
-       /* Copy symbol table */
-       bfd_set_symtab ( obfd->bfd, ibfd->symtab, ibfd->symcount );
-       obfd->symtab = ibfd->symtab;
-
-       return obfd;
-}
-
-/**
- * Copy section from input BFD file to output BFD file
- *
- * @v obfd             Output BFD file
- * @v ibfd             Input BFD file
- * @v section          Section
- */
-static void copy_bfd_section ( struct bfd_file *obfd, struct bfd_file *ibfd,
-                              asection *isection ) {
-       size_t size;
-       void *buf;
-       arelent **reltab;
-       arelent **rel;
-       char *errmsg;
-
-       /* Read in original section */
-       size = bfd_section_size ( ibfd->bfd, isection );
-       if ( ! size )
-               return;
-       buf = xmalloc ( size );
-       if ( ( ! bfd_get_section_contents ( ibfd->bfd, isection,
-                                           buf, 0, size ) ) ) {
-               fprintf ( stderr, "Cannot read section %s: ", isection->name );
-               bfd_perror ( NULL );
-               exit ( 1 );
-       }
-
-       /* Perform relocations.  We do this here, rather than letting
-        * ld do it for us when creating the input ELF file, so that
-        * we can change symbol values as a result of having created
-        * the .reloc section.
-        */
-       reltab = read_reltab ( ibfd, isection );
-       for ( rel = reltab ; *rel ; rel++ ) {
-               bfd_perform_relocation ( ibfd->bfd, *rel, buf, isection,
-                                        NULL, &errmsg );
-       }
-       free ( reltab );
-
-       /* Write out modified section */
-       if ( ( ! bfd_set_section_contents ( obfd->bfd,
-                                           isection->output_section,
-                                           buf, 0, size ) ) ) {
-               fprintf ( stderr, "Cannot write section %s: ",
-                         isection->output_section->name );
-               bfd_perror ( NULL );
-               exit ( 1 );
-       }
-
-       free ( buf );
-}
-
-/**
- * Process relocation record
- *
- * @v section          Section
- * @v rel              Relocation entry
- * @v pe_reltab                PE relocation table to fill in
- */
-static void process_reloc ( asection *section, arelent *rel,
-                           struct pe_relocs **pe_reltab ) {
-       reloc_howto_type *howto = rel->howto;
-       asymbol *sym = *(rel->sym_ptr_ptr);
-       unsigned long offset = ( section->lma + rel->address );
-
-       if ( bfd_is_abs_section ( sym->section ) ) {
-               /* Skip absolute symbols; the symbol value won't
-                * change when the object is loaded.
-                */
-       } else if ( strcmp ( howto->name, "R_X86_64_64" ) == 0 ) {
-               /* Generate an 8-byte PE relocation */
-               generate_pe_reloc ( pe_reltab, offset, 8 );
-       } else if ( ( strcmp ( howto->name, "R_386_32" ) == 0 ) ||
-                   ( strcmp ( howto->name, "R_X86_64_32" ) == 0 ) ) {
-               /* Generate a 4-byte PE relocation */
-               generate_pe_reloc ( pe_reltab, offset, 4 );
-       } else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
-               /* Generate a 2-byte PE relocation */
-               generate_pe_reloc ( pe_reltab, offset, 2 );
-       } else if ( ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) ||
-                   ( strcmp ( howto->name, "R_X86_64_PC32" ) == 0 ) ) {
-               /* Skip PC-relative relocations; all relative offsets
-                * remain unaltered when the object is loaded.
-                */
-       } else {
-               fprintf ( stderr, "Unrecognised relocation type %s\n",
-                         howto->name );
-               exit ( 1 );
-       }
-}
-
-/**
- * Create .reloc section
- *
- * obfd                        Output BFD file
- * section             .reloc section in output file
- * pe_reltab           PE relocation table
- */
-static void create_reloc_section ( struct bfd_file *obfd, asection *section,
-                                  struct pe_relocs *pe_reltab ) {
-       size_t raw_size;
-       size_t size;
-       size_t old_size;
-       void *buf;
-       asymbol **sym;
-
-       /* Build binary PE relocation table */
-       raw_size = output_pe_reltab ( pe_reltab, NULL );
-       size = ( ( raw_size + 31 ) & ~31 );
-       buf = xmalloc ( size );
-       memset ( buf, 0, size );
-       output_pe_reltab ( pe_reltab, buf );
-
-       /* Write .reloc section */
-       old_size = bfd_section_size ( obfd->bfd, section );
-       if ( ! bfd_set_section_size ( obfd->bfd, section, size ) ) {
-               bfd_perror ( "Cannot resize .reloc section" );
-               exit ( 1 );
-       }
-       if ( ! bfd_set_section_contents ( obfd->bfd, section,
-                                         buf, 0, size ) ) {
-               bfd_perror ( "Cannot set .reloc section contents" );
-               exit ( 1 );
-       }
-
-       /* Update symbols pertaining to the relocation directory */
-       for ( sym = obfd->symtab ; *sym ; sym++ ) {
-               if ( strcmp ( (*sym)->name, "_reloc_memsz" ) == 0 ) {
-                       (*sym)->value = size;
-               } else if ( strcmp ( (*sym)->name, "_reloc_filesz" ) == 0 ){
-                       (*sym)->value = raw_size;
-               } else if ( strcmp ( (*sym)->name, "_filesz" ) == 0 ) {
-                       (*sym)->value += ( size - old_size );
-               }
-       }
-}
-
-int main ( int argc, const char *argv[] ) {
-       const char *iname;
-       const char *oname;
-       struct bfd_file *ibfd;
-       struct bfd_file *obfd;
-       asection *section;
-       arelent **reltab;
-       arelent **rel;
-       struct pe_relocs *pe_reltab = NULL;
-       asection *reloc_section;
-
-       /* Initialise libbfd */
-       bfd_init();
-
-       /* Identify intput and output files */
-       if ( argc != 3 ) {
-               fprintf ( stderr, "Syntax: %s infile outfile\n", argv[0] );
-               exit ( 1 );
-       }
-       iname = argv[1];
-       oname = argv[2];
-
-       /* Open BFD files */
-       ibfd = open_input_bfd ( iname );
-       obfd = open_output_bfd ( oname, ibfd );
-
-       /* Process relocations in all sections */
-       for ( section = ibfd->bfd->sections ; section ;
-             section = section->next ) {
-               reltab = read_reltab ( ibfd, section );
-               for ( rel = reltab ; *rel ; rel++ ) {
-                       process_reloc ( section, *rel, &pe_reltab );
-               }
-               free ( reltab );
-       }
-
-       /* Create modified .reloc section */
-       reloc_section = bfd_get_section_by_name ( obfd->bfd, ".reloc" );
-       if ( ! reloc_section ) {
-               fprintf ( stderr, "Cannot find .reloc section\n" );
-               exit ( 1 );
-       }
-       create_reloc_section ( obfd, reloc_section, pe_reltab );
-
-       /* Copy other section contents */
-       for ( section = ibfd->bfd->sections ; section ;
-             section = section->next ) {
-               if ( section->output_section != reloc_section )
-                       copy_bfd_section ( obfd, ibfd, section );
-       }
-
-       /* Write out files and clean up */
-       bfd_close ( obfd->bfd );
-       bfd_close ( ibfd->bfd );
-
-       return 0;
-}
diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c
new file mode 100644 (file)
index 0000000..0c65a44
--- /dev/null
@@ -0,0 +1,764 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <bfd.h>
+
+/* Include the EFI PE image header file */
+typedef uint8_t UINT8;
+typedef uint16_t UINT16;
+typedef uint32_t UINT32;
+typedef uint64_t UINT64;
+#define SIGNATURE_16( a, b ) ( (a) | ( (b) << 8 ) )
+#define SIGNATURE_32( a, b, c, d ) \
+       ( (a) | ( (b) << 8 ) | ( (c) << 16 ) | ( (d) << 24 ) )
+#define  BIT0     0x00000001
+#define  BIT1     0x00000002
+#define  BIT2     0x00000004
+#define  BIT3     0x00000008
+#define  BIT4     0x00000010
+#define  BIT5     0x00000020
+#define  BIT6     0x00000040
+#define  BIT7     0x00000080
+#define  BIT8     0x00000100
+#define  BIT9     0x00000200
+#define  BIT10    0x00000400
+#define  BIT11    0x00000800
+#define  BIT12    0x00001000
+#define  BIT13    0x00002000
+#define  BIT14    0x00004000
+#define  BIT15    0x00008000
+#define  BIT16    0x00010000
+#define  BIT17    0x00020000
+#define  BIT18    0x00040000
+#define  BIT19    0x00080000
+#define  BIT20    0x00100000
+#define  BIT21    0x00200000
+#define  BIT22    0x00400000
+#define  BIT23    0x00800000
+#define  BIT24    0x01000000
+#define  BIT25    0x02000000
+#define  BIT26    0x04000000
+#define  BIT27    0x08000000
+#define  BIT28    0x10000000
+#define  BIT29    0x20000000
+#define  BIT30    0x40000000
+#define  BIT31    0x80000000
+#include "../include/gpxe/efi/IndustryStandard/PeImage.h"
+
+#define EFI_FILE_ALIGN 0x20
+
+struct pe_section {
+       struct pe_section *next;
+       EFI_IMAGE_SECTION_HEADER hdr;
+       uint8_t contents[0];
+};
+
+struct pe_relocs {
+       struct pe_relocs *next;
+       unsigned long start_rva;
+       unsigned int used_relocs;
+       unsigned int total_relocs;
+       uint16_t *relocs;
+};
+
+struct pe_header {
+       EFI_IMAGE_DOS_HEADER dos;
+       uint8_t padding[128];
+#if defined(MDE_CPU_IA32)
+       EFI_IMAGE_NT_HEADERS32 nt;
+#elif defined(MDE_CPU_X64)
+       EFI_IMAGE_NT_HEADERS64 nt;
+#endif
+};
+
+static struct pe_header efi_pe_header = {
+       .dos = {
+               .e_magic = EFI_IMAGE_DOS_SIGNATURE,
+               .e_lfanew = offsetof ( typeof ( efi_pe_header ), nt ),
+       },
+       .nt = {
+               .Signature = EFI_IMAGE_NT_SIGNATURE,
+               .FileHeader = {
+#if defined(MDE_CPU_IA32)
+                       .Machine = EFI_IMAGE_MACHINE_IA32,
+#elif defined(MDE_CPU_X64)
+                       .Machine = EFI_IMAGE_MACHINE_X64,
+#endif
+                       .TimeDateStamp = 0x10d1a884,
+                       .SizeOfOptionalHeader =
+                               sizeof ( efi_pe_header.nt.OptionalHeader ),
+                       .Characteristics = ( EFI_IMAGE_FILE_DLL |
+#if defined(MDE_CPU_IA32)
+                                            EFI_IMAGE_FILE_32BIT_MACHINE |
+#endif
+                                            EFI_IMAGE_FILE_EXECUTABLE_IMAGE ),
+               },
+               .OptionalHeader = {
+#if defined(MDE_CPU_IA32)
+                       .Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC,
+#elif defined(MDE_CPU_X64)
+                       .Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC,
+#endif
+                       .SectionAlignment = EFI_FILE_ALIGN,
+                       .FileAlignment = EFI_FILE_ALIGN,
+                       .SizeOfImage = sizeof ( efi_pe_header ),
+                       .SizeOfHeaders = sizeof ( efi_pe_header ),
+                       .Subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
+                       .NumberOfRvaAndSizes =
+                               EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES,
+               },
+       },
+};
+
+/**
+ * Allocate memory
+ *
+ * @v len              Length of memory to allocate
+ * @ret ptr            Pointer to allocated memory
+ */
+static void * xmalloc ( size_t len ) {
+       void *ptr;
+
+       ptr = malloc ( len );
+       if ( ! ptr ) {
+               fprintf ( stderr, "Could not allocate %zd bytes\n", len );
+               exit ( 1 );
+       }
+
+       return ptr;
+}
+
+/**
+ * Align section within PE file
+ *
+ * @v offset           Unaligned offset
+ * @ret aligned_offset Aligned offset
+ */
+static unsigned long efi_file_align ( unsigned long offset ) {
+       return ( ( offset + EFI_FILE_ALIGN - 1 ) & ~( EFI_FILE_ALIGN - 1 ) );
+}
+
+/**
+ * Generate entry in PE relocation table
+ *
+ * @v pe_reltab                PE relocation table
+ * @v rva              RVA
+ * @v size             Size of relocation entry
+ */
+static void generate_pe_reloc ( struct pe_relocs **pe_reltab,
+                               unsigned long rva, size_t size ) {
+       unsigned long start_rva;
+       uint16_t reloc;
+       struct pe_relocs *pe_rel;
+       uint16_t *relocs;
+
+       /* Construct */
+       start_rva = ( rva & ~0xfff );
+       reloc = ( rva & 0xfff );
+       switch ( size ) {
+       case 8:
+               reloc |= 0xa000;
+               break;
+       case 4:
+               reloc |= 0x3000;
+               break;
+       case 2:
+               reloc |= 0x2000;
+               break;
+       default:
+               fprintf ( stderr, "Unsupported relocation size %zd\n", size );
+               exit ( 1 );
+       }
+
+       /* Locate or create PE relocation table */
+       for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+               if ( pe_rel->start_rva == start_rva )
+                       break;
+       }
+       if ( ! pe_rel ) {
+               pe_rel = xmalloc ( sizeof ( *pe_rel ) );
+               memset ( pe_rel, 0, sizeof ( *pe_rel ) );
+               pe_rel->next = *pe_reltab;
+               *pe_reltab = pe_rel;
+               pe_rel->start_rva = start_rva;
+       }
+
+       /* Expand relocation list if necessary */
+       if ( pe_rel->used_relocs < pe_rel->total_relocs ) {
+               relocs = pe_rel->relocs;
+       } else {
+               pe_rel->total_relocs = ( pe_rel->total_relocs ?
+                                        ( pe_rel->total_relocs * 2 ) : 256 );
+               relocs = xmalloc ( pe_rel->total_relocs *
+                                  sizeof ( pe_rel->relocs[0] ) );
+               memset ( relocs, 0,
+                        pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) );
+               memcpy ( relocs, pe_rel->relocs,
+                        pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) );
+               free ( pe_rel->relocs );
+               pe_rel->relocs = relocs;
+       }
+
+       /* Store relocation */
+       pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc;
+}
+
+/**
+ * Calculate size of binary PE relocation table
+ *
+ * @v pe_reltab                PE relocation table
+ * @v buffer           Buffer to contain binary table, or NULL
+ * @ret size           Size of binary table
+ */
+static size_t output_pe_reltab ( struct pe_relocs *pe_reltab,
+                                void *buffer ) {
+       struct pe_relocs *pe_rel;
+       unsigned int num_relocs;
+       size_t size;
+       size_t total_size = 0;
+
+       for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+               num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 );
+               size = ( sizeof ( uint32_t ) /* VirtualAddress */ +
+                        sizeof ( uint32_t ) /* SizeOfBlock */ +
+                        ( num_relocs * sizeof ( uint16_t ) ) );
+               if ( buffer ) {
+                       *( (uint32_t *) ( buffer + total_size + 0 ) )
+                               = pe_rel->start_rva;
+                       *( (uint32_t *) ( buffer + total_size + 4 ) ) = size;
+                       memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs,
+                                ( num_relocs * sizeof ( uint16_t ) ) );
+               }
+               total_size += size;
+       }
+
+       return total_size;
+}
+
+/**
+ * Open input BFD file
+ *
+ * @v filename         File name
+ * @ret ibfd           BFD file
+ */
+static bfd * open_input_bfd ( const char *filename ) {
+       bfd *bfd;
+
+       /* Open the file */
+       bfd = bfd_openr ( filename, NULL );
+       if ( ! bfd ) {
+               fprintf ( stderr, "Cannot open %s: ", filename );
+               bfd_perror ( NULL );
+               exit ( 1 );
+       }
+
+       /* The call to bfd_check_format() must be present, otherwise
+        * we get a segfault from later BFD calls.
+        */
+       if ( bfd_check_format ( bfd, bfd_object ) < 0 ) {
+               fprintf ( stderr, "%s is not an object file\n", filename );
+               exit ( 1 );
+       }
+
+       return bfd;
+}
+
+/**
+ * Read symbol table
+ *
+ * @v bfd              BFD file
+ */
+static asymbol ** read_symtab ( bfd *bfd ) {
+       long symtab_size;
+       asymbol **symtab;
+       long symcount;
+
+       /* Get symbol table size */
+       symtab_size = bfd_get_symtab_upper_bound ( bfd );
+       if ( symtab_size < 0 ) {
+               bfd_perror ( "Could not get symbol table upper bound" );
+               exit ( 1 );
+       }
+
+       /* Allocate and read symbol table */
+       symtab = xmalloc ( symtab_size );
+       symcount = bfd_canonicalize_symtab ( bfd, symtab );
+       if ( symcount < 0 ) {
+               bfd_perror ( "Cannot read symbol table" );
+               exit ( 1 );
+       }
+
+       return symtab;
+}
+
+/**
+ * Read relocation table
+ *
+ * @v bfd              BFD file
+ * @v symtab           Symbol table
+ * @v section          Section
+ * @v symtab           Symbol table
+ * @ret reltab         Relocation table
+ */
+static arelent ** read_reltab ( bfd *bfd, asymbol **symtab,
+                               asection *section ) {
+       long reltab_size;
+       arelent **reltab;
+       long numrels;
+
+       /* Get relocation table size */
+       reltab_size = bfd_get_reloc_upper_bound ( bfd, section );
+       if ( reltab_size < 0 ) {
+               bfd_perror ( "Could not get relocation table upper bound" );
+               exit ( 1 );
+       }
+
+       /* Allocate and read relocation table */
+       reltab = xmalloc ( reltab_size );
+       numrels = bfd_canonicalize_reloc ( bfd, section, reltab, symtab );
+       if ( numrels < 0 ) {
+               bfd_perror ( "Cannot read relocation table" );
+               exit ( 1 );
+       }
+
+       return reltab;
+}
+
+/**
+ * Process section
+ *
+ * @v bfd              BFD file
+ * @v pe_header                PE file header
+ * @v section          Section
+ * @ret new            New PE section
+ */
+static struct pe_section * process_section ( bfd *bfd,
+                                            struct pe_header *pe_header,
+                                            asection *section ) {
+       struct pe_section *new;
+       size_t section_memsz;
+       size_t section_filesz;
+       unsigned long flags = bfd_get_section_flags ( bfd, section );
+       unsigned long code_start;
+       unsigned long code_end;
+       unsigned long data_start;
+       unsigned long data_mid;
+       unsigned long data_end;
+       unsigned long start;
+       unsigned long end;
+       unsigned long *applicable_start;
+       unsigned long *applicable_end;
+
+       /* Extract current RVA limits from file header */
+       code_start = pe_header->nt.OptionalHeader.BaseOfCode;
+       code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode );
+#if defined(MDE_CPU_IA32)
+       data_start = pe_header->nt.OptionalHeader.BaseOfData;
+#elif defined(MDE_CPU_X64)
+       data_start = code_end;
+#endif
+       data_mid = ( data_start +
+                    pe_header->nt.OptionalHeader.SizeOfInitializedData );
+       data_end = ( data_mid +
+                    pe_header->nt.OptionalHeader.SizeOfUninitializedData );
+
+       /* Allocate PE section */
+       section_memsz = bfd_section_size ( bfd, section );
+       section_filesz = ( ( flags & SEC_LOAD ) ?
+                          efi_file_align ( section_memsz ) : 0 );
+       new = xmalloc ( sizeof ( *new ) + section_filesz );
+       memset ( new, 0, sizeof ( *new ) + section_filesz );
+
+       /* Fill in section header details */
+       strncpy ( ( char * ) new->hdr.Name, section->name,
+                 sizeof ( new->hdr.Name ) );
+       new->hdr.Misc.VirtualSize = section_memsz;
+       new->hdr.VirtualAddress = bfd_get_section_vma ( bfd, section );
+       new->hdr.SizeOfRawData = section_filesz;
+
+       /* Fill in section characteristics and update RVA limits */
+       if ( flags & SEC_CODE ) {
+               /* .text-type section */
+               new->hdr.Characteristics =
+                       ( EFI_IMAGE_SCN_CNT_CODE |
+                         EFI_IMAGE_SCN_MEM_NOT_PAGED |
+                         EFI_IMAGE_SCN_MEM_EXECUTE |
+                         EFI_IMAGE_SCN_MEM_READ );
+               applicable_start = &code_start;
+               applicable_end = &code_end;
+       } else if ( flags & SEC_DATA ) {
+               /* .data-type section */
+               new->hdr.Characteristics =
+                       ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+                         EFI_IMAGE_SCN_MEM_NOT_PAGED |
+                         EFI_IMAGE_SCN_MEM_READ |
+                         EFI_IMAGE_SCN_MEM_WRITE );
+               applicable_start = &data_start;
+               applicable_end = &data_mid;
+       } else if ( flags & SEC_READONLY ) {
+               /* .rodata-type section */
+               new->hdr.Characteristics =
+                       ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+                         EFI_IMAGE_SCN_MEM_NOT_PAGED |
+                         EFI_IMAGE_SCN_MEM_READ );
+               applicable_start = &data_start;
+               applicable_end = &data_mid;
+       } else if ( ! ( flags & SEC_LOAD ) ) {
+               /* .bss-type section */
+               new->hdr.Characteristics =
+                       ( EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA |
+                         EFI_IMAGE_SCN_MEM_NOT_PAGED |
+                         EFI_IMAGE_SCN_MEM_READ |
+                         EFI_IMAGE_SCN_MEM_WRITE );
+               applicable_start = &data_mid;
+               applicable_end = &data_end;
+       }
+
+       /* Copy in section contents */
+       if ( flags & SEC_LOAD ) {
+               if ( ! bfd_get_section_contents ( bfd, section, new->contents,
+                                                 0, section_memsz ) ) {
+                       fprintf ( stderr, "Cannot read section %s: ",
+                                 section->name );
+                       bfd_perror ( NULL );
+                       exit ( 1 );
+               }
+       }
+
+       /* Update RVA limits */
+       start = new->hdr.VirtualAddress;
+       end = ( start + new->hdr.Misc.VirtualSize );
+       if ( ( ! *applicable_start ) || ( *applicable_start >= start ) )
+               *applicable_start = start;
+       if ( *applicable_end < end )
+               *applicable_end = end;
+       if ( data_start < code_end )
+               data_start = code_end;
+       if ( data_mid < data_start )
+               data_mid = data_start;
+       if ( data_end < data_mid )
+               data_end = data_mid;
+
+       /* Write RVA limits back to file header */
+       pe_header->nt.OptionalHeader.BaseOfCode = code_start;
+       pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start );
+#if defined(MDE_CPU_IA32)
+       pe_header->nt.OptionalHeader.BaseOfData = data_start;
+#endif
+       pe_header->nt.OptionalHeader.SizeOfInitializedData =
+               ( data_mid - data_start );
+       pe_header->nt.OptionalHeader.SizeOfUninitializedData =
+               ( data_end - data_mid );
+
+       /* Update remaining file header fields */
+       pe_header->nt.FileHeader.NumberOfSections++;
+       pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr );
+       pe_header->nt.OptionalHeader.SizeOfImage =
+               efi_file_align ( data_end );
+
+       return new;
+}
+
+/**
+ * Process relocation record
+ *
+ * @v bfd              BFD file
+ * @v section          Section
+ * @v rel              Relocation entry
+ * @v pe_reltab                PE relocation table to fill in
+ */
+static void process_reloc ( bfd *bfd, asection *section, arelent *rel,
+                           struct pe_relocs **pe_reltab ) {
+       reloc_howto_type *howto = rel->howto;
+       asymbol *sym = *(rel->sym_ptr_ptr);
+       unsigned long offset = ( bfd_get_section_vma ( bfd, section ) +
+                                rel->address );
+
+       if ( bfd_is_abs_section ( sym->section ) ) {
+               /* Skip absolute symbols; the symbol value won't
+                * change when the object is loaded.
+                */
+       } else if ( strcmp ( howto->name, "R_X86_64_64" ) == 0 ) {
+               /* Generate an 8-byte PE relocation */
+               generate_pe_reloc ( pe_reltab, offset, 8 );
+       } else if ( ( strcmp ( howto->name, "R_386_32" ) == 0 ) ||
+                   ( strcmp ( howto->name, "R_X86_64_32" ) == 0 ) ) {
+               /* Generate a 4-byte PE relocation */
+               generate_pe_reloc ( pe_reltab, offset, 4 );
+       } else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
+               /* Generate a 2-byte PE relocation */
+               generate_pe_reloc ( pe_reltab, offset, 2 );
+       } else if ( ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) ||
+                   ( strcmp ( howto->name, "R_X86_64_PC32" ) == 0 ) ) {
+               /* Skip PC-relative relocations; all relative offsets
+                * remain unaltered when the object is loaded.
+                */
+       } else {
+               fprintf ( stderr, "Unrecognised relocation type %s\n",
+                         howto->name );
+               exit ( 1 );
+       }
+}
+
+/**
+ * Create relocations section
+ *
+ * @v pe_header                PE file header
+ * @v pe_reltab                PE relocation table
+ * @ret section                Relocation section
+ */
+static struct pe_section *
+create_reloc_section ( struct pe_header *pe_header,
+                      struct pe_relocs *pe_reltab ) {
+       struct pe_section *reloc;
+       size_t section_memsz;
+       size_t section_filesz;
+       EFI_IMAGE_DATA_DIRECTORY *relocdir;
+
+       /* Allocate PE section */
+       section_memsz = output_pe_reltab ( pe_reltab, NULL );
+       section_filesz = efi_file_align ( section_memsz );
+       reloc = xmalloc ( sizeof ( *reloc ) + section_filesz );
+       memset ( reloc, 0, sizeof ( *reloc ) + section_filesz );
+
+       /* Fill in section header details */
+       strncpy ( ( char * ) reloc->hdr.Name, ".reloc",
+                 sizeof ( reloc->hdr.Name ) );
+       reloc->hdr.Misc.VirtualSize = section_memsz;
+       reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
+       reloc->hdr.SizeOfRawData = section_filesz;
+       reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+                                      EFI_IMAGE_SCN_MEM_NOT_PAGED |
+                                      EFI_IMAGE_SCN_MEM_READ );
+
+       /* Copy in section contents */
+       output_pe_reltab ( pe_reltab, reloc->contents );
+
+       /* Update file header details */
+       pe_header->nt.FileHeader.NumberOfSections++;
+       pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr );
+       pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
+       relocdir = &(pe_header->nt.OptionalHeader.DataDirectory
+                    [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]);
+       relocdir->VirtualAddress = reloc->hdr.VirtualAddress;
+       relocdir->Size = reloc->hdr.Misc.VirtualSize;
+
+       return reloc;
+}
+
+/**
+ * Create debug section
+ *
+ * @v pe_header                PE file header
+ * @ret section                Debug section
+ */
+static struct pe_section *
+create_debug_section ( struct pe_header *pe_header, const char *filename ) {
+       struct pe_section *debug;
+       size_t section_memsz;
+       size_t section_filesz;
+       EFI_IMAGE_DATA_DIRECTORY *debugdir;
+       struct {
+               EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug;
+               EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds;
+               char name[ strlen ( filename ) + 1 ];
+       } *contents;
+
+       /* Allocate PE section */
+       section_memsz = sizeof ( *contents );
+       section_filesz = efi_file_align ( section_memsz );
+       debug = xmalloc ( sizeof ( *debug ) + section_filesz );
+       memset ( debug, 0, sizeof ( *debug ) + section_filesz );
+       contents = ( void * ) debug->contents;
+
+       /* Fill in section header details */
+       strncpy ( ( char * ) debug->hdr.Name, ".debug",
+                 sizeof ( debug->hdr.Name ) );
+       debug->hdr.Misc.VirtualSize = section_memsz;
+       debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
+       debug->hdr.SizeOfRawData = section_filesz;
+       debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+                                      EFI_IMAGE_SCN_MEM_NOT_PAGED |
+                                      EFI_IMAGE_SCN_MEM_READ );
+
+       /* Create section contents */
+       contents->debug.TimeDateStamp = 0x10d1a884;
+       contents->debug.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
+       contents->debug.SizeOfData =
+               ( sizeof ( *contents ) - sizeof ( contents->debug ) );
+       contents->debug.RVA = ( debug->hdr.VirtualAddress +
+                               offsetof ( typeof ( *contents ), rsds ) );
+       contents->rsds.Signature = CODEVIEW_SIGNATURE_RSDS;
+       snprintf ( contents->name, sizeof ( contents->name ), "%s",
+                  filename );
+
+       /* Update file header details */
+       pe_header->nt.FileHeader.NumberOfSections++;
+       pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr );
+       pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
+       debugdir = &(pe_header->nt.OptionalHeader.DataDirectory
+                    [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+       debugdir->VirtualAddress = debug->hdr.VirtualAddress;
+       debugdir->Size = debug->hdr.Misc.VirtualSize;
+
+       return debug;
+}
+
+/**
+ * Write out PE file
+ *
+ * @v pe_header                PE file header
+ * @v pe_sections      List of PE sections
+ * @v pe               Output file
+ */
+static void write_pe_file ( struct pe_header *pe_header,
+                           struct pe_section *pe_sections,
+                           FILE *pe ) {
+       struct pe_section *section;
+       unsigned long fpos = 0;
+
+       /* Assign raw data pointers */
+       fpos = efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
+       for ( section = pe_sections ; section ; section = section->next ) {
+               if ( section->hdr.SizeOfRawData ) {
+                       section->hdr.PointerToRawData = fpos;
+                       fpos += section->hdr.SizeOfRawData;
+                       fpos = efi_file_align ( fpos );
+               }
+       }
+
+       /* Write file header */
+       if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) {
+               perror ( "Could not write PE header" );
+               exit ( 1 );
+       }
+
+       /* Write section headers */
+       for ( section = pe_sections ; section ; section = section->next ) {
+               if ( fwrite ( &section->hdr, sizeof ( section->hdr ),
+                             1, pe ) != 1 ) {
+                       perror ( "Could not write section header" );
+                       exit ( 1 );
+               }
+       }
+
+       /* Write sections */
+       for ( section = pe_sections ; section ; section = section->next ) {
+               if ( fseek ( pe, section->hdr.PointerToRawData,
+                            SEEK_SET ) != 0 ) {
+                       fprintf ( stderr, "Could not seek to %lx: %s\n",
+                                 section->hdr.PointerToRawData,
+                                 strerror ( errno ) );
+                       exit ( 1 );
+               }
+               if ( section->hdr.SizeOfRawData &&
+                    ( fwrite ( section->contents, section->hdr.SizeOfRawData,
+                               1, pe ) != 1 ) ) {
+                       fprintf ( stderr, "Could not write section %.8s: %s\n",
+                                 section->hdr.Name, strerror ( errno ) );
+                       exit ( 1 );
+               }
+       }
+}
+
+/**
+ * Convert ELF to PE
+ *
+ * @v elf_name         ELF file name
+ * @v pe_name          PE file name
+ */
+static void elf2pe ( const char *elf_name, const char *pe_name ) {
+       bfd *bfd;
+       asymbol **symtab;
+       asection *section;
+       arelent **reltab;
+       arelent **rel;
+       struct pe_relocs *pe_reltab = NULL;
+       struct pe_section *pe_sections = NULL;
+       struct pe_section **next_pe_section = &pe_sections;
+       struct pe_header pe_header;
+       FILE *pe;
+
+       /* Open the file */
+       bfd = open_input_bfd ( elf_name );
+       symtab = read_symtab ( bfd );
+
+       /* Initialise the PE header */
+       memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
+       pe_header.nt.OptionalHeader.AddressOfEntryPoint =
+               bfd_get_start_address ( bfd );
+
+       /* For each input section, build an output section and create
+        * the appropriate relocation records
+        */
+       for ( section = bfd->sections ; section ; section = section->next ) {
+               /* Discard non-allocatable sections */
+               if ( ! ( bfd_get_section_flags ( bfd, section ) & SEC_ALLOC ) )
+                       continue;
+               /* Create output section */
+               *(next_pe_section) = process_section ( bfd, &pe_header,
+                                                      section );
+               next_pe_section = &(*next_pe_section)->next;
+               /* Add relocations from this section */
+               reltab = read_reltab ( bfd, symtab, section );
+               for ( rel = reltab ; *rel ; rel++ )
+                       process_reloc ( bfd, section, *rel, &pe_reltab );
+               free ( reltab );
+       }
+
+       /* Create the .reloc section */
+       *(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
+       next_pe_section = &(*next_pe_section)->next;
+
+       /* Create the .reloc section */
+       *(next_pe_section) = create_debug_section ( &pe_header,
+                                                   basename ( pe_name ) );
+       next_pe_section = &(*next_pe_section)->next;
+
+       /* Write out PE file */
+       pe = fopen ( pe_name, "w" );
+       if ( ! pe ) {
+               fprintf ( stderr, "Could not open %s for writing: %s\n",
+                         pe_name, strerror ( errno ) );
+               exit ( 1 );
+       }
+       write_pe_file ( &pe_header, pe_sections, pe );
+       fclose ( pe );
+
+       /* Close BFD file */
+       bfd_close ( bfd );
+}
+
+int main ( int argc, char **argv ) {
+
+       /* Initialise libbfd */
+       bfd_init();
+
+       elf2pe ( argv[1], argv[2] );
+
+       return 0;
+}