123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809 |
- /*
- * 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 <getopt.h>
- #include <bfd.h>
- #include <ipxe/efi/efi.h>
- #include <ipxe/efi/IndustryStandard/PeImage.h>
- #include <libgen.h>
-
- #define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
-
- #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(EFI_TARGET_IA32)
- EFI_IMAGE_NT_HEADERS32 nt;
- #elif defined(EFI_TARGET_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(EFI_TARGET_IA32)
- .Machine = EFI_IMAGE_MACHINE_IA32,
- #elif defined(EFI_TARGET_X64)
- .Machine = EFI_IMAGE_MACHINE_X64,
- #endif
- .TimeDateStamp = 0x10d1a884,
- .SizeOfOptionalHeader =
- sizeof ( efi_pe_header.nt.OptionalHeader ),
- .Characteristics = ( EFI_IMAGE_FILE_DLL |
- #if defined(EFI_TARGET_IA32)
- EFI_IMAGE_FILE_32BIT_MACHINE |
- #endif
- EFI_IMAGE_FILE_EXECUTABLE_IMAGE ),
- },
- .OptionalHeader = {
- #if defined(EFI_TARGET_IA32)
- .Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC,
- #elif defined(EFI_TARGET_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 ),
- .NumberOfRvaAndSizes =
- EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES,
- },
- },
- };
-
- /** Command-line options */
- struct options {
- unsigned int subsystem;
- };
-
- /**
- * 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 ) {
- eprintf ( "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:
- eprintf ( "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 ) {
- eprintf ( "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 ) ) {
- eprintf ( "%s is not an object file: ", filename );
- bfd_perror ( NULL );
- 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(EFI_TARGET_IA32)
- data_start = pe_header->nt.OptionalHeader.BaseOfData;
- #elif defined(EFI_TARGET_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 ) ) {
- eprintf ( "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(EFI_TARGET_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 {
- eprintf ( "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 ) {
- eprintf ( "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 ) ) {
- eprintf ( "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,
- struct options *opts ) {
- char pe_name_tmp[ strlen ( pe_name ) + 1 ];
- 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;
-
- /* Create a modifiable copy of the PE name */
- memcpy ( pe_name_tmp, pe_name, sizeof ( pe_name_tmp ) );
-
- /* 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 );
- pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;
-
- /* 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_tmp ) );
- next_pe_section = &(*next_pe_section)->next;
-
- /* Write out PE file */
- pe = fopen ( pe_name, "w" );
- if ( ! pe ) {
- eprintf ( "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 );
- }
-
- /**
- * Print help
- *
- * @v program_name Program name
- */
- static void print_help ( const char *program_name ) {
- eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n",
- program_name );
- }
-
- /**
- * Parse command-line options
- *
- * @v argc Argument count
- * @v argv Argument list
- * @v opts Options structure to populate
- */
- static int parse_options ( const int argc, char **argv,
- struct options *opts ) {
- char *end;
- int c;
-
- while (1) {
- int option_index = 0;
- static struct option long_options[] = {
- { "subsystem", required_argument, NULL, 's' },
- { "help", 0, NULL, 'h' },
- { 0, 0, 0, 0 }
- };
-
- if ( ( c = getopt_long ( argc, argv, "s:h",
- long_options,
- &option_index ) ) == -1 ) {
- break;
- }
-
- switch ( c ) {
- case 's':
- opts->subsystem = strtoul ( optarg, &end, 0 );
- if ( *end ) {
- eprintf ( "Invalid subsytem \"%s\"\n",
- optarg );
- exit ( 2 );
- }
- break;
- case 'h':
- print_help ( argv[0] );
- exit ( 0 );
- case '?':
- default:
- exit ( 2 );
- }
- }
- return optind;
- }
-
- int main ( int argc, char **argv ) {
- struct options opts = {
- .subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
- };
- unsigned int infile_index;
- const char *infile;
- const char *outfile;
-
- /* Initialise libbfd */
- bfd_init();
-
- /* Parse command-line arguments */
- infile_index = parse_options ( argc, argv, &opts );
- if ( argc != ( infile_index + 2 ) ) {
- print_help ( argv[0] );
- exit ( 2 );
- }
- infile = argv[infile_index];
- outfile = argv[infile_index + 1];
-
- /* Convert file */
- elf2pe ( infile, outfile, &opts );
-
- return 0;
- }
|