From c4cb4cca47091978be0c557bcc0b2fbdca7c3b61 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Sun, 17 Apr 2011 15:49:58 +0000 Subject: sbtools: move internal elf definition to elf.c, implement elf reading sbtoelf: generate a correct section name for undef and string table sections elftosb: static'ify functions, add cmd file to sb file conversion git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29738 a1c6a512-1295-4272-9138-f99709370657 --- utils/sbtools/elf.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 235 insertions(+), 5 deletions(-) (limited to 'utils/sbtools/elf.c') diff --git a/utils/sbtools/elf.c b/utils/sbtools/elf.c index f146bcc111..4b95025d8f 100644 --- a/utils/sbtools/elf.c +++ b/utils/sbtools/elf.c @@ -1,5 +1,135 @@ #include "elf.h" +/** + * Definitions + * taken from elf.h linux header + * based on ELF specification + * based on ARM ELF specification + */ +typedef uint16_t Elf32_Half; + +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint16_t Elf32_Section; + +#define EI_NIDENT 16 + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +}Elf32_Ehdr; + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASS32 1 /* 32-bit objects */ + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ + +#define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ +#define ELFOSABI_ARM 97 /* ARM */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +#define ET_EXEC 2 /* Executable file */ + +#define EM_ARM 40 /* ARM */ + +#define EV_CURRENT 1 /* Current version */ + +#define EF_ARM_HASENTRY 0x00000002 + +#define SHN_UNDEF 0 /* Undefined section */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +}Elf32_Shdr; + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +}Elf32_Phdr; + +#define PT_LOAD 1 /* Loadable program segment */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ + void elf_init(struct elf_params_t *params) { params->has_start_addr = false; @@ -54,7 +184,7 @@ void elf_add_fill_section(struct elf_params_t *params, sec->pattern = pattern; } -void elf_output(struct elf_params_t *params, elf_write_fn_t write, void *user) +void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, void *user) { Elf32_Ehdr ehdr; uint32_t phnum = 0; @@ -64,9 +194,11 @@ void elf_output(struct elf_params_t *params, elf_write_fn_t write, void *user) Elf32_Shdr shdr; memset(&ehdr, 0, EI_NIDENT); - uint32_t bss_strtbl = 0; + uint32_t bss_strtbl = 1; uint32_t text_strtbl = bss_strtbl + strlen(".bss") + 1; - uint32_t strtbl_size = text_strtbl + strlen(".text") + 1; + uint32_t shstrtab_strtbl = text_strtbl + strlen(".text") + 1; + uint32_t strtbl_size = shstrtab_strtbl + strlen(".shstrtab") + 1; + while(sec) { @@ -182,7 +314,7 @@ void elf_output(struct elf_params_t *params, elf_write_fn_t write, void *user) } { - shdr.sh_name = bss_strtbl; + shdr.sh_name = shstrtab_strtbl; shdr.sh_type = SHT_STRTAB; shdr.sh_flags = 0; shdr.sh_addr = 0; @@ -206,7 +338,86 @@ void elf_output(struct elf_params_t *params, elf_write_fn_t write, void *user) sec = sec->next; } - write(user, strtbl_offset + data_offset, ".bss\0.text\0", strtbl_size); + write(user, strtbl_offset + data_offset, "\0.bss\0.text\0.shstrtab\0", strtbl_size); +} + +bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, + elf_printf_fn_t printf, void *user) +{ + #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) + /* read header */ + Elf32_Ehdr ehdr; + if(!read(user, 0, &ehdr, sizeof(ehdr))) + { + printf(user, true, "error reading elf header\n"); + return false; + } + /* basic checks */ + if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 || + ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3) + error_printf("invalid elf header\n"); + if(ehdr.e_ident[EI_CLASS] != ELFCLASS32) + error_printf("invalid elf class: must be a 32-bit object\n"); + if(ehdr.e_ident[EI_DATA] != ELFDATA2LSB) + error_printf("invalid elf data encoding: must be 32-bit lsb\n"); + if(ehdr.e_ident[EI_VERSION] != EV_CURRENT) + error_printf("invalid elf version"); + if(ehdr.e_type != ET_EXEC) + error_printf("invalid elf file: must be an executable file\n"); + if(ehdr.e_machine != EM_ARM) + error_printf("invalid elf file: must target an arm machine\n"); + if(ehdr.e_ehsize != sizeof(ehdr)) + error_printf("invalid elf file: size header mismatch\n"); + if(ehdr.e_phentsize != sizeof(Elf32_Phdr)) + error_printf("invalid elf file: program header size mismatch\n"); + if(ehdr.e_shentsize != sizeof(Elf32_Shdr)) + error_printf("invalid elf file: section header size mismatch\n"); + if(ehdr.e_flags & EF_ARM_HASENTRY) + elf_set_start_addr(params, ehdr.e_entry); + + char *strtab = NULL; + { + Elf32_Shdr shstrtab; + if(read(user, ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize, + &shstrtab, sizeof(shstrtab))) + { + strtab = xmalloc(shstrtab.sh_size); + if(!read(user, shstrtab.sh_offset, strtab, shstrtab.sh_size)) + { + free(strtab); + strtab = NULL; + } + } + } + /* run through sections */ + printf(user, false, "ELF file:\n"); + for(int i = 1; i< ehdr.e_shnum; i++) + { + uint32_t off = ehdr.e_shoff + i * ehdr.e_shentsize; + Elf32_Shdr shdr; + memset(&shdr, 0, sizeof(shdr)); + if(!read(user, off, &shdr, sizeof(shdr))) + error_printf("error reading elf section header"); + + if(shdr.sh_type == SHT_PROGBITS && shdr.sh_flags & SHF_ALLOC) + { + void *data = xmalloc(shdr.sh_size); + if(!read(user, shdr.sh_offset, data, shdr.sh_size)) + error_printf("error read self section data"); + elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data); + + printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]); + } + else if(shdr.sh_type == SHT_NOBITS && shdr.sh_flags & SHF_ALLOC) + { + elf_add_fill_section(params, shdr.sh_addr, shdr.sh_size, 0); + printf(user, false, "create fill segment for %s\n", &strtab[shdr.sh_name]); + } + else + printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); + + } + return true; } bool elf_is_empty(struct elf_params_t *params) @@ -220,6 +431,25 @@ void elf_set_start_addr(struct elf_params_t *params, uint32_t addr) params->start_addr = addr; } +bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr) +{ + if(params->has_start_addr && addr != NULL) + *addr = params->start_addr; + return params->has_start_addr; +} + +int elf_get_nr_sections(struct elf_params_t *params) +{ + int nr = 0; + struct elf_section_t *sec = params->first_section; + while(sec) + { + nr++; + sec = sec->next; + } + return nr; +} + void elf_release(struct elf_params_t *params) { struct elf_section_t *sec, *next_sec; -- cgit v1.2.3