diff options
Diffstat (limited to 'src/base/loader')
-rw-r--r-- | src/base/loader/aout_object.cc | 23 | ||||
-rw-r--r-- | src/base/loader/dtb_object.cc | 51 | ||||
-rw-r--r-- | src/base/loader/dtb_object.hh | 2 | ||||
-rw-r--r-- | src/base/loader/ecoff_object.cc | 23 | ||||
-rw-r--r-- | src/base/loader/elf_object.cc | 133 | ||||
-rw-r--r-- | src/base/loader/elf_object.hh | 5 | ||||
-rw-r--r-- | src/base/loader/object_file.cc | 21 | ||||
-rw-r--r-- | src/base/loader/object_file.hh | 83 | ||||
-rw-r--r-- | src/base/loader/raw_object.cc | 19 | ||||
-rw-r--r-- | src/base/loader/raw_object.hh | 3 |
10 files changed, 165 insertions, 198 deletions
diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc index e3f703e1d..97651586f 100644 --- a/src/base/loader/aout_object.cc +++ b/src/base/loader/aout_object.cc @@ -61,21 +61,14 @@ AoutObject::AoutObject(const string &_filename, entry = execHdr->entry; - text.base = N_TXTADDR(*execHdr); - text.size = execHdr->tsize; - text.data = fileData + N_TXTOFF(*execHdr); - - data.base = N_DATADDR(*execHdr); - data.size = execHdr->dsize; - data.data = fileData + N_DATOFF(*execHdr); - - bss.base = N_BSSADDR(*execHdr); - bss.size = execHdr->bsize; - bss.data = NULL; - - DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", - text.base, text.size, data.base, data.size, - bss.base, bss.size); + addSegment("text", N_TXTADDR(*execHdr), fileData + N_TXTOFF(*execHdr), + execHdr->tsize); + addSegment("data", N_DATADDR(*execHdr), fileData + N_DATOFF(*execHdr), + execHdr->dsize); + addSegment("bss", N_BSSADDR(*execHdr), nullptr, execHdr->bsize); + + for (auto &seg: segments) + DPRINTFR(Loader, "%s\n", *seg); } diff --git a/src/base/loader/dtb_object.cc b/src/base/loader/dtb_object.cc index 92e305ffa..275139a8c 100644 --- a/src/base/loader/dtb_object.cc +++ b/src/base/loader/dtb_object.cc @@ -53,20 +53,10 @@ DtbObject::tryFile(const std::string &fname, size_t len, uint8_t *data) DtbObject::DtbObject(const std::string &_filename, size_t _len, uint8_t *_data, Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _len, _data, _arch, _opSys) + : ObjectFile(_filename, _len, _data, _arch, _opSys), + data(new Segment{ "data", 0, fileData, len }) { - text.base = 0; - text.size = len; - text.data = fileData; - - data.base = 0; - data.size = 0; - data.data = nullptr; - - bss.base = 0; - bss.size = 0; - bss.data = nullptr; - + segments.emplace_back(data); fileDataMmapped = true; } @@ -92,10 +82,10 @@ DtbObject::addBootCmdLine(const char* _args, size_t len) const char* property_name = "bootargs"; // Make a new buffer that has extra space to add nodes/properties - int newLen = 2*this->len; - uint8_t* fdt_buf_w_space = new uint8_t[newLen]; + int newLen = 2 * this->len; + uint8_t *fdt_buf_w_space = new uint8_t[newLen]; // Copy and unpack flattened device tree into new buffer - int ret = fdt_open_into((void*)fileData, (void*)fdt_buf_w_space, (newLen)); + int ret = fdt_open_into((void *)fileData, (void *)fdt_buf_w_space, newLen); if (ret < 0) { warn("Error resizing buffer of flattened device tree, " "errno: %d\n", ret); @@ -104,14 +94,15 @@ DtbObject::addBootCmdLine(const char* _args, size_t len) } // First try finding the /chosen node in the dtb - int offset = fdt_path_offset((void*)fdt_buf_w_space, full_path_node_name); + int offset = fdt_path_offset((void *)fdt_buf_w_space, full_path_node_name); if (offset < 0) { // try adding the node by walking dtb tree to proper insertion point - offset = fdt_path_offset((void*)fdt_buf_w_space, root_path); - offset = fdt_add_subnode((void*)fdt_buf_w_space, offset, node_name); + offset = fdt_path_offset((void *)fdt_buf_w_space, root_path); + offset = fdt_add_subnode((void *)fdt_buf_w_space, offset, node_name); // if we successfully add the subnode, get the offset if (offset >= 0) - offset = fdt_path_offset((void*)fdt_buf_w_space, full_path_node_name); + offset = fdt_path_offset((void *)fdt_buf_w_space, + full_path_node_name); if (offset < 0) { warn("Error finding or adding \"chosen\" subnode to flattened " @@ -122,8 +113,8 @@ DtbObject::addBootCmdLine(const char* _args, size_t len) } // Set the bootargs property in the /chosen node - ret = fdt_setprop((void*)fdt_buf_w_space, offset, property_name, - (const void*)_args, len+1); + ret = fdt_setprop((void *)fdt_buf_w_space, offset, property_name, + (const void *)_args, len+1); if (ret < 0) { warn("Error setting \"bootargs\" property to flattened device tree, " "errno: %d\n", ret); @@ -132,7 +123,7 @@ DtbObject::addBootCmdLine(const char* _args, size_t len) } // Repack the dtb for kernel use - ret = fdt_pack((void*)fdt_buf_w_space); + ret = fdt_pack((void *)fdt_buf_w_space); if (ret < 0) { warn("Error re-packing flattened device tree structure, " "errno: %d\n", ret); @@ -140,8 +131,8 @@ DtbObject::addBootCmdLine(const char* _args, size_t len) return false; } - text.size = newLen; - text.data = fdt_buf_w_space; + data->size = newLen; + data->data = fdt_buf_w_space; // clean up old buffer and set to new fdt blob munmap(fileData, this->len); @@ -155,7 +146,7 @@ DtbObject::addBootCmdLine(const char* _args, size_t len) Addr DtbObject::findReleaseAddr() { - void *fd = (void*)fileData; + void *fd = (void *)fileData; int offset = fdt_path_offset(fd, "/cpus/cpu@0"); int len; @@ -164,9 +155,11 @@ DtbObject::findReleaseAddr() Addr rel_addr = 0; if (len > 3) - rel_addr = betoh(*static_cast<const uint32_t*>(temp)); - if (len == 8) - rel_addr = (rel_addr << 32) | betoh(*(static_cast<const uint32_t*>(temp)+1)); + rel_addr = betoh(*static_cast<const uint32_t *>(temp)); + if (len == 8) { + rel_addr = (rel_addr << 32) | + betoh(*(static_cast<const uint32_t *>(temp) + 1)); + } return rel_addr; } diff --git a/src/base/loader/dtb_object.hh b/src/base/loader/dtb_object.hh index c49b144ac..7cb842e43 100644 --- a/src/base/loader/dtb_object.hh +++ b/src/base/loader/dtb_object.hh @@ -49,6 +49,8 @@ class DtbObject : public ObjectFile */ bool fileDataMmapped; + Segment *data; + public: virtual ~DtbObject(); diff --git a/src/base/loader/ecoff_object.cc b/src/base/loader/ecoff_object.cc index 76b91dd66..56f9b35fc 100644 --- a/src/base/loader/ecoff_object.cc +++ b/src/base/loader/ecoff_object.cc @@ -73,21 +73,14 @@ EcoffObject::EcoffObject(const string &_filename, size_t _len, uint8_t *_data, entry = aoutHdr->entry; - text.base = aoutHdr->text_start; - text.size = aoutHdr->tsize; - text.data = fileData + ECOFF_TXTOFF(execHdr); - - data.base = aoutHdr->data_start; - data.size = aoutHdr->dsize; - data.data = fileData + ECOFF_DATOFF(execHdr); - - bss.base = aoutHdr->bss_start; - bss.size = aoutHdr->bsize; - bss.data = nullptr; - - DPRINTFR(Loader, "text: %#x %d\ndata: %#x %d\nbss: %#x %d\n", - text.base, text.size, data.base, data.size, - bss.base, bss.size); + addSegment("text", aoutHdr->text_start, fileData + ECOFF_TXTOFF(execHdr), + aoutHdr->tsize); + addSegment("data", aoutHdr->data_start, fileData + ECOFF_DATOFF(execHdr), + aoutHdr->dsize); + addSegment("bss", aoutHdr->bss_start, nullptr, aoutHdr->bsize); + + for (auto &seg: segments) + DPRINTFR(Loader, "%s\n", *seg); } bool diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc index 327919540..4dee7d2c0 100644 --- a/src/base/loader/elf_object.cc +++ b/src/base/loader/elf_object.cc @@ -293,45 +293,8 @@ ElfObject::ElfObject(const std::string &_filename, size_t _len, entry = ehdr.e_entry; - // initialize segment sizes to 0 in case they're not present - text.size = data.size = bss.size = 0; - text.base = data.base = bss.base = 0; - int sec_idx = 1; - // The first address of some important sections. - Addr text_sec_start = 0; - Addr data_sec_start = 0; - Addr bss_sec_start = 0; - - // Get the first section - Elf_Scn *section = elf_getscn(elf, sec_idx); - - // Find the beginning of the most interesting sections. - while (section) { - GElf_Shdr shdr; - gelf_getshdr(section, &shdr); - char *sec_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); - - if (sec_name) { - if (!strcmp(".text", sec_name)) { - text_sec_start = shdr.sh_addr; - } else if (!strcmp(".data", sec_name)) { - data_sec_start = shdr.sh_addr; - } else if (!strcmp(".bss", sec_name)) { - bss_sec_start = shdr.sh_addr; - } - } else { - Elf_Error errorNum = (Elf_Error)elf_errno(); - if (errorNum != ELF_E_NONE) { - const char *errorMessage = elf_errmsg(errorNum); - fatal("Error from libelf: %s.\n", errorMessage); - } - } - - section = elf_getscn(elf, ++sec_idx); - } - // Go through all the segments in the program, record them, and scrape // out information about the text, data, and bss areas needed by other // code. @@ -348,50 +311,54 @@ ElfObject::ElfObject(const std::string &_filename, size_t _len, ldMin = std::min(ldMin, phdr.p_vaddr); ldMax = std::max(ldMax, phdr.p_vaddr + phdr.p_memsz); - // Check to see if this segment contains the bss section. - if (phdr.p_paddr <= bss_sec_start && - phdr.p_paddr + phdr.p_memsz > bss_sec_start && - phdr.p_memsz - phdr.p_filesz > 0) { - bss.base = phdr.p_paddr + phdr.p_filesz; - bss.size = phdr.p_memsz - phdr.p_filesz; - bss.data = nullptr; + std::string name; + + // Get the first section + Elf_Scn *section = elf_getscn(elf, sec_idx); + + // Name segments after the sections they contain. + while (section) { + GElf_Shdr shdr; + gelf_getshdr(section, &shdr); + char *sec_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); + + if (!sec_name) { + Elf_Error errorNum = (Elf_Error)elf_errno(); + if (errorNum != ELF_E_NONE) { + const char *errorMessage = elf_errmsg(errorNum); + fatal("Error from libelf: %s.\n", errorMessage); + } + } + + if (shdr.sh_addr >= ldMin && shdr.sh_addr < ldMax) { + if (name != "") + name += ","; + name += sec_name; + } + + section = elf_getscn(elf, ++sec_idx); } - // Check to see if this is the text or data segment - if (phdr.p_vaddr <= text_sec_start && - phdr.p_vaddr + phdr.p_filesz > text_sec_start) { - - // If this value is nonzero, we need to flip the relocate flag. - if (phdr.p_vaddr != 0) - relocate = false; - - text.base = phdr.p_paddr; - text.size = phdr.p_filesz; - text.data = fileData + phdr.p_offset; - } else if (phdr.p_vaddr <= data_sec_start && - phdr.p_vaddr + phdr.p_filesz > data_sec_start) { - data.base = phdr.p_paddr; - data.size = phdr.p_filesz; - data.data = fileData + phdr.p_offset; - } else { - // If it's none of the above but is loadable, - // load the filesize worth of data - Segment extra; - extra.base = phdr.p_paddr; - extra.size = phdr.p_filesz; - extra.data = fileData + phdr.p_offset; - extraSegments.push_back(extra); + addSegment(name, phdr.p_paddr, fileData + phdr.p_offset, + phdr.p_filesz); + Addr uninitialized = phdr.p_memsz - phdr.p_filesz; + if (uninitialized) { + // There may be parts of a segment which aren't included in the + // file. In those cases, we need to create a new segment with no + // data to take up the extra space. This should be zeroed when + // loaded into memory. + addSegment(name + "(uninitialized)", phdr.p_paddr + phdr.p_filesz, + nullptr, uninitialized); } } // should have found at least one loadable segment - warn_if(text.size == 0, - "Empty .text segment in '%s'. ELF file corrupted?\n", + warn_if(segments.empty(), + "No loadable segments in '%s'. ELF file corrupted?\n", filename); - DPRINTFR(Loader, "text: %#x %d\ndata: %#x %d\nbss: %#x %d\n", - text.base, text.size, data.base, data.size, - bss.base, bss.size); + for (auto &seg: segments) + DPRINTFR(Loader, "%s\n", *seg); elf_end(elf); @@ -498,20 +465,13 @@ ElfObject::loadWeakSymbols(SymbolTable *symtab, Addr base, Addr offset, } bool -ElfObject::loadSegments(const PortProxy& mem_proxy, Addr addr_mask, - Addr offset) +ElfObject::loadSegments(const PortProxy &mem_proxy) { - if (!ObjectFile::loadSegments(mem_proxy, addr_mask, offset)) + if (!ObjectFile::loadSegments(mem_proxy)) return false; - for (auto seg : extraSegments) { - if (!loadSegment(&seg, mem_proxy, addr_mask, offset)) { - return false; - } - } - if (interpreter) - interpreter->loadSegments(mem_proxy, addr_mask, offset); + interpreter->loadSegments(mem_proxy); return true; } @@ -570,9 +530,6 @@ ElfObject::updateBias(Addr bias_addr) entry += bias_addr; // Patch segments with the bias_addr. - text.base += bias_addr; - data.base += bias_addr; - bss.base += bias_addr; - for (auto &segment : extraSegments) - segment.base += bias_addr; + for (auto &segment : segments) + segment->base += bias_addr; } diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh index 244b9fc3f..f2af4142a 100644 --- a/src/base/loader/elf_object.hh +++ b/src/base/loader/elf_object.hh @@ -86,13 +86,10 @@ class ElfObject : public ObjectFile void getSections(); bool sectionExists(std::string sec); - std::vector<Segment> extraSegments; - public: virtual ~ElfObject() {} - bool loadSegments(const PortProxy& mem_proxy, Addr addr_mask = maxAddr, - Addr offset = 0) override; + bool loadSegments(const PortProxy &mem_proxy) override; virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0, Addr offset = 0, Addr addr_mask = maxAddr) diff --git a/src/base/loader/object_file.cc b/src/base/loader/object_file.cc index 8a6b063de..d63b2221b 100644 --- a/src/base/loader/object_file.cc +++ b/src/base/loader/object_file.cc @@ -57,10 +57,8 @@ ObjectFile::ObjectFile(const string &_filename, size_t _len, uint8_t *_data, Arch _arch, OpSys _op_sys) : filename(_filename), fileData(_data), len(_len), - arch(_arch), opSys(_op_sys), entry(0), - text{0, nullptr, 0}, data{0, nullptr, 0}, bss{0, nullptr, 0} -{ -} + arch(_arch), opSys(_op_sys), entry(0) +{} ObjectFile::~ObjectFile() @@ -73,11 +71,10 @@ ObjectFile::~ObjectFile() bool -ObjectFile::loadSegment(Segment *seg, const PortProxy& mem_proxy, - Addr addr_mask, Addr offset) +ObjectFile::loadSegment(Segment *seg, const PortProxy &mem_proxy) { if (seg->size != 0) { - Addr addr = (seg->base & addr_mask) + offset; + Addr addr = (seg->base & loadMask) + loadOffset; if (seg->data) { mem_proxy.writeBlob(addr, seg->data, seg->size); } else { @@ -90,12 +87,12 @@ ObjectFile::loadSegment(Segment *seg, const PortProxy& mem_proxy, bool -ObjectFile::loadSegments(const PortProxy& mem_proxy, Addr addr_mask, - Addr offset) +ObjectFile::loadSegments(const PortProxy &proxy) { - return (loadSegment(&text, mem_proxy, addr_mask, offset) - && loadSegment(&data, mem_proxy, addr_mask, offset) - && loadSegment(&bss, mem_proxy, addr_mask, offset)); + for (auto &seg: segments) + if (!loadSegment(seg.get(), proxy)) + return false; + return true; } namespace diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh index db995f5d7..e5053ad82 100644 --- a/src/base/loader/object_file.hh +++ b/src/base/loader/object_file.hh @@ -33,7 +33,9 @@ #define __OBJECT_FILE_HH__ #include <limits> +#include <memory> #include <string> +#include <vector> #include "base/logging.hh" #include "base/types.hh" @@ -72,10 +74,14 @@ class ObjectFile FreeBSD }; + static const Addr maxAddr = std::numeric_limits<Addr>::max(); + protected: const std::string filename; uint8_t *fileData; size_t len; + Addr loadOffset=0; + Addr loadMask=maxAddr; Arch arch; OpSys opSys; @@ -86,10 +92,7 @@ class ObjectFile public: virtual ~ObjectFile(); - static const Addr maxAddr = std::numeric_limits<Addr>::max(); - - virtual bool loadSegments(const PortProxy &mem_proxy, - Addr mask=maxAddr, Addr offset=0); + virtual bool loadSegments(const PortProxy &mem_proxy); virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0, Addr offset=0, Addr mask=maxAddr) = 0; @@ -114,41 +117,76 @@ class ObjectFile Arch getArch() const { return arch; } OpSys getOpSys() const { return opSys; } - protected: - struct Segment { + std::string name; Addr base; uint8_t *data; size_t size; }; + protected: Addr entry; - Segment text; - Segment data; - Segment bss; + std::vector<std::unique_ptr<Segment>> segments; - bool loadSegment(Segment *seg, const PortProxy &mem_proxy, Addr mask, - Addr offset=0); + void + addSegment(std::string name, Addr base, uint8_t *data, size_t size) + { + Segment *seg = new Segment; + seg->name = name; + seg->base = base; + seg->data = data; + seg->size = size; + segments.emplace_back(seg); + } + + bool loadSegment(Segment *seg, const PortProxy &mem_proxy); public: Addr entryPoint() const { return entry; } - Addr textBase() const { return text.base; } - Addr dataBase() const { return data.base; } - Addr bssBase() const { return bss.base; } - - size_t textSize() const { return text.size; } - size_t dataSize() const { return data.size; } - size_t bssSize() const { return bss.size; } + Addr + maxSegmentAddr() const + { + Addr max = 0; + for (auto &seg: segments) { + Addr end = seg->base + seg->size; + if (end > max) + max = end; + } + return max; + } + + Addr + minSegmentAddr() const + { + Addr min = maxAddr; + for (auto &seg: segments) + if (seg->base < min) + min = seg->base; + return min; + } + + bool + contains(Addr addr) const + { + for (auto &seg: segments) { + Addr start = seg->base; + Addr end = seg->base + seg->size; + if (addr >= start && addr < end) + return true; + } + return false; + } /* This function allows you to override the base address where * a binary is going to be loaded or set it if the binary is just a * blob that doesn't include an object header. * @param a address to load the binary/text section at */ - void setTextBase(Addr a) { text.base = a; } + void setLoadOffset(Addr val) { loadOffset = val; } + void setLoadMask(Addr val) { loadMask = val; } /** * Each instance of a Loader subclass will have a chance to try to load @@ -183,6 +221,13 @@ class ObjectFile static Process *tryLoaders(ProcessParams *params, ObjectFile *obj_file); }; +static inline std::ostream & +operator << (std::ostream &os, const ObjectFile::Segment &seg) +{ + ccprintf(os, "%s: %#x %d", seg.name, seg.base, seg.size); + return os; +} + ObjectFile *createObjectFile(const std::string &fname, bool raw = false); diff --git a/src/base/loader/raw_object.cc b/src/base/loader/raw_object.cc index 9662d8613..b0ece3ba2 100644 --- a/src/base/loader/raw_object.cc +++ b/src/base/loader/raw_object.cc @@ -43,23 +43,10 @@ RawObject::tryFile(const std::string &fname, size_t len, uint8_t *data) RawObject::RawObject(const std::string &_filename, size_t _len, uint8_t *_data, Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _len, _data, _arch, _opSys) + : ObjectFile(_filename, _len, _data, _arch, _opSys), + data(new Segment{ "data", 0, fileData, len }) { - text.base = 0; - text.size = len; - text.data = fileData; - - data.base = 0; - data.size = 0; - data.data = nullptr; - - bss.base = 0; - bss.size = 0; - bss.data = nullptr; - - DPRINTFR(Loader, "text: %#x %d\ndata: %#x %d\nbss: %#x %d\n", - text.base, text.size, data.base, data.size, - bss.base, bss.size); + segments.emplace_back(data); } bool diff --git a/src/base/loader/raw_object.hh b/src/base/loader/raw_object.hh index 6931a1321..9eb929107 100644 --- a/src/base/loader/raw_object.hh +++ b/src/base/loader/raw_object.hh @@ -38,6 +38,9 @@ class RawObject: public ObjectFile protected: RawObject(const std::string &_filename, size_t _len, uint8_t *_data, Arch _arch, OpSys _opSys); + + Segment *data; + public: virtual ~RawObject() {} |