From f437e6a4e9983be0583ee1bf34512f80f3cc0162 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Sun, 18 Aug 2019 16:03:43 +0200 Subject: Implement support for big-endian hosts --- fesvr/elf.h | 2 ++ fesvr/elfloader.cc | 74 ++++++++++++++++++++++++++++++------------------------ fesvr/htif.cc | 5 ++-- fesvr/syscall.cc | 11 ++++---- 4 files changed, 52 insertions(+), 40 deletions(-) (limited to 'fesvr') diff --git a/fesvr/elf.h b/fesvr/elf.h index b66038d..b4b0add 100644 --- a/fesvr/elf.h +++ b/fesvr/elf.h @@ -11,6 +11,8 @@ #define IS_ELF32(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 1) #define IS_ELF64(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 2) +#define IS_ELFLE(hdr) (IS_ELF(hdr) && (hdr).e_ident[5] == 1) +#define IS_ELFBE(hdr) (IS_ELF(hdr) && (hdr).e_ident[5] == 2) #define PT_LOAD 1 diff --git a/fesvr/elfloader.cc b/fesvr/elfloader.cc index 3042f54..6e764ef 100644 --- a/fesvr/elfloader.cc +++ b/fesvr/elfloader.cc @@ -2,6 +2,7 @@ #include "elf.h" #include "memif.h" +#include "byteorder.h" #include #include #include @@ -30,58 +31,65 @@ std::map load_elf(const char* fn, memif_t* memif, reg_t* assert(size >= sizeof(Elf64_Ehdr)); const Elf64_Ehdr* eh64 = (const Elf64_Ehdr*)buf; assert(IS_ELF32(*eh64) || IS_ELF64(*eh64)); + assert(IS_ELFLE(*eh64) || IS_ELFBE(*eh64)); std::vector zeros; std::map symbols; - #define LOAD_ELF(ehdr_t, phdr_t, shdr_t, sym_t) do { \ + #define LOAD_ELF(ehdr_t, phdr_t, shdr_t, sym_t, bswap) do { \ ehdr_t* eh = (ehdr_t*)buf; \ - phdr_t* ph = (phdr_t*)(buf + eh->e_phoff); \ - *entry = eh->e_entry; \ - assert(size >= eh->e_phoff + eh->e_phnum*sizeof(*ph)); \ - for (unsigned i = 0; i < eh->e_phnum; i++) { \ - if(ph[i].p_type == PT_LOAD && ph[i].p_memsz) { \ - if (ph[i].p_filesz) { \ - assert(size >= ph[i].p_offset + ph[i].p_filesz); \ - memif->write(ph[i].p_paddr, ph[i].p_filesz, (uint8_t*)buf + ph[i].p_offset); \ + phdr_t* ph = (phdr_t*)(buf + bswap(eh->e_phoff)); \ + *entry = bswap(eh->e_entry); \ + assert(size >= bswap(eh->e_phoff) + bswap(eh->e_phnum)*sizeof(*ph)); \ + for (unsigned i = 0; i < bswap(eh->e_phnum); i++) { \ + if(bswap(ph[i].p_type) == PT_LOAD && bswap(ph[i].p_memsz)) { \ + if (bswap(ph[i].p_filesz)) { \ + assert(size >= bswap(ph[i].p_offset) + bswap(ph[i].p_filesz)); \ + memif->write(bswap(ph[i].p_paddr), bswap(ph[i].p_filesz), (uint8_t*)buf + bswap(ph[i].p_offset)); \ } \ - zeros.resize(ph[i].p_memsz - ph[i].p_filesz); \ - memif->write(ph[i].p_paddr + ph[i].p_filesz, ph[i].p_memsz - ph[i].p_filesz, &zeros[0]); \ + zeros.resize(bswap(ph[i].p_memsz) - bswap(ph[i].p_filesz)); \ + memif->write(bswap(ph[i].p_paddr) + bswap(ph[i].p_filesz), bswap(ph[i].p_memsz) - bswap(ph[i].p_filesz), &zeros[0]); \ } \ } \ - shdr_t* sh = (shdr_t*)(buf + eh->e_shoff); \ - assert(size >= eh->e_shoff + eh->e_shnum*sizeof(*sh)); \ - assert(eh->e_shstrndx < eh->e_shnum); \ - assert(size >= sh[eh->e_shstrndx].sh_offset + sh[eh->e_shstrndx].sh_size); \ - char *shstrtab = buf + sh[eh->e_shstrndx].sh_offset; \ + shdr_t* sh = (shdr_t*)(buf + bswap(eh->e_shoff)); \ + assert(size >= bswap(eh->e_shoff) + bswap(eh->e_shnum)*sizeof(*sh)); \ + assert(bswap(eh->e_shstrndx) < bswap(eh->e_shnum)); \ + assert(size >= bswap(sh[bswap(eh->e_shstrndx)].sh_offset) + bswap(sh[bswap(eh->e_shstrndx)].sh_size)); \ + char *shstrtab = buf + bswap(sh[bswap(eh->e_shstrndx)].sh_offset); \ unsigned strtabidx = 0, symtabidx = 0; \ - for (unsigned i = 0; i < eh->e_shnum; i++) { \ - unsigned max_len = sh[eh->e_shstrndx].sh_size - sh[i].sh_name; \ - assert(sh[i].sh_name < sh[eh->e_shstrndx].sh_size); \ - assert(strnlen(shstrtab + sh[i].sh_name, max_len) < max_len); \ - if (sh[i].sh_type & SHT_NOBITS) continue; \ - assert(size >= sh[i].sh_offset + sh[i].sh_size); \ - if (strcmp(shstrtab + sh[i].sh_name, ".strtab") == 0) \ + for (unsigned i = 0; i < bswap(eh->e_shnum); i++) { \ + unsigned max_len = bswap(sh[bswap(eh->e_shstrndx)].sh_size) - bswap(sh[i].sh_name); \ + assert(bswap(sh[i].sh_name) < bswap(sh[bswap(eh->e_shstrndx)].sh_size)); \ + assert(strnlen(shstrtab + bswap(sh[i].sh_name), max_len) < max_len); \ + if (bswap(sh[i].sh_type) & SHT_NOBITS) continue; \ + assert(size >= bswap(sh[i].sh_offset) + bswap(sh[i].sh_size)); \ + if (strcmp(shstrtab + bswap(sh[i].sh_name), ".strtab") == 0) \ strtabidx = i; \ - if (strcmp(shstrtab + sh[i].sh_name, ".symtab") == 0) \ + if (strcmp(shstrtab + bswap(sh[i].sh_name), ".symtab") == 0) \ symtabidx = i; \ } \ if (strtabidx && symtabidx) { \ - char* strtab = buf + sh[strtabidx].sh_offset; \ - sym_t* sym = (sym_t*)(buf + sh[symtabidx].sh_offset); \ - for (unsigned i = 0; i < sh[symtabidx].sh_size/sizeof(sym_t); i++) { \ - unsigned max_len = sh[strtabidx].sh_size - sym[i].st_name; \ - assert(sym[i].st_name < sh[strtabidx].sh_size); \ - assert(strnlen(strtab + sym[i].st_name, max_len) < max_len); \ - symbols[strtab + sym[i].st_name] = sym[i].st_value; \ + char* strtab = buf + bswap(sh[strtabidx].sh_offset); \ + sym_t* sym = (sym_t*)(buf + bswap(sh[symtabidx].sh_offset)); \ + for (unsigned i = 0; i < bswap(sh[symtabidx].sh_size)/sizeof(sym_t); i++) { \ + unsigned max_len = bswap(sh[strtabidx].sh_size) - bswap(sym[i].st_name); \ + assert(bswap(sym[i].st_name) < bswap(sh[strtabidx].sh_size)); \ + assert(strnlen(strtab + bswap(sym[i].st_name), max_len) < max_len); \ + symbols[strtab + bswap(sym[i].st_name)] = bswap(sym[i].st_value); \ } \ } \ } while(0) if (IS_ELF32(*eh64)) - LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym); + if (IS_ELFLE(*eh64)) + LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym, from_le); + else + LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym, from_be); else - LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym); + if (IS_ELFLE(*eh64)) + LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym, from_le); + else + LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym, from_be); munmap(buf, size); diff --git a/fesvr/htif.cc b/fesvr/htif.cc index d9ff341..d9e884f 100644 --- a/fesvr/htif.cc +++ b/fesvr/htif.cc @@ -4,6 +4,7 @@ #include "rfb.h" #include "elfloader.h" #include "encoding.h" +#include "byteorder.h" #include #include #include @@ -183,7 +184,7 @@ int htif_t::run() while (!signal_exit && exitcode == 0) { - if (auto tohost = mem.read_uint64(tohost_addr)) { + if (auto tohost = from_le(mem.read_uint64(tohost_addr))) { mem.write_uint64(tohost_addr, 0); command_t cmd(mem, tohost, fromhost_callback); device_list.handle_command(cmd); @@ -194,7 +195,7 @@ int htif_t::run() device_list.tick(); if (!fromhost_queue.empty() && mem.read_uint64(fromhost_addr) == 0) { - mem.write_uint64(fromhost_addr, fromhost_queue.front()); + mem.write_uint64(fromhost_addr, to_le(fromhost_queue.front())); fromhost_queue.pop(); } } diff --git a/fesvr/syscall.cc b/fesvr/syscall.cc index 6e8baf6..f0bdd25 100644 --- a/fesvr/syscall.cc +++ b/fesvr/syscall.cc @@ -2,6 +2,7 @@ #include "syscall.h" #include "htif.h" +#include "byteorder.h" #include #include #include @@ -299,21 +300,21 @@ reg_t syscall_t::sys_getmainvars(reg_t pbuf, reg_t limit, reg_t a2, reg_t a3, re { std::vector args = htif->target_args(); std::vector words(args.size() + 3); - words[0] = args.size(); + words[0] = to_le(args.size()); words[args.size()+1] = 0; // argv[argc] = NULL words[args.size()+2] = 0; // envp[0] = NULL size_t sz = (args.size() + 3) * sizeof(words[0]); for (size_t i = 0; i < args.size(); i++) { - words[i+1] = sz + pbuf; + words[i+1] = to_le(sz + pbuf); sz += args[i].length() + 1; } std::vector bytes(sz); memcpy(&bytes[0], &words[0], sizeof(words[0]) * words.size()); for (size_t i = 0; i < args.size(); i++) - strcpy(&bytes[words[i+1] - pbuf], args[i].c_str()); + strcpy(&bytes[from_le(words[i+1]) - pbuf], args[i].c_str()); if (bytes.size() > limit) return -ENOMEM; @@ -342,11 +343,11 @@ void syscall_t::dispatch(reg_t mm) reg_t magicmem[8]; memif->read(mm, sizeof(magicmem), magicmem); - reg_t n = magicmem[0]; + reg_t n = from_le(magicmem[0]); if (n >= table.size() || !table[n]) throw std::runtime_error("bad syscall #" + std::to_string(n)); - magicmem[0] = (this->*table[n])(magicmem[1], magicmem[2], magicmem[3], magicmem[4], magicmem[5], magicmem[6], magicmem[7]); + magicmem[0] = to_le((this->*table[n])(from_le(magicmem[1]), from_le(magicmem[2]), from_le(magicmem[3]), from_le(magicmem[4]), from_le(magicmem[5]), from_le(magicmem[6]), from_le(magicmem[7]))); memif->write(mm, sizeof(magicmem), magicmem); } -- cgit v1.1