arch, base: Stop assuming object files have three segments.
The ObjectFile class has hardcoded assumptions that there are three segments, text, bss and data. There are some files which have one "segment" like raw files, where the entire file's contents are considered a single segment. There are also ELF files which can have an arbitrary number of segments, and those segments can hold any number of sections, including the text, data and/or bss sections. Removing this assumption frees up some object file formats from having to twist themselves to fit in that structure, possibly introducing ambiguities when some segments may fulfill multiple roles. Change-Id: I976e06a3a90ef852b17a6485e2595b006b2090d5 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21463 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com> Maintainer: Gabe Black <gabeblack@google.com>
This commit is contained in:
@@ -54,12 +54,10 @@ AlphaProcess::AlphaProcess(ProcessParams *params, ObjectFile *objFile)
|
||||
objFile)
|
||||
{
|
||||
fatal_if(params->useArchPT, "Arch page tables not implemented.");
|
||||
Addr brk_point = objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize();
|
||||
brk_point = roundUp(brk_point, PageBytes);
|
||||
Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
|
||||
|
||||
// Set up stack. On Alpha, stack goes below the image.
|
||||
Addr stack_base = objFile->textBase() - (409600 + 4096);
|
||||
Addr stack_base = objFile->minSegmentAddr() - (409600 + 4096);
|
||||
|
||||
// Set up region for mmaps.
|
||||
Addr mmap_end = 0x10000;
|
||||
|
||||
@@ -57,11 +57,13 @@ AlphaSystem::AlphaSystem(Params *p)
|
||||
*/
|
||||
// Load Console Code
|
||||
console = createObjectFile(params()->console);
|
||||
console->setLoadMask(loadAddrMask);
|
||||
if (console == NULL)
|
||||
fatal("Could not load console file %s", params()->console);
|
||||
|
||||
// Load pal file
|
||||
pal = createObjectFile(params()->pal);
|
||||
pal->setLoadMask(loadAddrMask);
|
||||
if (pal == NULL)
|
||||
fatal("Could not load PALcode file %s", params()->pal);
|
||||
|
||||
@@ -109,8 +111,8 @@ AlphaSystem::initState()
|
||||
System::initState();
|
||||
|
||||
// Load program sections into memory
|
||||
pal->loadSegments(physProxy, loadAddrMask);
|
||||
console->loadSegments(physProxy, loadAddrMask);
|
||||
pal->loadSegments(physProxy);
|
||||
console->loadSegments(physProxy);
|
||||
|
||||
/**
|
||||
* Copy the osflags (kernel arguments) into the consoles
|
||||
|
||||
@@ -132,7 +132,7 @@ FreebsdArmSystem::initState()
|
||||
if (ra)
|
||||
bootReleaseAddr = ra & ~ULL(0x7F);
|
||||
|
||||
dtb_file->setTextBase(params()->atags_addr + loadAddrOffset);
|
||||
dtb_file->setLoadOffset(params()->atags_addr + loadAddrOffset);
|
||||
dtb_file->loadSegments(physProxy);
|
||||
delete dtb_file;
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ LinuxArmSystem::initState()
|
||||
"to DTB file: %s\n", params()->dtb_filename);
|
||||
}
|
||||
|
||||
dtb_file->setTextBase(params()->atags_addr + loadAddrOffset);
|
||||
dtb_file->setLoadOffset(params()->atags_addr + loadAddrOffset);
|
||||
dtb_file->loadSegments(physProxy);
|
||||
delete dtb_file;
|
||||
} else {
|
||||
|
||||
@@ -75,8 +75,7 @@ ArmProcess32::ArmProcess32(ProcessParams *params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch)
|
||||
: ArmProcess(params, objFile, _arch)
|
||||
{
|
||||
Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize(), PageBytes);
|
||||
Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
|
||||
Addr stack_base = 0xbf000000L;
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
@@ -90,8 +89,7 @@ ArmProcess64::ArmProcess64(ProcessParams *params, ObjectFile *objFile,
|
||||
ObjectFile::Arch _arch)
|
||||
: ArmProcess(params, objFile, _arch)
|
||||
{
|
||||
Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize(), PageBytes);
|
||||
Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
|
||||
Addr stack_base = 0x7fffff0000L;
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
|
||||
@@ -65,8 +65,7 @@ MipsProcess::MipsProcess(ProcessParams *params, ObjectFile *objFile)
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
|
||||
// Set up break point (Top of Heap)
|
||||
Addr brk_point = objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize();
|
||||
Addr brk_point = objFile->maxSegmentAddr();
|
||||
brk_point = roundUp(brk_point, PageBytes);
|
||||
|
||||
// Set up region for mmaps. Start it 1GB above the top of the heap.
|
||||
|
||||
@@ -56,8 +56,7 @@ PowerProcess::PowerProcess(ProcessParams *params, ObjectFile *objFile)
|
||||
{
|
||||
fatal_if(params->useArchPT, "Arch page tables not implemented.");
|
||||
// Set up break point (Top of Heap)
|
||||
Addr brk_point = objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize();
|
||||
Addr brk_point = objFile->maxSegmentAddr();
|
||||
brk_point = roundUp(brk_point, PageBytes);
|
||||
|
||||
Addr stack_base = 0xbf000000L;
|
||||
|
||||
@@ -75,8 +75,7 @@ RiscvProcess64::RiscvProcess64(ProcessParams *params, ObjectFile *objFile) :
|
||||
const Addr stack_base = 0x7FFFFFFFFFFFFFFFL;
|
||||
const Addr max_stack_size = 8 * 1024 * 1024;
|
||||
const Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
const Addr brk_point = roundUp(objFile->bssBase() + objFile->bssSize(),
|
||||
PageBytes);
|
||||
const Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
|
||||
const Addr mmap_end = 0x4000000000000000L;
|
||||
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
|
||||
next_thread_stack_base, mmap_end);
|
||||
@@ -88,8 +87,7 @@ RiscvProcess32::RiscvProcess32(ProcessParams *params, ObjectFile *objFile) :
|
||||
const Addr stack_base = 0x7FFFFFFF;
|
||||
const Addr max_stack_size = 8 * 1024 * 1024;
|
||||
const Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
const Addr brk_point = roundUp(objFile->bssBase() + objFile->bssSize(),
|
||||
PageBytes);
|
||||
const Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
|
||||
const Addr mmap_end = 0x40000000L;
|
||||
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
|
||||
next_thread_stack_base, mmap_end);
|
||||
|
||||
@@ -78,8 +78,7 @@ class Sparc32Process : public SparcProcess
|
||||
Sparc32Process(ProcessParams * params, ObjectFile *objFile)
|
||||
: SparcProcess(params, objFile, 0)
|
||||
{
|
||||
Addr brk_point = objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize();
|
||||
Addr brk_point = objFile->maxSegmentAddr();
|
||||
brk_point = roundUp(brk_point, SparcISA::PageBytes);
|
||||
|
||||
// Reserve 8M for main stack.
|
||||
@@ -123,8 +122,7 @@ class Sparc64Process : public SparcProcess
|
||||
Sparc64Process(ProcessParams * params, ObjectFile *objFile)
|
||||
: SparcProcess(params, objFile, 2047)
|
||||
{
|
||||
Addr brk_point = objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize();
|
||||
Addr brk_point = objFile->maxSegmentAddr();
|
||||
brk_point = roundUp(brk_point, SparcISA::PageBytes);
|
||||
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
|
||||
@@ -137,22 +137,22 @@ SparcSystem::initState()
|
||||
System::initState();
|
||||
|
||||
// Load reset binary into memory
|
||||
reset->setTextBase(params()->reset_addr);
|
||||
reset->setLoadOffset(params()->reset_addr);
|
||||
reset->loadSegments(physProxy);
|
||||
// Load the openboot binary
|
||||
openboot->setTextBase(params()->openboot_addr);
|
||||
openboot->setLoadOffset(params()->openboot_addr);
|
||||
openboot->loadSegments(physProxy);
|
||||
// Load the hypervisor binary
|
||||
hypervisor->setTextBase(params()->hypervisor_addr);
|
||||
hypervisor->setLoadOffset(params()->hypervisor_addr);
|
||||
hypervisor->loadSegments(physProxy);
|
||||
// Load the nvram image
|
||||
nvram->setTextBase(params()->nvram_addr);
|
||||
nvram->setLoadOffset(params()->nvram_addr);
|
||||
nvram->loadSegments(physProxy);
|
||||
// Load the hypervisor description image
|
||||
hypervisor_desc->setTextBase(params()->hypervisor_desc_addr);
|
||||
hypervisor_desc->setLoadOffset(params()->hypervisor_desc_addr);
|
||||
hypervisor_desc->loadSegments(physProxy);
|
||||
// Load the partition description image
|
||||
partition_desc->setTextBase(params()->partition_desc_addr);
|
||||
partition_desc->setLoadOffset(params()->partition_desc_addr);
|
||||
partition_desc->loadSegments(physProxy);
|
||||
|
||||
|
||||
|
||||
@@ -136,8 +136,7 @@ X86_64Process::X86_64Process(ProcessParams *params, ObjectFile *objFile,
|
||||
vsyscallPage.vtimeOffset = 0x400;
|
||||
vsyscallPage.vgettimeofdayOffset = 0x0;
|
||||
|
||||
Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize(), PageBytes);
|
||||
Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
|
||||
Addr stack_base = 0x7FFFFFFFF000ULL;
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
@@ -176,8 +175,7 @@ I386Process::I386Process(ProcessParams *params, ObjectFile *objFile,
|
||||
vsyscallPage.vsyscallOffset = 0x400;
|
||||
vsyscallPage.vsysexitOffset = 0x410;
|
||||
|
||||
Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
|
||||
objFile->bssSize(), PageBytes);
|
||||
Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
|
||||
Addr stack_base = _gdtStart;
|
||||
Addr max_stack_size = 8 * 1024 * 1024;
|
||||
Addr next_thread_stack_base = stack_base - max_stack_size;
|
||||
|
||||
@@ -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);
|
||||
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);
|
||||
|
||||
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);
|
||||
for (auto &seg: segments)
|
||||
DPRINTFR(Loader, "%s\n", *seg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ class DtbObject : public ObjectFile
|
||||
*/
|
||||
bool fileDataMmapped;
|
||||
|
||||
Segment *data;
|
||||
|
||||
public:
|
||||
virtual ~DtbObject();
|
||||
|
||||
|
||||
@@ -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);
|
||||
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);
|
||||
|
||||
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);
|
||||
for (auto &seg: segments)
|
||||
DPRINTFR(Loader, "%s\n", *seg);
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
Addr
|
||||
maxSegmentAddr() const
|
||||
{
|
||||
Addr max = 0;
|
||||
for (auto &seg: segments) {
|
||||
Addr end = seg->base + seg->size;
|
||||
if (end > max)
|
||||
max = end;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
size_t textSize() const { return text.size; }
|
||||
size_t dataSize() const { return data.size; }
|
||||
size_t bssSize() const { return bss.size; }
|
||||
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);
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
|
||||
@@ -1888,19 +1888,14 @@ mmapImpl(SyscallDesc *desc, int num, ThreadContext *tc, bool is_mmap2)
|
||||
// this will not work since there is a single global symbol table.
|
||||
ObjectFile *interpreter = p->getInterpreter();
|
||||
if (interpreter) {
|
||||
Addr text_start = interpreter->textBase();
|
||||
Addr text_end = text_start + interpreter->textSize();
|
||||
|
||||
Addr pc = tc->pcState().pc();
|
||||
|
||||
if (pc >= text_start && pc < text_end) {
|
||||
if (interpreter->contains(tc->pcState().instAddr())) {
|
||||
std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
|
||||
auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
|
||||
ObjectFile *lib = createObjectFile(ffdp->getFileName());
|
||||
|
||||
if (lib) {
|
||||
lib->loadAllSymbols(debugSymbolTable,
|
||||
lib->textBase(), start);
|
||||
lib->minSegmentAddr(), start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,14 +152,16 @@ System::System(Params *p)
|
||||
} else {
|
||||
// Get the kernel code
|
||||
kernel = createObjectFile(params()->kernel);
|
||||
kernel->setLoadOffset(loadAddrOffset);
|
||||
kernel->setLoadMask(loadAddrMask);
|
||||
inform("kernel located at: %s", params()->kernel);
|
||||
|
||||
if (kernel == NULL)
|
||||
fatal("Could not load kernel file %s", params()->kernel);
|
||||
|
||||
// setup entry points
|
||||
kernelStart = kernel->textBase();
|
||||
kernelEnd = kernel->bssBase() + kernel->bssSize();
|
||||
kernelStart = kernel->minSegmentAddr();
|
||||
kernelEnd = kernel->maxSegmentAddr();
|
||||
kernelEntry = kernel->entryPoint();
|
||||
|
||||
// If load_addr_mask is set to 0x0, then auto-calculate
|
||||
@@ -168,6 +170,7 @@ System::System(Params *p)
|
||||
if (loadAddrMask == 0) {
|
||||
Addr shift_amt = findMsbSet(kernelEnd - kernelStart) + 1;
|
||||
loadAddrMask = ((Addr)1 << shift_amt) - 1;
|
||||
kernel->setLoadMask(loadAddrMask);
|
||||
}
|
||||
|
||||
// load symbols
|
||||
@@ -192,6 +195,8 @@ System::System(Params *p)
|
||||
ObjectFile *obj = createObjectFile(obj_name);
|
||||
fatal_if(!obj, "Failed to additional kernel object '%s'.\n",
|
||||
obj_name);
|
||||
obj->setLoadOffset(loadAddrOffset);
|
||||
obj->setLoadMask(loadAddrMask);
|
||||
kernelExtras.push_back(obj);
|
||||
}
|
||||
}
|
||||
@@ -327,11 +332,9 @@ System::initState()
|
||||
}
|
||||
}
|
||||
// Load program sections into memory
|
||||
kernel->loadSegments(physProxy, loadAddrMask, loadAddrOffset);
|
||||
for (const auto &extra_kernel : kernelExtras) {
|
||||
extra_kernel->loadSegments(physProxy, loadAddrMask,
|
||||
loadAddrOffset);
|
||||
}
|
||||
kernel->loadSegments(physProxy);
|
||||
for (const auto &extra_kernel : kernelExtras)
|
||||
extra_kernel->loadSegments(physProxy);
|
||||
|
||||
DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
|
||||
DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd);
|
||||
|
||||
Reference in New Issue
Block a user