[arm] Add support for 32-bit ARM

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2015-10-19 20:01:19 +01:00
parent 49a5bcfba6
commit 1a16f67a28
43 changed files with 1879 additions and 49 deletions

View File

@@ -70,20 +70,14 @@
#endif
#define EFI_FILE_ALIGN 0x20
#define ELF_MREL( mach, type ) ( (mach) | ( (type) << 16 ) )
struct elf_machine {
unsigned int pe_machine;
unsigned int r_none;
unsigned int r_abs;
unsigned int r_pcrel;
};
#define EFI_FILE_ALIGN 0x20
struct elf_file {
void *data;
size_t len;
const Elf_Ehdr *ehdr;
struct elf_machine *machine;
};
struct pe_section {
@@ -136,20 +130,6 @@ static struct pe_header efi_pe_header = {
},
};
static struct elf_machine machine_i386 = {
.pe_machine = EFI_IMAGE_MACHINE_IA32,
.r_none = R_386_NONE,
.r_abs = R_386_32,
.r_pcrel = R_386_PC32,
};
static struct elf_machine machine_x86_64 = {
.pe_machine = EFI_IMAGE_MACHINE_X64,
.r_none = R_X86_64_NONE,
.r_abs = R_X86_64_64,
.r_pcrel = R_X86_64_PC32,
};
/** Command-line options */
struct options {
unsigned int subsystem;
@@ -355,19 +335,6 @@ static void read_elf_file ( const char *name, struct elf_file *elf ) {
exit ( 1 );
}
}
/* Identify architecture */
switch ( ehdr->e_machine ) {
case EM_386:
elf->machine = &machine_i386;
break;
case EM_X86_64:
elf->machine = &machine_x86_64;
break;
default:
eprintf ( "Unknown ELF architecture %d\n", ehdr->e_machine );
exit ( 1 );
}
}
/**
@@ -415,6 +382,36 @@ static const char * elf_string ( struct elf_file *elf, unsigned int section,
return string;
}
/**
* Set machine architecture
*
* @v elf ELF file
* @v pe_header PE file header
*/
static void set_machine ( struct elf_file *elf, struct pe_header *pe_header ) {
const Elf_Ehdr *ehdr = elf->ehdr;
uint16_t machine;
/* Identify machine architecture */
switch ( ehdr->e_machine ) {
case EM_386:
machine = EFI_IMAGE_MACHINE_IA32;
break;
case EM_X86_64:
machine = EFI_IMAGE_MACHINE_X64;
break;
case EM_ARM:
machine = EFI_IMAGE_MACHINE_ARMTHUMB_MIXED;
break;
default:
eprintf ( "Unknown ELF architecture %d\n", ehdr->e_machine );
exit ( 1 );
}
/* Set machine architecture */
pe_header->nt.FileHeader.Machine = machine;
}
/**
* Process section
*
@@ -568,6 +565,7 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr,
const Elf_Rel *rel, struct pe_relocs **pe_reltab ) {
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 );
size_t offset = ( shdr->sh_addr + rel->r_offset );
/* Look up symbol and process relocation */
@@ -579,18 +577,36 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr,
/* Skip absolute symbols; the symbol value won't
* change when the object is loaded.
*/
} else if ( type == elf->machine->r_none ) {
/* Ignore dummy relocations used by REQUIRE_SYMBOL() */
} else if ( type == elf->machine->r_abs ) {
/* Generate an 8-byte or 4-byte PE relocation */
generate_pe_reloc ( pe_reltab, offset, sizeof ( Elf_Addr ) );
} else if ( type == elf->machine->r_pcrel ) {
/* Skip PC-relative relocations; all relative offsets
* remain unaltered when the object is loaded.
*/
} else {
eprintf ( "Unrecognised relocation type %d\n", type );
exit ( 1 );
switch ( mrel ) {
case ELF_MREL ( EM_386, R_386_NONE ) :
case ELF_MREL ( EM_ARM, R_ARM_NONE ) :
case ELF_MREL ( EM_X86_64, R_X86_64_NONE ) :
/* Ignore dummy relocations used by REQUIRE_SYMBOL() */
break;
case ELF_MREL ( EM_386, R_386_32 ) :
case ELF_MREL ( EM_ARM, R_ARM_ABS32 ) :
/* Generate a 4-byte PE relocation */
generate_pe_reloc ( pe_reltab, offset, 4 );
break;
case ELF_MREL ( EM_X86_64, R_X86_64_64 ) :
/* Generate an 8-byte PE relocation */
generate_pe_reloc ( pe_reltab, offset, 8 );
break;
case ELF_MREL ( EM_386, R_386_PC32 ) :
case ELF_MREL ( EM_ARM, R_ARM_CALL ) :
case ELF_MREL ( EM_ARM, R_ARM_THM_PC22 ) :
case ELF_MREL ( EM_ARM, R_ARM_THM_JUMP24 ) :
case ELF_MREL ( EM_X86_64, R_X86_64_PC32 ) :
/* Skip PC-relative relocations; all relative
* offsets remain unaltered when the object is
* loaded.
*/
break;
default:
eprintf ( "Unrecognised relocation type %d\n", type );
exit ( 1 );
}
}
}
@@ -835,7 +851,7 @@ static void elf2pe ( const char *elf_name, const char *pe_name,
/* Initialise the PE header */
memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
pe_header.nt.FileHeader.Machine = elf.machine->pe_machine;
set_machine ( &elf, &pe_header );
pe_header.nt.OptionalHeader.AddressOfEntryPoint = elf.ehdr->e_entry;
pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;