From 8e95bc13a9431e848134d4d3b227c051ad6fd7e4 Mon Sep 17 00:00:00 2001 From: Robert Pengelly Date: Tue, 19 Aug 2025 06:18:16 +0100 Subject: [PATCH] Add support for 64-bit ELF objects --- elf.h | 51 +++++++++++++++++++-- ranlib.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++--------- stdint.h | 31 +++++++++++++ 3 files changed, 192 insertions(+), 23 deletions(-) create mode 100644 stdint.h diff --git a/elf.h b/elf.h index 7624dbf..d6f95ee 100644 --- a/elf.h +++ b/elf.h @@ -4,7 +4,7 @@ #ifndef _ELF_H #define _ELF_H -struct elf_exec { +struct elf32_exec { unsigned char e_ident[16]; unsigned char e_type[2]; @@ -23,8 +23,27 @@ struct elf_exec { }; -struct elf_shdr { +struct elf64_exec { + unsigned char e_ident[16]; + unsigned char e_type[2]; + unsigned char e_machine[2]; + unsigned char e_version[4]; + unsigned char e_entry[8]; + unsigned char e_phoff[8]; + unsigned char e_shoff[8]; + unsigned char e_flags[4]; + unsigned char e_ehsize[2]; + unsigned char e_phentsize[2]; + unsigned char e_phnum[2]; + unsigned char e_shentsize[2]; + unsigned char e_shnum[2]; + unsigned char e_shstrndx[2]; + +}; + +struct elf32_shdr { + unsigned char sh_name[4]; unsigned char sh_type[4]; unsigned char sh_flags[4]; @@ -38,7 +57,22 @@ struct elf_shdr { }; -struct elf_sym { +struct elf64_shdr { + + unsigned char sh_name[4]; + unsigned char sh_type[4]; + unsigned char sh_flags[8]; + unsigned char sh_addr[8]; + unsigned char sh_offset[8]; + unsigned char sh_size[8]; + unsigned char sh_link[4]; + unsigned char sh_info[4]; + unsigned char sh_addralign[8]; + unsigned char sh_entsize[8]; + +}; + +struct elf32_sym { unsigned char st_name[4]; unsigned char st_value[4]; @@ -49,4 +83,15 @@ struct elf_sym { }; +struct elf64_sym { + + unsigned char st_name[4]; + unsigned char st_info[1]; + unsigned char st_other[1]; + unsigned char st_shndx[2]; + unsigned char st_value[8]; + unsigned char st_size[8]; + +}; + #endif /* _ELF_H */ diff --git a/ranlib.c b/ranlib.c index f2a832b..27f5d88 100644 --- a/ranlib.c +++ b/ranlib.c @@ -3,6 +3,7 @@ *****************************************************************************/ #include #include +#include #include #include #include @@ -15,10 +16,10 @@ #include "lib.h" #include "report.h" -#define GET_INT32(arr) ((long) arr[0] | (((long) arr[1]) << 8) | (((long) arr[2]) << 16) | (((long) arr[3]) << 24)) -#define GET_UINT32(arr) ((unsigned long) arr[0] | (((unsigned long) arr[1]) << 8) | (((unsigned long) arr[2]) << 16) | (((unsigned long) arr[3]) << 24)) +#define GET_INT32(arr) ((int32_t) (arr)[0] | (((int32_t) (arr)[1]) << 8) | (((int32_t) (arr)[2]) << 16) | (((int32_t) (arr)[3]) << 24)) +#define GET_UINT32(arr) ((uint32_t) (arr)[0] | (((uint32_t) (arr)[1]) << 8) | (((uint32_t) (arr)[2]) << 16) | (((uint32_t) (arr)[3]) << 24)) -#define GET_UINT16(arr) ((unsigned long) (arr)[0] | (((unsigned long) (arr)[1]) << 8)) +#define GET_UINT16(arr) ((uint32_t) (arr)[0] | (((uint32_t) (arr)[1]) << 8)) struct strtab { @@ -182,7 +183,7 @@ static void coff_get_symbols (void *object, long offset) { unsigned char offset3 = (unsigned char) sym.Name[6]; unsigned char offset4 = (unsigned char) sym.Name[7]; - long final_offset = (((long) offset1) | (((long) offset2) << 8) | (((long) offset3) << 16) | (((long) offset4) << 24)); + long final_offset = ((uint32_t) offset1 | (((uint32_t) offset2) << 8) | (((uint32_t) offset3) << 16) | (((uint32_t) offset4) << 24)); final_offset += string_table_start; strtab = xmalloc (sizeof (*strtab)); @@ -203,25 +204,25 @@ static void coff_get_symbols (void *object, long offset) { } -#define GET_ELF_UINT16(arr) (endianess ? (((unsigned long) arr[0] << 8) | (((unsigned long) arr[1]))) : ((unsigned long) arr[0] | (((unsigned long) arr[1]) << 8))) +#define GET_ELF_UINT16(arr) (endianess ? (((uint32_t) (arr)[0] << 8) | (((uint32_t) (arr)[1]))) : ((uint32_t) (arr)[0] | (((uint32_t) (arr)[1]) << 8))) -#define GET_ELF_UINT32(arr) (endianess ? (((unsigned long) arr[0] << 24) | (((unsigned long) arr[1]) << 16) | (((unsigned long) arr[2]) << 8) | (((unsigned long) arr[3]))) \ - : ((unsigned long) arr[0] | (((unsigned long) arr[1]) << 8) | (((unsigned long) arr[2]) << 16) | (((unsigned long) arr[3]) << 24))) +#define GET_ELF_UINT32(arr) (endianess ? (((uint32_t) (arr)[0] << 24) | (((uint32_t) (arr)[1]) << 16) | (((uint32_t) (arr)[2]) << 8) | (((uint32_t) (arr)[3]))) \ + : ((uint32_t) (arr)[0] | (((uint32_t) (arr)[1]) << 8) | (((uint32_t) (arr)[2]) << 16) | (((uint32_t) (arr)[3]) << 24))) -static void elf_get_symbols (void *object, long offset, int endianess) { +static void elf32_get_symbols (void *object, long offset, int endianess) { - struct elf_exec *hdr = (struct elf_exec *) object; + struct elf32_exec *hdr = (struct elf32_exec *) object; - unsigned long e_shnum = GET_ELF_UINT16 (hdr->e_shnum); - unsigned long e_shoff = GET_ELF_UINT32 (hdr->e_shoff); - unsigned long e_shentsize = GET_ELF_UINT16 (hdr->e_shentsize); + uint16_t e_shnum = GET_ELF_UINT16 (hdr->e_shnum); + uint32_t e_shoff = GET_ELF_UINT32 (hdr->e_shoff); + uint16_t e_shentsize = GET_ELF_UINT16 (hdr->e_shentsize); - unsigned long sh_link, sh_offset, sh_entsize, sh_size; - unsigned long sym_strtab_size, i, j, st_name; + uint32_t sh_link, sh_offset, sh_entsize, sh_size; + uint32_t sym_strtab_size, i, j, st_name; - struct elf_shdr strtabhdr; - struct elf_shdr shdr; - struct elf_sym elf_symbol; + struct elf32_shdr strtabhdr; + struct elf32_shdr shdr; + struct elf32_sym elf_symbol; struct strtab *strtab; char *sym_strtab; @@ -286,6 +287,88 @@ static void elf_get_symbols (void *object, long offset, int endianess) { } +#define GET_ELF_UINT64(arr) \ + (endianess ? (((uint64_t) (arr)[0]) << 56) | (((uint64_t) (arr)[1]) << 48) | (((uint64_t) (arr)[2]) << 40) | (((uint64_t) (arr)[3]) >> 32) | (((uint64_t) (arr)[4]) << 24) | (((uint64_t) (arr)[5]) << 16) | (((uint64_t) (arr)[6]) << 8) | (((uint64_t) (arr)[7])) \ + : ((uint64_t) (arr)[0]) | (((uint64_t) (arr)[1]) << 8) | (((uint64_t) (arr)[2]) << 16) | (((uint64_t) (arr)[3]) << 24) | (((uint64_t) (arr)[4]) << 32) | (((uint64_t) (arr)[5]) << 40) | (((uint64_t) (arr)[6]) << 48) | (((uint64_t) (arr)[7]) << 56)) + +static void elf64_get_symbols (void *object, long offset, int endianess) { + + struct elf64_exec *hdr = (struct elf64_exec *) object; + + uint16_t e_shnum = GET_ELF_UINT16 (hdr->e_shnum); + uint64_t e_shoff = GET_ELF_UINT64 (hdr->e_shoff); + uint16_t e_shentsize = GET_ELF_UINT16 (hdr->e_shentsize); + + uint64_t sh_link, sh_offset, sh_entsize, sh_size; + uint64_t sym_strtab_size, i, j, st_name; + + struct elf64_shdr strtabhdr; + struct elf64_shdr shdr; + struct elf64_sym elf_symbol; + + struct strtab *strtab; + char *sym_strtab; + + for (i = 1; i < e_shnum; i++) { + + memcpy (&shdr, (char *) object + e_shoff + i * e_shentsize, sizeof (shdr)); + + if (GET_ELF_UINT32 (shdr.sh_type) != 2) { + continue; + } + + sh_link = GET_ELF_UINT32 (shdr.sh_link); + sh_offset = GET_ELF_UINT64 (shdr.sh_offset); + + if (sh_link == 0 || sh_link >= e_shnum) { + continue; + } + + memcpy (&strtabhdr, (char *) object + e_shoff + sh_link * e_shentsize, sizeof (strtabhdr)); + + if (GET_ELF_UINT32 (strtabhdr.sh_type) != 3) { + continue; + } + + sym_strtab_size = GET_ELF_UINT64 (strtabhdr.sh_size); + sym_strtab = (char *) object + GET_ELF_UINT64 (strtabhdr.sh_offset); + + if ((sh_entsize = GET_ELF_UINT64 (shdr.sh_entsize)) < sizeof (elf_symbol)) { + continue; + } + + sh_size = GET_ELF_UINT64 (shdr.sh_size); + + for (j = 1; j < sh_size / sh_entsize; j++) { + + memcpy (&elf_symbol, (char *) object + sh_offset + j * sh_entsize, sizeof (elf_symbol)); + + if ((st_name = GET_ELF_UINT32 (elf_symbol.st_name)) >= sym_strtab_size) { + continue; + } + + if (GET_ELF_UINT16 (elf_symbol.st_shndx) == 0 || (elf_symbol.st_info[0] >> 4) != 1) { + continue; + } + + if (sym_strtab[st_name] != '\0') { + + strtab = xmalloc (sizeof (*strtab)); + strtab->offset = offset; + + strtab->name = xstrdup (sym_strtab + st_name); + strtab->length = strlen (strtab->name); + + add_strtab (&gstrtab, strtab); + + } + + } + + } + +} + unsigned long array_to_integer (unsigned char *arr, int size) { unsigned long value = 0; @@ -394,6 +477,8 @@ static void hunk_get_symbols (void *object, unsigned long bytes, long offset) { pos = pos + 4 + num_ref; } + + free (symname); } @@ -612,7 +697,15 @@ void ranlib (FILE *arfp) { } else if ((object[0] == 0x4C && object[1] == 0x01) || (object[0] == 0x64 && object[1] == 0x86)) { coff_get_symbols (object, offset + 8); } else if (object[0] == 0x7F && memcmp (object + 1, "ELF", 3) == 0) { - elf_get_symbols (object, offset + 8, object[5] == 2); + + int endianess = (object[5] == 2); + + if (object[4] == 2) { + elf64_get_symbols (object, offset + 8, endianess); + } else { + elf32_get_symbols (object, offset + 8, endianess); + } + } else if (object[0] == 0x80) { char filename[17] = { 0 }; @@ -663,14 +756,14 @@ void ranlib (FILE *arfp) { } - memset (temp, 0x20, 16); + memset (temp, ' ', 16); temp[0] = '0'; len = 1; memcpy (header.name, "/", len); while (len < 16) { - header.name[len++] = 0x20; + header.name[len++] = ' '; } memcpy (header.mtime, temp, 12); diff --git a/stdint.h b/stdint.h new file mode 100644 index 0000000..22fe599 --- /dev/null +++ b/stdint.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * @file stdint.h + *****************************************************************************/ +#ifndef _STDINT_H +#define _STDINT_H + +#include + +typedef signed char int8_t; +typedef unsigned char uint8_t; + +typedef signed short int16_t; +typedef unsigned short uint16_t; + +#if INT_MAX == 32767 +typedef signed long int32_t; +typedef unsigned long uint32_t; +#else +typedef signed int int32_t; +typedef unsigned int uint32_t; +#endif + +#if ULONG_MAX == 4294967295UL && !defined (NO_LONG_LONG) +typedef signed long long int64_t; +typedef signed long long uint64_t; +#else +typedef signed long int64_t; +typedef unsigned long uint64_t; +#endif + +#endif /* _STDINT_H */ -- 2.34.1