summaryrefslogtreecommitdiff
path: root/src/base/loader
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/loader')
-rw-r--r--src/base/loader/aout_object.cc23
-rw-r--r--src/base/loader/dtb_object.cc51
-rw-r--r--src/base/loader/dtb_object.hh2
-rw-r--r--src/base/loader/ecoff_object.cc23
-rw-r--r--src/base/loader/elf_object.cc133
-rw-r--r--src/base/loader/elf_object.hh5
-rw-r--r--src/base/loader/object_file.cc21
-rw-r--r--src/base/loader/object_file.hh83
-rw-r--r--src/base/loader/raw_object.cc19
-rw-r--r--src/base/loader/raw_object.hh3
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() {}