diff options
| author | Jon French | 2018-11-01 15:58:08 +0000 |
|---|---|---|
| committer | Jon French | 2018-11-01 15:58:08 +0000 |
| commit | 6bab4056ba7cd10e0dc633187b74b24a73bdd259 (patch) | |
| tree | 9d9b6fb1f26122b6fa1a1a86359737c928b9991b /lib | |
| parent | d47313c00011be39ed1c2e411d401bb759ed65bf (diff) | |
| parent | 29f69b03602552d3ca1a29713527d21f5790e28a (diff) | |
Merge branch 'sail2' into rmem_interpreter
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/coq/Sail2_string.v | 4 | ||||
| -rw-r--r-- | lib/elf.c | 192 | ||||
| -rw-r--r-- | lib/elf.h | 5 | ||||
| -rw-r--r-- | lib/rts.c | 2 |
4 files changed, 188 insertions, 15 deletions
diff --git a/lib/coq/Sail2_string.v b/lib/coq/Sail2_string.v index 0a63ff2c..a02556b2 100644 --- a/lib/coq/Sail2_string.v +++ b/lib/coq/Sail2_string.v @@ -11,6 +11,10 @@ Definition string_drop s (n : {n : Z & ArithFact (n >= 0)}) := let n := Z.to_nat (projT1 n) in String.substring n (String.length s - n) s. +Definition string_take s (n : {n : Z & ArithFact (n >= 0)}) := + let n := Z.to_nat (projT1 n) in + String.substring 0 n s. + Definition string_length s : {n : Z & ArithFact (n >= 0)} := build_ex (Z.of_nat (String.length s)). @@ -103,6 +103,7 @@ uint64_t rev64(uint64_t x) { #define PT_LOAD 1 /* Loadable segment */ #define SHT_SYMTAB 2 /* Symbol table type */ +#define SHT_STRTAB 3 /* String table type */ /* How to extract and insert information held in the st_info field. */ @@ -306,7 +307,7 @@ void loadProgHdr64(bool le, const char* buffer, Elf64_Off off, const int total_f } } -void loadELFHdr(const char* buffer, const int total_file_size) { +void checkELFHdr(const char* buffer, const int total_file_size) { if (total_file_size < sizeof(Elf32_Ehdr)) { fprintf(stderr, "File too small, not big enough even for 32-bit ELF header\n"); exit(EXIT_FAILURE); @@ -319,7 +320,6 @@ void loadELFHdr(const char* buffer, const int total_file_size) { fprintf(stderr, "Invalid ELF magic bytes. Not an ELF file?\n"); exit(EXIT_FAILURE); } - if (hdr->e_ident[EI_CLASS] == ELFCLASS32) { bool le = hdr->e_ident[EI_DATA] == ELFDATA2LSB; Elf32_Ehdr *ehdr = (Elf32_Ehdr*) &buffer[0]; @@ -329,12 +329,6 @@ void loadELFHdr(const char* buffer, const int total_file_size) { fprintf(stderr, "Invalid ELF type or machine for class (32-bit)\n"); exit(EXIT_FAILURE); } - - for(int i = 0; i < rdHalf32(le, ehdr->e_phnum); ++i) { - loadProgHdr32(le, buffer, rdOff32(le, ehdr->e_phoff) + i * rdHalf32(le, ehdr->e_phentsize), total_file_size); - } - - return; } else if (hdr->e_ident[EI_CLASS] == ELFCLASS64) { if (total_file_size < sizeof(Elf64_Ehdr)) { fprintf(stderr, "File too small, specifies 64-bit ELF but not big enough for 64-bit ELF header\n"); @@ -348,19 +342,39 @@ void loadELFHdr(const char* buffer, const int total_file_size) { fprintf(stderr, "Invalid ELF type or machine for class (64-bit)\n"); exit(EXIT_FAILURE); } + } else { + fprintf(stderr, "Unrecognized ELF file format\n"); + exit(EXIT_FAILURE); + } +} + +void loadELFHdr(const char* buffer, const int total_file_size, bool *is32bit_p, uint64_t *entry) { + checkELFHdr(buffer, total_file_size); + Elf32_Ehdr *hdr = (Elf32_Ehdr*) &buffer[0]; + if (hdr->e_ident[EI_CLASS] == ELFCLASS32) { + bool le = hdr->e_ident[EI_DATA] == ELFDATA2LSB; + Elf32_Ehdr *ehdr = (Elf32_Ehdr*) &buffer[0]; + for(int i = 0; i < rdHalf32(le, ehdr->e_phnum); ++i) { + loadProgHdr32(le, buffer, rdOff32(le, ehdr->e_phoff) + i * rdHalf32(le, ehdr->e_phentsize), total_file_size); + } + if (is32bit_p) *is32bit_p = true; + if (entry) *entry = (uint64_t) ehdr->e_entry; + } else if (hdr->e_ident[EI_CLASS] == ELFCLASS64) { + bool le = hdr->e_ident[EI_DATA] == ELFDATA2LSB; + Elf64_Ehdr *ehdr = (Elf64_Ehdr*) &buffer[0]; for(int i = 0; i < rdHalf64(le, ehdr->e_phnum); ++i) { loadProgHdr64(le, buffer, rdOff64(le, ehdr->e_phoff) + i * rdHalf64(le, ehdr->e_phentsize), total_file_size); } - - return; + if (is32bit_p) *is32bit_p = false; + if (entry) *entry = ehdr->e_entry; } else { fprintf(stderr, "Unrecognized ELF file format\n"); exit(EXIT_FAILURE); } } -void load_elf(char *filename) { +void load_elf(char *filename, bool *is32bit_p, uint64_t *entry) { // Read input file into memory char* buffer = NULL; int size = 0; @@ -377,8 +391,7 @@ void load_elf(char *filename) { if (s < 0) { goto fail; } read += s; } - - loadELFHdr(buffer, read); + loadELFHdr(buffer, read, is32bit_p, entry); free(buffer); return; @@ -387,6 +400,159 @@ fail: exit(EXIT_FAILURE); } +// symbol lookup for very simple ELF files (single symtab, two strtabs): looks up a +// single symbol at a time, but avoids retaining memory. + +int lookupSymbol(const char *buffer, const int total_file_size, const char *symname, uint64_t *value) { + checkELFHdr(buffer, total_file_size); + Elf32_Ehdr *hdr = (Elf32_Ehdr*) &buffer[0]; + if (hdr->e_ident[EI_CLASS] == ELFCLASS32) { + bool le = hdr->e_ident[EI_DATA] == ELFDATA2LSB; + Elf32_Ehdr *ehdr = (Elf32_Ehdr*) &buffer[0]; + if (total_file_size < rdOff32(le, ehdr->e_shoff) + + rdHalf32(le, ehdr->e_shnum)*sizeof(Elf32_Shdr)) { + fprintf(stderr, "File too small for %d sections from offset %d\n", + rdHalf32(le, ehdr->e_shnum), rdOff32(le, ehdr->e_shoff)); + exit(EXIT_FAILURE); + } + if (rdHalf32(le, ehdr->e_shtrndx) >= rdHalf32(le, ehdr->e_shnum)) { + fprintf(stderr, "Invalid string section table index %d\n", hdr->e_shtrndx); + exit(EXIT_FAILURE); + } + Elf32_Shdr *shdr = (Elf32_Shdr *)&buffer[ehdr->e_shoff]; + Elf32_Shdr *shstrtab = (Elf32_Shdr *)&shdr[rdHalf32(le, ehdr->e_shtrndx)]; + if (total_file_size < rdOff32(le, shstrtab->sh_offset) + rdWord32(le, shstrtab->sh_size)) { + fprintf(stderr, "File too small for string section\n"); + exit(EXIT_FAILURE); + } + const char *shstrbuf = buffer + rdOff32(le, shstrtab->sh_offset); + Elf32_Word strtabidx = 0, symtabidx = 0; + for (Elf32_Word i = 0; i < rdHalf32(le, ehdr->e_shnum); i++) { + if (rdWord32(le, shdr[i].sh_type) == SHT_SYMTAB) { + symtabidx = i; + } + if (rdWord32(le, shdr[i].sh_type) == SHT_STRTAB) { + // skip section name string table + if (i != rdHalf32(le, ehdr->e_shtrndx)) { + strtabidx = i; + } + } + } + if (!strtabidx || !symtabidx) { + fprintf(stderr, "ELF: unable to find string or symbol table\n"); + return -1; + } + const char *strtab = buffer + rdOff32(le, shdr[strtabidx].sh_offset); + Elf32_Word strtab_size = rdWord32(le, shdr[strtabidx].sh_size); + Elf32_Sym *sym_ent = (Elf32_Sym *)(buffer + rdOff32(le, shdr[symtabidx].sh_offset)); + for (Elf32_Word i = 0; i < rdWord32(le, shdr[symtabidx].sh_size)/sizeof(*sym_ent); i++) { + Elf32_Word sidx = rdWord32(le, sym_ent[i].st_name); + if (sidx >= strtab_size) { + fprintf(stderr, "Symbol name index out of bounds\n"); + exit(EXIT_FAILURE); + } + Elf32_Word max_len = strtab_size - sidx; + const char *sname = strtab + sidx; + if (strnlen(sname, max_len) >= max_len) { + fprintf(stderr, "Unterminated symbol name\n"); + exit(EXIT_FAILURE); + } + if (!strcmp(sname, symname)) { + if (value) *value = (uint64_t) rdAddr32(le, sym_ent[i].st_value); + return 0; + } + } + return -1; + } else if (hdr->e_ident[EI_CLASS] == ELFCLASS64) { + bool le = hdr->e_ident[EI_DATA] == ELFDATA2LSB; + Elf64_Ehdr *ehdr = (Elf64_Ehdr*) &buffer[0]; + if (total_file_size < rdOff64(le, ehdr->e_shoff) + + rdHalf64(le, ehdr->e_shnum)*sizeof(Elf64_Shdr)) { + fprintf(stderr, "File too small for %d sections from offset %ld\n", + rdHalf64(le, ehdr->e_shnum), rdOff64(le, ehdr->e_shoff)); + exit(EXIT_FAILURE); + } + if (rdHalf64(le, ehdr->e_shtrndx) >= rdHalf64(le, ehdr->e_shnum)) { + fprintf(stderr, "Invalid string section table index %d\n", hdr->e_shtrndx); + exit(EXIT_FAILURE); + } + Elf64_Shdr *shdr = (Elf64_Shdr *)&buffer[ehdr->e_shoff]; + Elf64_Shdr *shstrtab = (Elf64_Shdr *)&shdr[rdHalf64(le, ehdr->e_shtrndx)]; + if (total_file_size < rdOff64(le, shstrtab->sh_offset) + rdWord64(le, shstrtab->sh_size)) { + fprintf(stderr, "File too small for string section\n"); + exit(EXIT_FAILURE); + } + const char *shstrbuf = buffer + rdOff64(le, shstrtab->sh_offset); + Elf64_Word strtabidx = 0, symtabidx = 0; + for (Elf64_Word i = 0; i < rdHalf64(le, ehdr->e_shnum); i++) { + if (rdWord64(le, shdr[i].sh_type) == SHT_SYMTAB) { + symtabidx = i; + } + if (rdWord64(le, shdr[i].sh_type) == SHT_STRTAB) { + // skip section name string table + if (i != rdHalf64(le, ehdr->e_shtrndx)) { + strtabidx = i; + } + } + } + if (!strtabidx || !symtabidx) { + fprintf(stderr, "ELF: unable to find string or symbol table\n"); + return -1; + } + const char *strtab = buffer + rdOff64(le, shdr[strtabidx].sh_offset); + Elf64_Xword strtab_size = rdXword64(le, shdr[strtabidx].sh_size); + Elf64_Sym *sym_ent = (Elf64_Sym *)(buffer + rdOff64(le, shdr[symtabidx].sh_offset)); + for (Elf64_Xword i = 0; i < rdXword64(le, shdr[symtabidx].sh_size)/sizeof(*sym_ent); i++) { + Elf64_Word sidx = rdWord64(le, sym_ent[i].st_name); + if (sidx >= strtab_size) { + fprintf(stderr, "Symbol name index out of bounds\n"); + exit(EXIT_FAILURE); + } + Elf64_Word max_len = strtab_size - sidx; + const char *sname = strtab + sidx; + if (strnlen(sname, max_len) >= max_len) { + fprintf(stderr, "Unterminated symbol name\n"); + exit(EXIT_FAILURE); + } + if (!strcmp(sname, symname)) { + if (value) *value = (uint64_t) rdAddr64(le, sym_ent[i].st_value); + return 0; + } + } + return -1; + } else { + fprintf(stderr, "Unrecognized ELF file format\n"); + exit(EXIT_FAILURE); + } +} + +int lookup_sym(const char *filename, const char *symname, uint64_t *value) { + // Read input file into memory + char* buffer = NULL; + int size = 0; + int chunk = (1<<24); // increments output buffer this much + int read = 0; + int ret = 0; + gzFile in = gzopen(filename, "rb"); + if (in == NULL) { goto fail; } + while (!gzeof(in)) { + size = read + chunk; + buffer = (char*)realloc(buffer, size); + if (buffer == NULL) { goto fail; } + + int s = gzread(in, buffer+read, size - read); + if (s < 0) { goto fail; } + read += s; + } + ret = lookupSymbol(buffer, read, symname, value); + free(buffer); + return ret; + +fail: + fprintf(stderr, "Unable to read file %s\n", filename); + exit(EXIT_FAILURE); +} + //////////////////////////////////////////////////////////////// // ELF Loader //////////////////////////////////////////////////////////////// @@ -1,5 +1,8 @@ #pragma once #include<string.h> +#include<stdbool.h> +#include<stdint.h> -void load_elf(char *filename); +void load_elf(char *filename, bool *is32bit_p, uint64_t *entry); +int lookup_sym(const char *filename, const char *symname, uint64_t *value); @@ -520,7 +520,7 @@ int process_arguments(int argc, char *argv[]) break; case 'e': - load_elf(optarg); + load_elf(optarg, NULL, NULL); break; case 'n': |
