[hatari-devel] Symbol loading for upcoming MINT+ELF program format |
[ Thread Index | Date Index | More lists.tuxfamily.org/hatari-devel Archives ]
Hi,
although not yet officially released, i think the newly defined format is mature enough to deserve support in Hatari. Attached is a patch to do so.
Note that currently the p_res1 member of the GEMDOS header contains the value "ELF(". "(" here happens to be the decimal value 40, which is the offset to the ELF header. That byte is masked out for the tests, should there be any future extensions.
A few definitions might by duplicate (also used in src/lilo.c), but i did not bother to move them out there.
diff --git a/src/debug/symbols-common.c b/src/debug/symbols-common.c index b5b8959c..d5aaa1a6 100644 --- a/src/debug/symbols-common.c +++ b/src/debug/symbols-common.c @@ -51,8 +51,9 @@ typedef struct { } ignore_counts_t; /* Magic used to denote different symbol table formats */ -#define SYMBOL_FORMAT_GNU 0x474E555f /* "MiNT" */ -#define SYMBOL_FORMAT_MINT 0x4D694E54 /* "GNU_" */ +#define SYMBOL_FORMAT_GNU 0x474E555f /* "GNU_" */ +#define SYMBOL_FORMAT_MINT 0x4D694E54 /* "MiNT" */ +#define SYMBOL_FORMAT_ELF 0x454c4600 /* "ELF" */ #define SYMBOL_FORMAT_DRI 0x0 /* Magic identifying Atari programs */ @@ -883,6 +884,290 @@ static symbol_list_t* symbols_load_gnu(FILE *fp, const prg_section_t *sections, return list; } +/** + * Load symbols of given type and the symbol address addresses from + * ELF format symbol table, and add given offsets to the addresses. + * Return symbols list or NULL for failure. + */ + +#define SIZEOF_ELF32_SYM 16 + +#define ELF_ST_BIND(val) (((unsigned int)(val)) >> 4) +#define ELF_ST_TYPE(val) ((val) & 0xF) +#define ELF_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xF)) + +/* sh_type */ +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program specific (private) data */ +#define SHT_SYMTAB 2 /* Link editing symbol table */ +#define SHT_STRTAB 3 /* A string table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* A symbol hash table */ +#define SHT_DYNAMIC 6 /* Information for dynamic linking */ +#define SHT_NOTE 7 /* Information that marks file */ +#define SHT_NOBITS 8 /* Section occupies no space in file */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved, unspecified semantics */ +#define SHT_DYNSYM 11 /* Dynamic linking 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 indices */ + +/* ST_BIND */ +#define STB_LOCAL 0 /* Symbol not visible outside obj */ +#define STB_GLOBAL 1 /* Symbol visible outside obj */ +#define STB_WEAK 2 /* Like globals, lower precedence */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_GNU_UNIQUE 10 /* Symbol is unique in namespace */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Application-specific semantics */ +#define STB_HIPROC 15 /* Application-specific semantics */ + +/* ST_TYPE */ +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol gives a file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_GNU_IFUNC 10 /* Symbol is an indirect code object */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Application-specific semantics */ +#define STT_HIPROC 15 /* Application-specific semantics */ + +/* special sections indexes */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ +#define SHN_LOPROC 0xFF00 /* Begin range of appl-specific */ +#define SHN_HIPROC 0xFF1F /* End range of appl-specific */ +#define SHN_LOOS 0xFF20 /* OS specific semantics, lo */ +#define SHN_HIOS 0xFF3F /* OS specific semantics, hi */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is in common */ +#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ +#define SHN_HIRESERVE 0xFFFF /* End range of reserved indices */ + +/* Values for section header, sh_flags field. */ +#define SHF_WRITE ((uint32_t)1 << 0) /* Writable data during execution */ +#define SHF_ALLOC ((uint32_t)1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR ((uint32_t)1 << 2) /* Executable machine instructions */ +#define SHF_MERGE ((uint32_t)1 << 4) /* Might be merged */ +#define SHF_STRINGS ((uint32_t)1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK ((uint32_t)1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER ((uint32_t)1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING ((uint32_t)1 << 8) /* Non-standard OS specific handling + required */ +#define SHF_GROUP ((uint32_t)1 << 9) /* Section is member of a group. */ +#define SHF_TLS ((uint32_t)1 << 10) /* Section hold thread-local data. */ +#define SHF_COMPRESSED ((uint32_t)1 << 11) /* Section with compressed data */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ +#define SHF_ORDERED ((uint32_t)1 << 30) /* Special ordering requirement + (Solaris). */ +#define SHF_EXCLUDE ((uint32_t)1 << 31) /* Section is excluded unless + referenced or allocated (Solaris).*/ + +struct elf_shdr { + uint32_t sh_name; /* Section name */ + uint32_t sh_type; /* Type of section */ + uint32_t sh_flags; /* Miscellaneous section attributes */ + uint32_t sh_addr; /* Section virtual addr at execution */ + uint32_t sh_offset; /* Section file offset */ + uint32_t sh_size; /* Size of section in bytes */ + uint32_t sh_link; /* Index of another section */ + uint32_t sh_info; /* Additional section information */ + uint32_t sh_addralign; /* Section alignment */ + uint32_t sh_entsize; /* Entry size if section holds table */ +}; + +static symbol_list_t* symbols_load_elf(FILE *fp, const prg_section_t *sections, uint32_t tablesize, uint32_t stroff, uint32_t strsize, const symbol_opts_t *opts, struct elf_shdr *headers, unsigned short e_shnum) +{ + size_t slots = tablesize / SIZEOF_ELF32_SYM; + size_t i; + size_t strx; + unsigned char *p; + char *name; + symbol_t *sym; + symtype_t symtype; + uint32_t address; + uint32_t nread; + symbol_list_t *list; + uint32_t st_size; + unsigned char st_info; + unsigned char st_other; + unsigned short st_shndx; + static char dummy[] = "<invalid>"; + int count; + ignore_counts_t ignore; + const prg_section_t *section; + unsigned char *symtab; + struct elf_shdr *shdr; + + if (!(list = symbol_list_alloc(slots))) { + return NULL; + } + + list->strtab = (char *)malloc(strsize); + symtab = (unsigned char *)malloc(tablesize); + + if (list->strtab == NULL || symtab == NULL) + { + perror(""); + free(symtab); + symbol_list_free(list); + return NULL; + } + + nread = fread(symtab, tablesize, 1, fp); + if (nread != 1) + { + perror("ERROR: reading symbols failed"); + free(symtab); + symbol_list_free(list); + return NULL; + } + + if (fseek(fp, stroff, SEEK_SET) < 0) { + perror("ERROR: seeking to string table failed"); + free(symtab); + symbol_list_free(list); + return NULL; + } + + nread = fread(list->strtab, strsize, 1, fp); + if (nread != 1) + { + perror("ERROR: reading symbol names failed"); + free(symtab); + symbol_list_free(list); + return NULL; + } + + p = (unsigned char *)symtab; + sym = list->names; + + memset(&ignore, 0, sizeof(ignore)); + count = 0; + + for (i = 0; i < slots; i++) + { + strx = get_be32(p); + p += 4; + address = get_be32(p); + p += 4; + st_size = get_be32(p); + p += 4; + st_info = *p++; + st_other = *p++; + st_shndx = be_swap16(*(uint16_t*)p); + p += 2; + name = dummy; + if (!strx) { + ignore.invalid++; + continue; + } + if (strx >= strsize) { + fprintf(stderr, "symbol name index %x out of range\n", (unsigned int)strx); + ignore.invalid++; + continue; + } + name = list->strtab + strx; + + section = NULL; + switch (st_info) + { + case ELF_ST_INFO(STB_LOCAL, STT_OBJECT): + case ELF_ST_INFO(STB_GLOBAL, STT_OBJECT): + case ELF_ST_INFO(STB_WEAK, STT_OBJECT): + case ELF_ST_INFO(STB_LOCAL, STT_FUNC): + case ELF_ST_INFO(STB_GLOBAL, STT_FUNC): + case ELF_ST_INFO(STB_WEAK, STT_FUNC): + case ELF_ST_INFO(STB_LOCAL, STT_COMMON): + case ELF_ST_INFO(STB_GLOBAL, STT_COMMON): + case ELF_ST_INFO(STB_WEAK, STT_COMMON): + case ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE): + case ELF_ST_INFO(STB_LOCAL, STT_NOTYPE): + case ELF_ST_INFO(STB_WEAK, STT_NOTYPE): + switch (st_shndx) + { + case SHN_ABS: + symtype = SYMTYPE_ABS; + break; + case SHN_UNDEF: + /* shouldn't happen here */ + ignore.undefined++; + continue; + case SHN_COMMON: + fprintf(stderr, "WARNING: ignoring common symbol '%s' in slot %u.\n", name, (unsigned int)i); + ignore.debug++; + continue; + default: + if (st_shndx >= e_shnum) + { + ignore.invalid++; + continue; + } else + { + shdr = &headers[st_shndx]; + if (shdr->sh_type == SHT_NOBITS) + { + symtype = ELF_ST_BIND(st_info) == STB_WEAK ? SYMTYPE_WEAK : SYMTYPE_BSS; + section = &(sections[2]); + } else if (shdr->sh_flags & SHF_EXECINSTR) + { + symtype = ELF_ST_BIND(st_info) == STB_WEAK ? SYMTYPE_WEAK : SYMTYPE_TEXT; + section = &(sections[0]); + } else + { + symtype = ELF_ST_BIND(st_info) == STB_WEAK ? SYMTYPE_WEAK : SYMTYPE_DATA; + section = &(sections[1]); + } + } + } + break; + + case ELF_ST_INFO(STB_LOCAL, STT_FILE): /* filename symbol */ + ignore.debug++; + continue; + + case ELF_ST_INFO(STB_LOCAL, STT_SECTION): /* section name */ + continue; + + default: + fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %u of unknown type 0x%x.\n", name, (unsigned int)i, st_info); + ignore.invalid++; + continue; + } + + if (section) { + address += sections[0].offset; /* all GNU symbol addresses are TEXT relative */ + if (address > section->end) { + fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %u with invalid offset 0x%x (>= 0x%x).\n", + name, symbol_char(symtype), (unsigned int)i, address, section->end); + ignore.invalid++; + continue; + } + } + sym->address = address; + sym->type = symtype; + sym->name = name; + sym++; + count++; + (void)st_other; + (void)st_size; + } + list->symbols = slots; + list->namecount = count; + + free(symtab); + + show_ignored(&ignore); + return list; +} /* ---------- program info + symbols loading ------------- */ @@ -912,6 +1197,9 @@ static bool symbols_print_prg_info(uint32_t tabletype, uint32_t prgflags, uint16 case SYMBOL_FORMAT_GNU: /* "GNU_" */ info = "GCC/MiNT executable, a.out symbol table"; break; + case SYMBOL_FORMAT_ELF: + info = "GCC/MiNT executable, elf symbol table"; + break; case SYMBOL_FORMAT_DRI: info = "TOS executable, DRI / GST symbol table"; break; @@ -959,6 +1247,8 @@ static symbol_list_t* symbols_load_binary(FILE *fp, const symbol_opts_t *opts, uint32_t symoff = 0; uint32_t stroff = 0; uint32_t strsize = 0; + struct elf_shdr *headers = 0; + uint16_t e_shnum = 0; /* get TEXT, DATA & BSS section sizes */ fseek(fp, 2, SEEK_SET); @@ -1055,11 +1345,116 @@ static symbol_list_t* symbols_load_binary(FILE *fp, const symbol_opts_t *opts, a_drsize; } } + else if ((tabletype & 0xffffff00) == SYMBOL_FORMAT_ELF && (tabletype & 0xff) >= 40) { /* new MiNT+ELF */ + uint32_t magic; + uint8_t e_ident[12]; + uint32_t dummy; + uint32_t e_phoff, e_shoff; + uint16_t e_type, e_machine, e_phnum, e_shentsize, e_shstrndx; + uint16_t i; + uint16_t strtabidx; + + /* skip to ELF program header */ + fseek(fp, (tabletype & 0xff) - 28, SEEK_CUR); + tabletype = SYMBOL_FORMAT_ELF; + /* symbol table size in GEMDOS header includes space of ELF headers, ignore it */ + tablesize = 0; + + reads = fread(&magic, sizeof(magic), 1, fp); + magic = be_swap32(magic); + /* read rest of e_ident */ + reads += fread(e_ident, sizeof(e_ident), 1, fp); + reads += fread(&e_type, sizeof(e_type), 1, fp); + e_type = be_swap16(e_type); + reads += fread(&e_machine, sizeof(e_machine), 1, fp); + e_machine = be_swap16(e_machine); + if (reads == 4 && + magic == 0x7f454c46 && /* '\177ELF' */ + e_ident[0] == 1 && /* ELFCLASS32 */ + e_ident[1] == 2 && /* ELFDATA2MSB */ + e_type == 2 && /* ET_EXEC */ + e_machine == 4) /* EM_68K */ + { + reads = fread(&dummy, sizeof(dummy), 1, fp); + reads += fread(&dummy, sizeof(dummy), 1, fp); + reads += fread(&e_phoff, sizeof(e_phoff), 1, fp); + e_phoff = be_swap32(e_phoff); + reads += fread(&e_shoff, sizeof(e_shoff), 1, fp); + e_shoff = be_swap32(e_shoff); + reads += fread(&dummy, sizeof(dummy), 1, fp); + reads += fread(&dummy, sizeof(dummy), 1, fp); + reads += fread(&e_phnum, sizeof(e_phnum), 1, fp); + e_phnum = be_swap16(e_phnum); + reads += fread(&e_shentsize, sizeof(e_shentsize), 1, fp); + reads += fread(&e_shnum, sizeof(e_shnum), 1, fp); + e_shnum = be_swap16(e_shnum); + reads += fread(&e_shstrndx, sizeof(e_shstrndx), 1, fp); + e_shstrndx = be_swap16(e_shstrndx); + fseek(fp, e_shoff, SEEK_SET); + strtabidx = -1; + headers = (struct elf_shdr *)malloc(sizeof(*headers) * e_shnum); + if (headers == NULL) + { + perror(""); + return NULL; + } + for (i = 0; i < e_shnum; i++) + { + struct elf_shdr *shdr = &headers[i]; + + reads = fread(&shdr->sh_name, 1, sizeof(shdr->sh_name), fp); + shdr->sh_name = be_swap32(shdr->sh_name); + reads += fread(&shdr->sh_type, 1, sizeof(shdr->sh_type), fp); + shdr->sh_type = be_swap32(shdr->sh_type); + reads += fread(&shdr->sh_flags, 1, sizeof(shdr->sh_flags), fp); + shdr->sh_flags = be_swap32(shdr->sh_flags); + reads += fread(&shdr->sh_addr, 1, sizeof(shdr->sh_addr), fp); + shdr->sh_addr = be_swap32(shdr->sh_addr); + reads += fread(&shdr->sh_offset, 1, sizeof(shdr->sh_offset), fp); + shdr->sh_offset = be_swap32(shdr->sh_offset); + reads += fread(&shdr->sh_size, 1, sizeof(shdr->sh_size), fp); + shdr->sh_size = be_swap32(shdr->sh_size); + reads += fread(&shdr->sh_link, 1, sizeof(shdr->sh_link), fp); + shdr->sh_link = be_swap32(shdr->sh_link); + reads += fread(&shdr->sh_info, 1, sizeof(shdr->sh_info), fp); + shdr->sh_info = be_swap32(shdr->sh_info); + reads += fread(&shdr->sh_addralign, 1, sizeof(shdr->sh_addralign), fp); + shdr->sh_addralign = be_swap32(shdr->sh_addralign); + reads += fread(&shdr->sh_entsize, 1, sizeof(shdr->sh_entsize), fp); + shdr->sh_entsize = be_swap32(shdr->sh_entsize); + if (shdr->sh_type == SHT_SYMTAB) + { + symoff = shdr->sh_offset; + tablesize = shdr->sh_size; + strtabidx = shdr->sh_link; + } + } + if (strtabidx == -1 || headers[strtabidx].sh_type != SHT_STRTAB) + { + tabletype = 0; + } else + { + stroff = headers[strtabidx].sh_offset; + strsize = headers[strtabidx].sh_size; + } + } else + { + tabletype = 0; + } + if (tabletype == 0) + { + fprintf(stderr, "ERROR: reading ELF header failed!\n"); + free(headers); + return NULL; + } + } if (!symbols_print_prg_info(tabletype, prgflags, relocflag)) { + free(headers); return NULL; } if (!tablesize) { fprintf(stderr, "ERROR: symbol table missing from the program!\n"); + free(headers); return NULL; } fprintf(stderr, "Program section sizes:\n text: 0x%x, data: 0x%x, bss: 0x%x, symtab: 0x%x\n", @@ -1070,6 +1465,7 @@ static symbol_list_t* symbols_load_binary(FILE *fp, const symbol_opts_t *opts, sections[2].end = bsslen; /* add suitable offsets to section beginnings & ends, and validate them */ if (!update_sections(sections)) { + free(headers); return NULL; } @@ -1082,6 +1478,17 @@ static symbol_list_t* symbols_load_binary(FILE *fp, const symbol_opts_t *opts, } fprintf(stderr, "Trying to load a.out symbol table at offset 0x%x...\n", offset); symbols = symbols_load_gnu(fp, sections, tablesize, stroff, strsize, opts); + } else if (tabletype == SYMBOL_FORMAT_ELF) { + /* go to start of symbol table */ + offset = symoff; + if (fseek(fp, offset, SEEK_SET) < 0) { + perror("ERROR: seeking to symbol table failed"); + free(headers); + return NULL; + } + fprintf(stderr, "Trying to load ELF symbol table at offset 0x%x...\n", offset); + symbols = symbols_load_elf(fp, sections, tablesize, stroff, strsize, opts, headers, e_shnum); + free(headers); } else { /* go to start of symbol table */ offset = 0x1C + textlen + datalen;
Mail converted by MHonArc 2.6.19+ | http://listengine.tuxfamily.org/ |