mirror of https://github.com/ipxe/ipxe.git
[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>
pull/963/head
parent
1e4c3789e9
commit
9fb28080d9
|
@ -231,7 +231,10 @@ static struct pe_header efi_pe_header = {
|
||||||
|
|
||||||
/** Command-line options */
|
/** Command-line options */
|
||||||
struct options {
|
struct options {
|
||||||
|
/** PE32+ subsystem type */
|
||||||
unsigned int subsystem;
|
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 nsyms Number of symbol table entries
|
||||||
* @v rel Relocation record
|
* @v rel Relocation record
|
||||||
* @v pe_reltab PE relocation table to fill in
|
* @v pe_reltab PE relocation table to fill in
|
||||||
|
* @v opts Options
|
||||||
*/
|
*/
|
||||||
static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr,
|
static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr,
|
||||||
const Elf_Sym *syms, unsigned int nsyms,
|
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 type = ELF_R_TYPE ( rel->r_info );
|
||||||
unsigned int sym = ELF_R_SYM ( rel->r_info );
|
unsigned int sym = ELF_R_SYM ( rel->r_info );
|
||||||
unsigned int mrel = ELF_MREL ( elf->ehdr->e_machine, type );
|
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.
|
* loaded.
|
||||||
*/
|
*/
|
||||||
break;
|
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:
|
default:
|
||||||
eprintf ( "Unrecognised relocation type %d\n", type );
|
eprintf ( "Unrecognised relocation type %d\n", type );
|
||||||
exit ( 1 );
|
exit ( 1 );
|
||||||
|
@ -758,9 +772,11 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr,
|
||||||
* @v shdr ELF section header
|
* @v shdr ELF section header
|
||||||
* @v stride Relocation record size
|
* @v stride Relocation record size
|
||||||
* @v pe_reltab PE relocation table to fill in
|
* @v pe_reltab PE relocation table to fill in
|
||||||
|
* @v opts Options
|
||||||
*/
|
*/
|
||||||
static void process_relocs ( struct elf_file *elf, const Elf_Shdr *shdr,
|
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_Shdr *symtab;
|
||||||
const Elf_Sym *syms;
|
const Elf_Sym *syms;
|
||||||
const Elf_Rel *rel;
|
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 );
|
rel = ( elf->data + shdr->sh_offset );
|
||||||
nrels = ( shdr->sh_size / stride );
|
nrels = ( shdr->sh_size / stride );
|
||||||
for ( i = 0 ; i < nrels ; i++ ) {
|
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 );
|
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 elf_name ELF file name
|
||||||
* @v pe_name PE file name
|
* @v pe_name PE file name
|
||||||
|
* @v opts Options
|
||||||
*/
|
*/
|
||||||
static void elf2pe ( const char *elf_name, const char *pe_name,
|
static void elf2pe ( const char *elf_name, const char *pe_name,
|
||||||
struct options *opts ) {
|
struct options *opts ) {
|
||||||
|
@ -1020,13 +1037,13 @@ static void elf2pe ( const char *elf_name, const char *pe_name,
|
||||||
|
|
||||||
/* Process .rel relocations */
|
/* Process .rel relocations */
|
||||||
process_relocs ( &elf, shdr, sizeof ( Elf_Rel ),
|
process_relocs ( &elf, shdr, sizeof ( Elf_Rel ),
|
||||||
&pe_reltab );
|
&pe_reltab, opts );
|
||||||
|
|
||||||
} else if ( shdr->sh_type == SHT_RELA ) {
|
} else if ( shdr->sh_type == SHT_RELA ) {
|
||||||
|
|
||||||
/* Process .rela relocations */
|
/* Process .rela relocations */
|
||||||
process_relocs ( &elf, shdr, sizeof ( Elf_Rela ),
|
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;
|
int option_index = 0;
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{ "subsystem", required_argument, NULL, 's' },
|
{ "subsystem", required_argument, NULL, 's' },
|
||||||
|
{ "hybrid", no_argument, NULL, 'H' },
|
||||||
{ "help", 0, NULL, 'h' },
|
{ "help", 0, NULL, 'h' },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( ( c = getopt_long ( argc, argv, "s:h",
|
if ( ( c = getopt_long ( argc, argv, "s:Hh",
|
||||||
long_options,
|
long_options,
|
||||||
&option_index ) ) == -1 ) {
|
&option_index ) ) == -1 ) {
|
||||||
break;
|
break;
|
||||||
|
@ -1098,6 +1116,9 @@ static int parse_options ( const int argc, char **argv,
|
||||||
exit ( 2 );
|
exit ( 2 );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'H':
|
||||||
|
opts->hybrid = 1;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
print_help ( argv[0] );
|
print_help ( argv[0] );
|
||||||
exit ( 0 );
|
exit ( 0 );
|
||||||
|
|
Loading…
Reference in New Issue