ref: e60e6dc4ded6d0ff578610e39d7a8c8a6f62f3ed
parent: ad3d0dac54f11b7b789b7a8932977ecbadf6380e
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Tue Oct 26 17:30:56 EDT 2021
libmach: Add elf64read() This function loads in memory all the information needed from an elf file.
--- /dev/null
+++ b/include/scc/scc/elf/elfent.h
@@ -1,0 +1,65 @@
+/* Symbol table index */
+#define STN_UNDEF 0 /* undefined */
+
+/* Extract symbol info - st_info */
+#define ELF32_ST_BIND(x) ((x) >> 4)
+#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf)
+#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf))
+
+#define ELF64_ST_BIND(x) ((x) >> 4)
+#define ELF64_ST_TYPE(x) (((unsigned int) x) & 0xf)
+#define ELF64_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf))
+
+/* Symbol Binding - ELF32_ST_BIND - st_info */
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* like global - lower precedence */
+#define STB_NUM 3 /* number of symbol bindings */
+#define STB_LOPROC 13 /* reserved range for processor */
+#define STB_HIPROC 15 /* specific symbol bindings */
+
+/* Symbol type - ELF32_ST_TYPE - st_info */
+#define STT_NOTYPE 0 /* not specified */
+#define STT_OBJECT 1 /* data object */
+#define STT_FUNC 2 /* function */
+#define STT_SECTION 3 /* section */
+#define STT_FILE 4 /* file */
+#define STT_COMMON 5 /* common symbol */
+#define STT_TLS 6 /* thread local storage */
+#define STT_LOPROC 13 /* reserved range for processor */
+#define STT_HIPROC 15 /* specific symbol types */
+
+/* Extract symbol visibility - st_other */
+#define ELF_ST_VISIBILITY(v) ((v) & 0x3)
+#define ELF32_ST_VISIBILITY ELF_ST_VISIBILITY
+#define ELF64_ST_VISIBILITY ELF_ST_VISIBILITY
+
+#define STV_DEFAULT 0 /* Visibility set by binding type */
+#define STV_INTERNAL 1 /* OS specific version of STV_HIDDEN */
+#define STV_HIDDEN 2 /* can only be seen inside own .so */
+#define STV_PROTECTED 3 /* HIDDEN inside, DEFAULT outside */
+
+#define ELFE32SZ 16
+#define ELFE64SZ 24
+
+typedef struct elf32_sym Elf32_Sym;
+typedef struct elf64_sym Elf64_Sym;
+
+/* Symbol Table Entry */
+struct elf32_sym {
+ Elf32_Word st_name; /* name - index into string table */
+ Elf32_Addr st_value; /* symbol value */
+ Elf32_Word st_size; /* symbol size */
+ unsigned char st_info; /* type and binding */
+ unsigned char st_other; /* 0 - no defined meaning */
+ Elf32_Half st_shndx; /* section header index */
+};
+
+struct elf64_sym {
+ Elf64_Word st_name; /* Symbol name index in str table */
+ unsigned char st_info; /* type / binding attrs */
+ unsigned char st_other; /* unused */
+ Elf64_Half st_shndx; /* section index of symbol */
+ Elf64_Addr st_value; /* value of symbol */
+ Elf64_Xword st_size; /* size of symbol */
+};
--- a/include/scc/scc/elf/elfhdr.h
+++ b/include/scc/scc/elf/elfhdr.h
@@ -261,6 +261,9 @@
/* Magic for e_phnum: get real value from sh_info of first section header */
#define PN_XNUM 0xffff
+#define ELFH32SZ 54
+#define ELFH64SZ 64
+
typedef struct elfhdr32 Elf32_Ehdr;
typedef struct elfhdr64 Elf64_Ehdr;
--- /dev/null
+++ b/include/scc/scc/elf/elfphdr.h
@@ -1,0 +1,44 @@
+/* See http://www.sco.com/developers/gabi/latest/contents.html */
+
+/* Segment types - p_type */
+#define PT_NULL 0 /* unused */
+#define PT_LOAD 1 /* loadable segment */
+#define PT_DYNAMIC 2 /* dynamic linking section */
+#define PT_INTERP 3 /* the RTLD */
+#define PT_NOTE 4 /* auxiliary information */
+#define PT_SHLIB 5 /* reserved - purpose undefined */
+#define PT_PHDR 6 /* program header */
+#define PT_TLS 7 /* thread local storage */
+#define PT_LOOS 0x60000000 /* reserved range for OS */
+#define PT_HIOS 0x6fffffff /* specific segment types */
+#define PT_LOPROC 0x70000000 /* reserved range for processor */
+#define PT_HIPROC 0x7fffffff /* specific segment types */
+
+#define ELFP32SZ 32
+#define ELFP64SZ 56
+
+typedef struct elf32_phdr Elf32_Phdr;
+typedef struct elf64_phdr Elf64_Phdr;
+
+/* Program Header */
+struct elf32_phdr {
+ Elf32_Word p_type; /* segment type */
+ Elf32_Off p_offset; /* segment offset */
+ Elf32_Addr p_vaddr; /* virtual address of segment */
+ Elf32_Addr p_paddr; /* physical address - ignored? */
+ Elf32_Word p_filesz; /* number of bytes in file for seg. */
+ Elf32_Word p_memsz; /* number of bytes in mem. for seg. */
+ Elf32_Word p_flags; /* flags */
+ Elf32_Word p_align; /* memory alignment */
+};
+
+struct elf64_phdr {
+ Elf64_Word p_type; /* entry type */
+ Elf64_Word p_flags; /* flags */
+ Elf64_Off p_offset; /* offset */
+ Elf64_Addr p_vaddr; /* virtual address */
+ Elf64_Addr p_paddr; /* physical address */
+ Elf64_Xword p_filesz; /* file size */
+ Elf64_Xword p_memsz; /* memory size */
+ Elf64_Xword p_align; /* memory & file alignment */
+};
--- /dev/null
+++ b/include/scc/scc/elf/elfshdr.h
@@ -1,0 +1,93 @@
+/* Special Section Indexes */
+#define SHN_UNDEF 0 /* undefined */
+#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */
+#define SHN_LOPROC 0xff00 /* reserved range for processor */
+#define SHN_HIPROC 0xff1f /* specific section indexes */
+#define SHN_ABS 0xfff1 /* absolute value */
+#define SHN_COMMON 0xfff2 /* common symbol */
+#define SHN_XINDEX 0xffff /* Escape -- index stored elsewhere. */
+#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */
+
+/* sh_type */
+#define SHT_NULL 0 /* inactive */
+#define SHT_PROGBITS 1 /* program defined information */
+#define SHT_SYMTAB 2 /* symbol table section */
+#define SHT_STRTAB 3 /* string table section */
+#define SHT_RELA 4 /* relocation section with addends*/
+#define SHT_HASH 5 /* symbol hash table section */
+#define SHT_DYNAMIC 6 /* dynamic section */
+#define SHT_NOTE 7 /* note section */
+#define SHT_NOBITS 8 /* no space section */
+#define SHT_REL 9 /* relation section without addends */
+#define SHT_SHLIB 10 /* reserved - purpose unknown */
+#define SHT_DYNSYM 11 /* dynamic symbol table section */
+#define SHT_NUM 12 /* number of section types */
+#define SHT_INIT_ARRAY 14 /* pointers to init functions */
+#define SHT_FINI_ARRAY 15 /* pointers to termination functions */
+#define SHT_PREINIT_ARRAY 16 /* ptrs to funcs called before init */
+#define SHT_GROUP 17 /* defines a section group */
+#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */
+#define SHT_LOOS 0x60000000 /* reserved range for OS specific */
+#define SHT_SUNW_dof 0x6ffffff4 /* used by dtrace */
+#define SHT_GNU_LIBLIST 0x6ffffff7 /* libraries to be prelinked */
+#define SHT_SUNW_move 0x6ffffffa /* inf for partially init'ed symbols */
+#define SHT_SUNW_syminfo 0x6ffffffc /* ad symbol information */
+#define SHT_SUNW_verdef 0x6ffffffd /* symbol versioning inf */
+#define SHT_SUNW_verneed 0x6ffffffe /* symbol versioning req */
+#define SHT_SUNW_versym 0x6fffffff /* symbol versioning table */
+#define SHT_HIOS 0x6fffffff /* section header types */
+#define SHT_LOPROC 0x70000000 /* reserved range for processor */
+#define SHT_HIPROC 0x7fffffff /* specific section header types */
+#define SHT_LOUSER 0x80000000 /* reserved range for application */
+#define SHT_HIUSER 0xffffffff /* specific indexes */
+
+#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table section */
+
+/* Section Attribute Flags - sh_flags */
+#define SHF_WRITE 0x1 /* Writable */
+#define SHF_ALLOC 0x2 /* occupies memory */
+#define SHF_EXECINSTR 0x4 /* executable */
+#define SHF_MERGE 0x10 /* may be merged */
+#define SHF_STRINGS 0x20 /* contains strings */
+#define SHF_INFO_LINK 0x40 /* sh_info holds section index */
+#define SHF_LINK_ORDER 0x80 /* ordering requirements */
+#define SHF_OS_NONCONFORMING 0x100 /* OS-specific processing required */
+#define SHF_GROUP 0x200 /* member of section group */
+#define SHF_TLS 0x400 /* thread local storage */
+#define SHF_COMPRESSED 0x800 /* contains compressed data */
+#define SHF_MASKOS 0x0ff00000 /* OS-specific semantics */
+#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */
+ /* specific section attributes */
+
+#define ELFS32SZ 40
+#define ELFS64SZ 64
+
+typedef struct elf32_shdr Elf32_Shdr;
+typedef struct elf64_shdr Elf64_Shdr;
+
+/* Section Header */
+struct elf32_shdr {
+ Elf32_Word sh_name; /* section name */
+ Elf32_Word sh_type; /* type */
+ Elf32_Word sh_flags; /* flags */
+ Elf32_Addr sh_addr; /* address */
+ Elf32_Off sh_offset; /* file offset */
+ Elf32_Word sh_size; /* section size */
+ Elf32_Word sh_link; /* section header table index link */
+ Elf32_Word sh_info; /* extra information */
+ Elf32_Word sh_addralign; /* address alignment */
+ Elf32_Word sh_entsize; /* section entry size */
+};
+
+struct elf64_shdr {
+ Elf64_Word sh_name; /* section name */
+ Elf64_Word sh_type; /* section type */
+ Elf64_Xword sh_flags; /* section flags */
+ Elf64_Addr sh_addr; /* virtual address */
+ Elf64_Off sh_offset; /* file offset */
+ Elf64_Xword sh_size; /* section size */
+ Elf64_Word sh_link; /* link to another */
+ Elf64_Word sh_info; /* misc info */
+ Elf64_Xword sh_addralign; /* memory alignment */
+ Elf64_Xword sh_entsize; /* table entry size */
+};
--- a/src/libmach/deps.mk
+++ b/src/libmach/deps.mk
@@ -59,6 +59,9 @@
elf64/elf64probe.o: $(INCDIR)/scc/scc/mach.h
elf64/elf64probe.o: elf64/../libmach.h
elf64/elf64probe.o: elf64/elf64.h
+elf64/elf64read.o: $(INCDIR)/scc/scc/mach.h
+elf64/elf64read.o: elf64/../libmach.h
+elf64/elf64read.o: elf64/elf64.h
findsec.o: $(INCDIR)/scc/scc/mach.h
findsec.o: libmach.h
getindex.o: $(INCDIR)/scc/scc/mach.h
--- a/src/libmach/elf64/elf64.c
+++ b/src/libmach/elf64/elf64.c
@@ -5,10 +5,10 @@
#include "../libmach.h"
#include "elf64.h"
-struct objops coff32 = {
+struct objops elf64 = {
.probe = elf64probe,
.new = elf64new,
- .read = NULL,
+ .read = elf64read,
.getidx = NULL,
.setidx = NULL,
.pc2line = NULL,
--- a/src/libmach/elf64/elf64.h
+++ b/src/libmach/elf64/elf64.h
@@ -1,10 +1,38 @@
#include <scc/elf/elftypes.h>
#include <scc/elf/elfhdr.h>
+#include <scc/elf/elfphdr.h>
+#include <scc/elf/elfshdr.h>
+#include <scc/elf/elfent.h>
+#define ELF_ST_BIND ELF64_ST_BIND
+#define ELF_ST_TYPE ELF64_ST_TYPE
#define Elf_Ehdr Elf64_Ehdr
+#define Elf_Phdr Elf64_Phdr
+#define Elf_Shdr Elf64_Shdr
+#define Elf_Sym Elf64_Sym
+#define ELFHSZ ELFH64SZ
+#define ELFPSZ ELFP64SZ
+#define ELFSSZ ELFS64SZ
+#define ELFESZ ELFE64SZ
+
+#define SEC_STRTBL 0
+#define SYM_STRTBL 1
+
+typedef struct elf64 Elf64;
+
struct elf64 {
Elf_Ehdr hdr;
+ Elf_Phdr *phdr;
+ Elf_Shdr *shdr;
+ Elf_Shdr *symtab;
+ Elf_Sym *syms;
+
+ char *strtbl[2];
+ size_t strsiz[2];
+
+ size_t nsec;
+ size_t nsym;
};
extern int elf64new(Obj *);
--- /dev/null
+++ b/src/libmach/elf64/elf64read.c
@@ -1,0 +1,381 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <scc/mach.h>
+
+#include "../libmach.h"
+#include "elf64.h"
+
+static int
+unpack_hdr(int order, unsigned char *buf, Elf_Ehdr *hdr)
+{
+ int n;
+
+ n = unpack(order,
+ buf,
+ "'16sslqqqlssssss",
+ hdr->e_ident,
+ &hdr->e_type,
+ &hdr->e_machine,
+ &hdr->e_version,
+ &hdr->e_entry,
+ &hdr->e_phoff,
+ &hdr->e_shoff,
+ &hdr->e_flags,
+ &hdr->e_ehsize,
+ &hdr->e_phentsize,
+ &hdr->e_phnum,
+ &hdr->e_shentsize,
+ &hdr->e_shnum,
+ &hdr->e_shstrndx);
+
+ assert(n == ELFHSZ);
+
+ return n;
+}
+
+static int
+unpack_phdr(int order, unsigned char *buf, Elf_Phdr *phdr)
+{
+ int n;
+
+ n = unpack(order,
+ buf,
+ "llqqqqqq",
+ &phdr->p_type,
+ &phdr->p_flags,
+ &phdr->p_offset,
+ &phdr->p_vaddr,
+ &phdr->p_paddr,
+ &phdr->p_filesz,
+ &phdr->p_memsz,
+ &phdr->p_align);
+
+ assert(n == ELFPSZ);
+
+ return n;
+}
+
+static int
+unpack_shdr(int order, unsigned char *buf, Elf_Shdr *shdr)
+{
+ int n;
+
+ n = unpack(order,
+ buf,
+ "llqqqqllqq",
+ &shdr->sh_name,
+ &shdr->sh_type,
+ &shdr->sh_flags,
+ &shdr->sh_addr,
+ &shdr->sh_offset,
+ &shdr->sh_size,
+ &shdr->sh_link,
+ &shdr->sh_info,
+ &shdr->sh_addralign,
+ &shdr->sh_entsize);
+
+ assert(n == ELFSSZ);
+
+ return n;
+}
+
+static int
+unpack_sym(int order, unsigned char *buf, Elf_Sym *sym)
+{
+ int n;
+
+ n = unpack(order,
+ buf,
+ "lccsqq",
+ &sym->st_name,
+ &sym->st_info,
+ &sym->st_other,
+ &sym->st_shndx,
+ &sym->st_value,
+ &sym->st_size);
+ assert(n == ELFESZ);
+
+ return n;
+}
+
+static int
+readhdr(Obj *obj, FILE *fp)
+{
+ Elf64 *elf;
+ Elf_Ehdr *hdr;
+ unsigned char buf[ELFHSZ];
+
+ elf = obj->data;
+ hdr = &elf->hdr;
+
+ if (fread(buf, ELFHSZ, 1, fp) != 1)
+ return 0;
+ unpack_hdr(ORDER(obj->type), buf, hdr);
+
+ switch (hdr->e_type) {
+ case ET_REL:
+ case ET_EXEC:
+ case ET_DYN:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int
+readphdr(Obj *obj, FILE *fp)
+{
+ long long i;
+ Elf_Ehdr *hdr;
+ Elf_Phdr *phdr;
+ Elf64 *elf;
+ unsigned char buf[ELFPSZ];
+
+ elf = obj->data;
+ hdr = &elf->hdr;
+
+ if (hdr->e_phoff == 0 || hdr->e_phnum == 0)
+ return 1;
+
+ phdr = calloc(hdr->e_phnum, sizeof(*phdr));
+ if (!phdr)
+ return 0;
+ elf->phdr = phdr;
+
+ if (!objpos(obj, fp, hdr->e_phoff))
+ return 0;
+ for (i = 0; i < hdr->e_phnum; i++) {
+ if (fread(buf, ELFPSZ, 1, fp) != 1)
+ return 0;
+ unpack_phdr(ORDER(obj->type), buf, &phdr[i]);
+ }
+
+ return 1;
+}
+
+static int
+readshdr(Obj *obj, FILE *fp)
+{
+ long long i, nsec;
+ Elf_Ehdr *hdr;
+ Elf_Shdr *shdr;
+ Elf64 *elf;
+ unsigned char buf[ELFSSZ + ELFHSZ];
+
+ elf = obj->data;
+ hdr = &elf->hdr;
+
+ if (hdr->e_shoff == 0)
+ return 1;
+
+ if (!objpos(obj, fp, hdr->e_shoff))
+ return 0;
+
+ if (hdr->e_shnum != SHN_UNDEF) {
+ nsec = hdr->e_shnum;
+ } else {
+ Elf_Shdr sec0;
+ fpos_t pos;
+
+ fgetpos(fp, &pos);
+ fread(buf, ELFHSZ, 1, fp);
+ fsetpos(fp, &pos);
+
+ if (ferror(fp))
+ return 0;
+
+ unpack_shdr(ORDER(obj->type), buf, &sec0);
+ nsec = sec0.sh_size;
+ }
+
+ if (nsec > SIZE_MAX)
+ return 0;
+
+ shdr = calloc(nsec, sizeof(*shdr));
+ if (!shdr)
+ return 0;
+ elf->shdr = shdr;
+ elf->nsec = nsec;
+
+ for (i = 0; i < nsec; i++) {
+ if (fread(buf, ELFSSZ, 1, fp) != 1)
+ return 0;
+ unpack_shdr(ORDER(obj->type), buf, &shdr[i]);
+ if (shdr[i].sh_type == SHT_SYMTAB) {
+ /*
+ * elf supports multiple symbol table, but we don't
+ * care and we only support one, and we reject elf
+ * files with more of one symbol table.
+ */
+ if (elf->symtab)
+ return 0;
+ elf->symtab = &shdr[i];
+ }
+ }
+
+ return 1;
+}
+
+static int
+readsecstr(Obj *obj, FILE *fp)
+{
+ long idx;
+ size_t siz;
+ char *str;
+ Elf_Shdr *shdr;
+ Elf64 *elf;
+ Elf_Ehdr *hdr;
+
+ elf = obj->data;
+ hdr = &elf->hdr;
+ idx = hdr->e_shstrndx;
+ if (idx == SHN_UNDEF)
+ return 0;
+ if (idx == SHN_XINDEX) {
+ if (hdr->e_shnum == 0)
+ return 0;
+ idx = elf->shdr[0].sh_link;
+ }
+
+ if (idx >= hdr->e_shnum)
+ return 0;
+ shdr = &elf->shdr[idx];
+
+ if (shdr->sh_size > SIZE_MAX)
+ return 0;
+
+ siz = shdr->sh_size;
+ if (siz == 0)
+ return 1;
+ str = malloc(siz);
+ if (!str)
+ return 0;
+
+ elf->strtbl[SEC_STRTBL] = str;
+ elf->strsiz[SEC_STRTBL] = siz;
+
+ if (!objpos(obj, fp, shdr->sh_offset))
+ return 0;
+ if (fread(str, siz, 1, fp) != 1)
+ return 0;
+
+ return 1;
+}
+
+static int
+readsymstr(Obj *obj, FILE *fp)
+{
+ long idx;
+ size_t siz;
+ char *str;
+ Elf64 *elf;
+ Elf_Shdr *shdr;
+
+ elf = obj->data;
+ if (!elf->symtab)
+ return 1;
+
+ idx = elf->symtab->sh_link;
+ if (idx >= elf->nsec)
+ return 0;
+ shdr = &elf->shdr[idx];
+
+ if (shdr->sh_size > SIZE_MAX)
+ return 0;
+
+ siz = shdr->sh_size;
+ if (siz == 0)
+ return 1;
+ str = malloc(siz);
+ if (!str)
+ return 0;
+
+ elf->strtbl[SYM_STRTBL] = str;
+ elf->strsiz[SYM_STRTBL] = siz;
+
+ if (!objpos(obj, fp, shdr->sh_offset))
+ return 0;
+ if (fread(str, siz, 1, fp) != 1)
+ return 0;
+
+ return 1;
+}
+
+static int
+readsym(Obj *obj, FILE *fp)
+{
+ long nsym, i;
+ int sec;
+ Elf64 *elf;
+ Elf_Sym *syms;
+ Elf_Shdr *shdr;
+ unsigned char buf[ELFSSZ];
+
+ elf = obj->data;
+ if (!elf->symtab)
+ return 1;
+ shdr = elf->symtab;
+
+ assert(shdr->sh_type == SHT_SYMTAB);
+
+ nsym = shdr->sh_size / shdr->sh_entsize;
+ if (nsym >= SIZE_MAX)
+ return 0;
+
+ syms = calloc(nsym, sizeof(*syms));
+ if (!syms)
+ return 0;
+ elf->syms = syms;
+ elf->nsym = nsym;
+
+ if (!objpos(obj, fp, shdr->sh_offset))
+ return 0;
+
+ for (i = 0; i < nsym; i++) {
+ if (fread(buf, ELFESZ, 1, fp) != 1)
+ return 0;
+ unpack_sym(ORDER(obj->type), buf, &syms[i]);
+
+ sec = syms[i].st_shndx;
+ switch (sec) {
+ case SHN_XINDEX:
+ /*
+ * Elf supports an extension mechanism to allow
+ * indexes bigger than 4 bytes. We don't care
+ * and we reject elf files using this feature.
+ */
+ return 0;
+ case SHN_UNDEF:
+ case SHN_ABS:
+ case SHN_COMMON:
+ break;
+ default:
+ if (sec >= elf->nsec)
+ return 0;
+ break;
+ }
+ }
+
+ return 1;
+}
+
+int
+elf64read(Obj *obj, FILE *fp)
+{
+ if (!readhdr(obj, fp))
+ return -1;
+ if (!readphdr(obj, fp))
+ return -1;
+ if (!readshdr(obj, fp))
+ return -1;
+ if (!readsym(obj, fp))
+ return -1;
+ if (!readsecstr(obj, fp))
+ return -1;
+ if (!readsymstr(obj, fp))
+ return -1;
+
+ return 0;
+}
--- a/src/libmach/elf64/rules.mk
+++ b/src/libmach/elf64/rules.mk
@@ -2,3 +2,4 @@
elf64/elf64.o \
elf64/elf64new.o\
elf64/elf64probe.o\
+ elf64/elf64read.o\