diff options
-rw-r--r-- | src/Makefile | 3 | ||||
-rw-r--r-- | src/Makefile.housekeeping | 13 | ||||
-rw-r--r-- | src/arch/i386/Makefile.efi | 16 | ||||
-rw-r--r-- | src/arch/i386/prefix/efiprefix.S | 175 | ||||
-rw-r--r-- | src/arch/i386/scripts/efi.lds | 180 | ||||
-rw-r--r-- | src/arch/x86/Makefile | 1 | ||||
-rw-r--r-- | src/arch/x86/prefix/efiprefix.c | 39 | ||||
-rw-r--r-- | src/arch/x86/scripts/efi.lds | 106 | ||||
-rw-r--r-- | src/arch/x86_64/Makefile.efi | 16 | ||||
-rw-r--r-- | src/arch/x86_64/prefix/efiprefix.S | 174 | ||||
-rw-r--r-- | src/arch/x86_64/scripts/efi.lds | 180 | ||||
-rw-r--r-- | src/include/gpxe/efi/efi.h | 2 | ||||
-rw-r--r-- | src/interface/efi/efi_init.c (renamed from src/interface/efi/efi_entry.c) | 10 | ||||
-rw-r--r-- | src/util/.gitignore | 3 | ||||
-rw-r--r-- | src/util/efilink.c | 515 | ||||
-rw-r--r-- | src/util/elf2efi.c | 764 |
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 ( §ion->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; +} |