diff options
author | Michael Brown <mcb30@ipxe.org> | 2023-04-05 13:29:29 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2023-04-10 16:51:51 +0100 |
commit | 9fb28080d97fac1061660befacfad8caaa2bc522 (patch) | |
tree | 98d57b8bfb4b7621298e310cae09a17c3d009f21 | |
parent | 1e4c3789e95393a1b87a0b2147bed82a87576673 (diff) | |
download | ipxe-9fb28080d97fac1061660befacfad8caaa2bc522.tar.gz |
[efi] Allow elf2efi to be used for hybrid binaries
Hybrid 32-bit BIOS and 64-bit UEFI binaries (such as wimboot) may
include R_X86_64_32 relocation records for the 32-bit BIOS portions.
These should be ignored when generating PE relocation records, since
they apply only to code that cannot be executed within the context of
the 64-bit UEFI binary, and creating a 4-byte relocation record is
invalid in a binary that may be relocated anywhere within the 64-bit
address space (see commit 907cffb "[efi] Disallow R_X86_64_32
relocations").
Add a "--hybrid" option to elf2efi, which will cause R_X86_64_32
relocation records to be silently discarded.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/util/elf2efi.c | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index a68154e4c..61ac0e277 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -231,7 +231,10 @@ static struct pe_header efi_pe_header = { /** Command-line options */ struct options { + /** PE32+ subsystem type */ unsigned int subsystem; + /** Create hybrid BIOS/UEFI binary */ + int hybrid; }; /** @@ -678,10 +681,12 @@ static struct pe_section * process_section ( struct elf_file *elf, * @v nsyms Number of symbol table entries * @v rel Relocation record * @v pe_reltab PE relocation table to fill in + * @v opts Options */ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr, const Elf_Sym *syms, unsigned int nsyms, - const Elf_Rel *rel, struct pe_relocs **pe_reltab ) { + const Elf_Rel *rel, struct pe_relocs **pe_reltab, + struct options *opts ) { unsigned int type = ELF_R_TYPE ( rel->r_info ); unsigned int sym = ELF_R_SYM ( rel->r_info ); unsigned int mrel = ELF_MREL ( elf->ehdr->e_machine, type ); @@ -744,6 +749,15 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr, * loaded. */ break; + case ELF_MREL ( EM_X86_64, R_X86_64_32 ) : + /* Ignore 32-bit relocations in a hybrid + * 32-bit BIOS and 64-bit UEFI binary, + * otherwise fall through to treat as an + * unknown type. + */ + if ( opts->hybrid ) + break; + /* fallthrough */ default: eprintf ( "Unrecognised relocation type %d\n", type ); exit ( 1 ); @@ -758,9 +772,11 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr, * @v shdr ELF section header * @v stride Relocation record size * @v pe_reltab PE relocation table to fill in + * @v opts Options */ static void process_relocs ( struct elf_file *elf, const Elf_Shdr *shdr, - size_t stride, struct pe_relocs **pe_reltab ) { + size_t stride, struct pe_relocs **pe_reltab, + struct options *opts ) { const Elf_Shdr *symtab; const Elf_Sym *syms; const Elf_Rel *rel; @@ -778,7 +794,7 @@ static void process_relocs ( struct elf_file *elf, const Elf_Shdr *shdr, rel = ( elf->data + shdr->sh_offset ); nrels = ( shdr->sh_size / stride ); for ( i = 0 ; i < nrels ; i++ ) { - process_reloc ( elf, shdr, syms, nsyms, rel, pe_reltab ); + process_reloc ( elf, shdr, syms, nsyms, rel, pe_reltab, opts ); rel = ( ( ( const void * ) rel ) + stride ); } } @@ -977,6 +993,7 @@ static void write_pe_file ( struct pe_header *pe_header, * * @v elf_name ELF file name * @v pe_name PE file name + * @v opts Options */ static void elf2pe ( const char *elf_name, const char *pe_name, struct options *opts ) { @@ -1020,13 +1037,13 @@ static void elf2pe ( const char *elf_name, const char *pe_name, /* Process .rel relocations */ process_relocs ( &elf, shdr, sizeof ( Elf_Rel ), - &pe_reltab ); + &pe_reltab, opts ); } else if ( shdr->sh_type == SHT_RELA ) { /* Process .rela relocations */ process_relocs ( &elf, shdr, sizeof ( Elf_Rela ), - &pe_reltab ); + &pe_reltab, opts ); } } @@ -1079,11 +1096,12 @@ static int parse_options ( const int argc, char **argv, int option_index = 0; static struct option long_options[] = { { "subsystem", required_argument, NULL, 's' }, + { "hybrid", no_argument, NULL, 'H' }, { "help", 0, NULL, 'h' }, { 0, 0, 0, 0 } }; - if ( ( c = getopt_long ( argc, argv, "s:h", + if ( ( c = getopt_long ( argc, argv, "s:Hh", long_options, &option_index ) ) == -1 ) { break; @@ -1098,6 +1116,9 @@ static int parse_options ( const int argc, char **argv, exit ( 2 ); } break; + case 'H': + opts->hybrid = 1; + break; case 'h': print_help ( argv[0] ); exit ( 0 ); |