From 314779eb369db746be5373b398111d5b746d67de Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Jan 2009 02:05:51 +0000 Subject: [efi] Use elf2efi utility in place of efilink elf2efi converts a suitable ELF executable (containing relocation information, and with appropriate virtual addresses) into an EFI executable. It is less tightly coupled with the gPXE build process and, in particular, does not require the use of a hand-crafted PE image header in efiprefix.S. elf2efi correctly handles .bss sections, which significantly reduces the size of the gPXE EFI executable. --- src/util/efilink.c | 515 ----------------------------------------------------- 1 file changed, 515 deletions(-) delete mode 100644 src/util/efilink.c (limited to 'src/util/efilink.c') diff --git a/src/util/efilink.c b/src/util/efilink.c deleted file mode 100644 index 17b99d293..000000000 --- a/src/util/efilink.c +++ /dev/null @@ -1,515 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -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; -} -- cgit v1.2.3-55-g7522