summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Makefile3
-rw-r--r--src/Makefile.housekeeping13
-rw-r--r--src/arch/i386/Makefile.efi16
-rw-r--r--src/arch/i386/prefix/efiprefix.S175
-rw-r--r--src/arch/i386/scripts/efi.lds180
-rw-r--r--src/arch/x86/Makefile1
-rw-r--r--src/arch/x86/prefix/efiprefix.c39
-rw-r--r--src/arch/x86/scripts/efi.lds106
-rw-r--r--src/arch/x86_64/Makefile.efi16
-rw-r--r--src/arch/x86_64/prefix/efiprefix.S174
-rw-r--r--src/arch/x86_64/scripts/efi.lds180
-rw-r--r--src/include/gpxe/efi/efi.h2
-rw-r--r--src/interface/efi/efi_init.c (renamed from src/interface/efi/efi_entry.c)10
-rw-r--r--src/util/.gitignore3
-rw-r--r--src/util/efilink.c515
-rw-r--r--src/util/elf2efi.c764
16 files changed, 939 insertions, 1258 deletions
diff --git a/src/Makefile b/src/Makefile
index 67e36a20..015fcc42 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -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
###############################################################################
diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping
index 39771e36..2a1a1a24 100644
--- a/src/Makefile.housekeeping
+++ b/src/Makefile.housekeeping
@@ -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)
###############################################################################
#
diff --git a/src/arch/i386/Makefile.efi b/src/arch/i386/Makefile.efi
index fec7a407..c75338c9 100644
--- a/src/arch/i386/Makefile.efi
+++ b/src/arch/i386/Makefile.efi
@@ -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
index c4cf68e4..00000000
--- a/src/arch/i386/prefix/efiprefix.S
+++ /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
index b6255a68..00000000
--- a/src/arch/i386/scripts/efi.lds
+++ /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 );
-}
diff --git a/src/arch/x86/Makefile b/src/arch/x86/Makefile
index 9ac75b45..a7c4bc0e 100644
--- a/src/arch/x86/Makefile
+++ b/src/arch/x86/Makefile
@@ -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
index 00000000..b05b744d
--- /dev/null
+++ b/src/arch/x86/prefix/efiprefix.c
@@ -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
index 00000000..bfe81739
--- /dev/null
+++ b/src/arch/x86/scripts/efi.lds
@@ -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.*)
+ }
+}
diff --git a/src/arch/x86_64/Makefile.efi b/src/arch/x86_64/Makefile.efi
index 9b9b373f..928f5e92 100644
--- a/src/arch/x86_64/Makefile.efi
+++ b/src/arch/x86_64/Makefile.efi
@@ -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
index a3b503b8..00000000
--- a/src/arch/x86_64/prefix/efiprefix.S
+++ /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
index 833905c9..00000000
--- a/src/arch/x86_64/scripts/efi.lds
+++ /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 );
-}
diff --git a/src/include/gpxe/efi/efi.h b/src/include/gpxe/efi/efi.h
index b46d5ca5..2f995141 100644
--- a/src/include/gpxe/efi/efi.h
+++ b/src/include/gpxe/efi/efi.h
@@ -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 */
diff --git a/src/interface/efi/efi_entry.c b/src/interface/efi/efi_init.c
index 7b670f8e..6e54cf7e 100644
--- a/src/interface/efi/efi_entry.c
+++ b/src/interface/efi/efi_init.c
@@ -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;
}
diff --git a/src/util/.gitignore b/src/util/.gitignore
index 7f9d7557..07bfc5d4 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -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
index 17b99d29..00000000
--- a/src/util/efilink.c
+++ /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
index 00000000..0c65a440
--- /dev/null
+++ b/src/util/elf2efi.c
@@ -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;
+}