arch,base: Separate the idea of a memory image and object file.

A memory image can be described by an object file, but an object file
is more than a memory image. Also, it makes sense to manipulate a
memory image to, for instance, change how it's loaded into memory. That
takes on larger implications (relocations, the entry point, symbols,
etc.) when talking about the whole object file, and also modifies
aspects which may not need to change. For instance if an image needs
to be loaded into memory at addresses different from what's in the
object file, but other things like symbols need to stay unmodified.

Change-Id: Ia360405ffb2c1c48e0cc201ac0a0764357996a54
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21466
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Brandon Potter <Brandon.Potter@amd.com>
Maintainer: Gabe Black <gabeblack@google.com>
This commit is contained in:
Gabe Black
2019-10-01 21:15:06 -07:00
parent 211869ea95
commit 6ee86bf497
34 changed files with 424 additions and 338 deletions

View File

@@ -54,10 +54,10 @@ AlphaProcess::AlphaProcess(ProcessParams *params, ObjectFile *objFile)
objFile)
{
fatal_if(params->useArchPT, "Arch page tables not implemented.");
Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
Addr brk_point = roundUp(image.maxAddr(), PageBytes);
// Set up stack. On Alpha, stack goes below the image.
Addr stack_base = objFile->minSegmentAddr() - (409600 + 4096);
Addr stack_base = image.minAddr() - (409600 + 4096);
// Set up region for mmaps.
Addr mmap_end = 0x10000;
@@ -74,13 +74,6 @@ AlphaProcess::AlphaProcess(ProcessParams *params, ObjectFile *objFile)
void
AlphaProcess::argsInit(int intSize, int pageSize)
{
// Patch the ld_bias for dynamic executables.
updateBias();
objFile->loadSegments(initVirtMem);
if (objFile->getInterpreter())
objFile->getInterpreter()->loadSegments(initVirtMem);
std::vector<AuxVector<uint64_t>> auxv;
ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);

View File

@@ -57,13 +57,11 @@ 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);
@@ -111,8 +109,8 @@ AlphaSystem::initState()
System::initState();
// Load program sections into memory
pal->loadSegments(physProxy);
console->loadSegments(physProxy);
pal->buildImage().mask(loadAddrMask).write(physProxy);
console->buildImage().mask(loadAddrMask).write(physProxy);
/**
* Copy the osflags (kernel arguments) into the consoles

View File

@@ -132,8 +132,8 @@ FreebsdArmSystem::initState()
if (ra)
bootReleaseAddr = ra & ~ULL(0x7F);
dtb_file->setLoadOffset(params()->atags_addr + loadAddrOffset);
dtb_file->loadSegments(physProxy);
dtb_file->buildImage().
offset(params()->atags_addr + loadAddrOffset).write(physProxy);
delete dtb_file;
// Kernel boot requirements to set up r0, r1 and r2 in ARMv7

View File

@@ -151,8 +151,8 @@ LinuxArmSystem::initState()
"to DTB file: %s\n", params()->dtb_filename);
}
dtb_file->setLoadOffset(params()->atags_addr + loadAddrOffset);
dtb_file->loadSegments(physProxy);
dtb_file->buildImage().
offset(params()->atags_addr + loadAddrOffset).write(physProxy);
delete dtb_file;
} else {
// Using ATAGS

View File

@@ -75,7 +75,7 @@ ArmProcess32::ArmProcess32(ProcessParams *params, ObjectFile *objFile,
ObjectFile::Arch _arch)
: ArmProcess(params, objFile, _arch)
{
Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
Addr brk_point = roundUp(image.maxAddr(), PageBytes);
Addr stack_base = 0xbf000000L;
Addr max_stack_size = 8 * 1024 * 1024;
Addr next_thread_stack_base = stack_base - max_stack_size;
@@ -89,7 +89,7 @@ ArmProcess64::ArmProcess64(ProcessParams *params, ObjectFile *objFile,
ObjectFile::Arch _arch)
: ArmProcess(params, objFile, _arch)
{
Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
Addr brk_point = roundUp(image.maxAddr(), PageBytes);
Addr stack_base = 0x7fffff0000L;
Addr max_stack_size = 8 * 1024 * 1024;
Addr next_thread_stack_base = stack_base - max_stack_size;
@@ -266,14 +266,6 @@ ArmProcess::argsInit(int pageSize, IntRegIndex spIndex)
//We want 16 byte alignment
uint64_t align = 16;
// Patch the ld_bias for dynamic executables.
updateBias();
// load object file into target memory
objFile->loadSegments(initVirtMem);
if (objFile->getInterpreter())
objFile->getInterpreter()->loadSegments(initVirtMem);
//Setup the auxilliary vectors. These will already have endian conversion.
//Auxilliary vectors are loaded only for elf formatted executables.
ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);

View File

@@ -143,7 +143,7 @@ ArmSystem::initState()
if (bootldr) {
bool isGICv3System = dynamic_cast<Gicv3 *>(getGIC()) != nullptr;
bootldr->loadSegments(physProxy);
bootldr->buildImage().write(physProxy);
inform("Using bootloader at address %#x\n", bootldr->entryPoint());

View File

@@ -65,7 +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->maxSegmentAddr();
Addr brk_point = image.maxAddr();
brk_point = roundUp(brk_point, PageBytes);
// Set up region for mmaps. Start it 1GB above the top of the heap.
@@ -89,14 +89,6 @@ MipsProcess::argsInit(int pageSize)
{
int intSize = sizeof(IntType);
// Patch the ld_bias for dynamic executables.
updateBias();
// load object file into target memory
objFile->loadSegments(initVirtMem);
if (objFile->getInterpreter())
objFile->getInterpreter()->loadSegments(initVirtMem);
std::vector<AuxVector<IntType>> auxv;
ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);

View File

@@ -56,7 +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->maxSegmentAddr();
Addr brk_point = image.maxAddr();
brk_point = roundUp(brk_point, PageBytes);
Addr stack_base = 0xbf000000L;
@@ -95,13 +95,9 @@ PowerProcess::argsInit(int intSize, int pageSize)
//We want 16 byte alignment
uint64_t align = 16;
// Patch the ld_bias for dynamic executables.
updateBias();
// load object file into target memory
objFile->loadSegments(initVirtMem);
if (objFile->getInterpreter())
objFile->getInterpreter()->loadSegments(initVirtMem);
image.write(initVirtMem);
interpImage.write(initVirtMem);
//Setup the auxilliary vectors. These will already have endian conversion.
//Auxilliary vectors are loaded only for elf formatted executables.

View File

@@ -55,7 +55,7 @@ BareMetalRiscvSystem::initState()
RiscvSystem::initState();
// load program sections into memory
if (!bootloader->loadSegments(physProxy)) {
if (!bootloader->buildImage().write(physProxy)) {
warn("could not load sections to memory");
}
}

View File

@@ -75,7 +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->maxSegmentAddr(), PageBytes);
const Addr brk_point = roundUp(image.maxAddr(), PageBytes);
const Addr mmap_end = 0x4000000000000000L;
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
next_thread_stack_base, mmap_end);
@@ -87,7 +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->maxSegmentAddr(), PageBytes);
const Addr brk_point = roundUp(image.maxAddr(), PageBytes);
const Addr mmap_end = 0x40000000L;
memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
next_thread_stack_base, mmap_end);
@@ -123,10 +123,6 @@ RiscvProcess::argsInit(int pageSize)
const int RandomBytes = 16;
const int addrSize = sizeof(IntType);
updateBias();
objFile->loadSegments(initVirtMem);
if (objFile->getInterpreter())
objFile->getInterpreter()->loadSegments(initVirtMem);
ElfObject* elfObject = dynamic_cast<ElfObject*>(objFile);
memState->setStackMin(memState->getStackBase());

View File

@@ -204,14 +204,6 @@ SparcProcess::argsInit(int pageSize)
// maintain double word alignment of the stack pointer.
uint64_t align = 16;
// Patch the ld_bias for dynamic executables.
updateBias();
// load object file into target memory
objFile->loadSegments(initVirtMem);
if (objFile->getInterpreter())
objFile->getInterpreter()->loadSegments(initVirtMem);
enum hardwareCaps
{
M5_HWCAP_SPARC_FLUSH = 1,

View File

@@ -78,7 +78,7 @@ class Sparc32Process : public SparcProcess
Sparc32Process(ProcessParams * params, ObjectFile *objFile)
: SparcProcess(params, objFile, 0)
{
Addr brk_point = objFile->maxSegmentAddr();
Addr brk_point = image.maxAddr();
brk_point = roundUp(brk_point, SparcISA::PageBytes);
// Reserve 8M for main stack.
@@ -122,7 +122,7 @@ class Sparc64Process : public SparcProcess
Sparc64Process(ProcessParams * params, ObjectFile *objFile)
: SparcProcess(params, objFile, 2047)
{
Addr brk_point = objFile->maxSegmentAddr();
Addr brk_point = image.maxAddr();
brk_point = roundUp(brk_point, SparcISA::PageBytes);
Addr max_stack_size = 8 * 1024 * 1024;

View File

@@ -136,25 +136,15 @@ SparcSystem::initState()
// Call the initialisation of the super class
System::initState();
// Load reset binary into memory
reset->setLoadOffset(params()->reset_addr);
reset->loadSegments(physProxy);
// Load the openboot binary
openboot->setLoadOffset(params()->openboot_addr);
openboot->loadSegments(physProxy);
// Load the hypervisor binary
hypervisor->setLoadOffset(params()->hypervisor_addr);
hypervisor->loadSegments(physProxy);
// Load the nvram image
nvram->setLoadOffset(params()->nvram_addr);
nvram->loadSegments(physProxy);
// Load the hypervisor description image
hypervisor_desc->setLoadOffset(params()->hypervisor_desc_addr);
hypervisor_desc->loadSegments(physProxy);
// Load the partition description image
partition_desc->setLoadOffset(params()->partition_desc_addr);
partition_desc->loadSegments(physProxy);
reset->buildImage().offset(params()->reset_addr).write(physProxy);
openboot->buildImage().offset(params()->openboot_addr).write(physProxy);
hypervisor->buildImage().
offset(params()->hypervisor_addr).write(physProxy);
nvram->buildImage().offset(params()->nvram_addr).write(physProxy);
hypervisor_desc->buildImage().
offset(params()->hypervisor_desc_addr).write(physProxy);
partition_desc->buildImage().
offset(params()->partition_desc_addr).write(physProxy);
// @todo any fixup code over writing data in binaries on setting break
// events on functions should happen here.

View File

@@ -136,7 +136,7 @@ X86_64Process::X86_64Process(ProcessParams *params, ObjectFile *objFile,
vsyscallPage.vtimeOffset = 0x400;
vsyscallPage.vgettimeofdayOffset = 0x0;
Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
Addr brk_point = roundUp(image.maxAddr(), PageBytes);
Addr stack_base = 0x7FFFFFFFF000ULL;
Addr max_stack_size = 8 * 1024 * 1024;
Addr next_thread_stack_base = stack_base - max_stack_size;
@@ -175,7 +175,7 @@ I386Process::I386Process(ProcessParams *params, ObjectFile *objFile,
vsyscallPage.vsyscallOffset = 0x400;
vsyscallPage.vsysexitOffset = 0x410;
Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
Addr brk_point = roundUp(image.maxAddr(), PageBytes);
Addr stack_base = _gdtStart;
Addr max_stack_size = 8 * 1024 * 1024;
Addr next_thread_stack_base = stack_base - max_stack_size;
@@ -770,14 +770,6 @@ X86Process::argsInit(int pageSize,
// We want 16 byte alignment
uint64_t align = 16;
// Patch the ld_bias for dynamic executables.
updateBias();
// load object file into target memory
objFile->loadSegments(initVirtMem);
if (objFile->getInterpreter())
objFile->getInterpreter()->loadSegments(initVirtMem);
enum X86CpuFeature {
X86_OnboardFPU = 1 << 0,
X86_VirtualModeExtensions = 1 << 1,

View File

@@ -76,6 +76,7 @@ Source('loader/aout_object.cc')
Source('loader/dtb_object.cc')
Source('loader/ecoff_object.cc')
Source('loader/elf_object.cc')
Source('loader/memory_image.cc')
Source('loader/object_file.cc')
Source('loader/raw_object.cc')
Source('loader/symtab.cc')

View File

@@ -58,17 +58,23 @@ AoutObject::AoutObject(const string &_filename,
: ObjectFile(_filename, _len, _data, _arch, _opSys)
{
execHdr = (aout_exechdr *)fileData;
entry = execHdr->entry;
}
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);
MemoryImage
AoutObject::buildImage() const
{
MemoryImage image({
{ "text", N_TXTADDR(*execHdr),
fileData + N_TXTOFF(*execHdr), execHdr->tsize },
{ "data", N_DATADDR(*execHdr),
fileData + N_DATOFF(*execHdr), execHdr->dsize },
{ "bss", N_BSSADDR(*execHdr), nullptr, execHdr->bsize}
});
for (auto &seg: segments)
DPRINTFR(Loader, "%s\n", *seg);
for (auto &seg: image.segments())
DPRINTFR(Loader, "%s\n", seg);
return image;
}

View File

@@ -48,13 +48,14 @@ class AoutObject : public ObjectFile
public:
virtual ~AoutObject() {}
virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addr_mask = maxAddr);
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0,
Addr addr_mask = maxAddr);
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addr_mask = maxAddr);
MemoryImage buildImage() const override;
bool loadAllSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask = MaxAddr) override;
bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
static ObjectFile *tryFile(const std::string &fname,
size_t len, uint8_t *data);

View File

@@ -53,10 +53,8 @@ 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),
data(new Segment{ "data", 0, fileData, len })
: ObjectFile(_filename, _len, _data, _arch, _opSys)
{
segments.emplace_back(data);
fileDataMmapped = true;
}
@@ -131,9 +129,6 @@ DtbObject::addBootCmdLine(const char* _args, size_t len)
return false;
}
data->size = newLen;
data->data = fdt_buf_w_space;
// clean up old buffer and set to new fdt blob
munmap(fileData, this->len);
fileData = fdt_buf_w_space;
@@ -164,6 +159,12 @@ DtbObject::findReleaseAddr()
return rel_addr;
}
MemoryImage
DtbObject::buildImage() const
{
return {{"data", 0, fileData, len}};
}
bool
DtbObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset,
Addr addr_mask)

View File

@@ -40,50 +40,50 @@
*/
class DtbObject : public ObjectFile
{
protected:
DtbObject(const std::string &_filename, size_t _len, uint8_t *_data,
Arch _arch, OpSys _opSys);
protected:
DtbObject(const std::string &_filename, size_t _len, uint8_t *_data,
Arch _arch, OpSys _opSys);
/** Bool marking if this dtb file has replaced the original
* read in DTB file with a new modified buffer
*/
bool fileDataMmapped;
/** Bool marking if this dtb file has replaced the original
* read in DTB file with a new modified buffer
*/
bool fileDataMmapped;
Segment *data;
public:
virtual ~DtbObject();
public:
virtual ~DtbObject();
/** Adds the passed in Command Line options for the kernel
* to the proper location in the device tree.
* @param _args command line to append
* @param len length of the command line string
* @return returns true on success, false otherwise
*/
bool addBootCmdLine(const char* _args, size_t len);
/** Adds the passed in Command Line options for the kernel
* to the proper location in the device tree.
* @param _args command line to append
* @param len length of the command line string
* @return returns true on success, false otherwise
*/
bool addBootCmdLine(const char* _args, size_t len);
/** Parse the DTB file enough to find the provided release
* address and return it.
* @return release address for SMP boot
*/
Addr findReleaseAddr();
/** Parse the DTB file enough to find the provided release
* address and return it.
* @return release address for SMP boot
*/
Addr findReleaseAddr();
MemoryImage buildImage() const override;
bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addrMask = maxAddr);
bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addrMask = maxAddr);
bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addrMask = maxAddr);
bool loadAllSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addrMask=MaxAddr) override;
bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addrMask=MaxAddr) override;
bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addrMask=MaxAddr) override;
/** Static function that tries to load file as a
* flattened device tree blob.
* @param fname path to file
* @param len length of file
* @param data mmap'ed data buffer containing file contents
* @return ObjectFile representing closest match of file type
*/
static ObjectFile *tryFile(const std::string &fname,
size_t len, uint8_t *data);
/** Static function that tries to load file as a
* flattened device tree blob.
* @param fname path to file
* @param len length of file
* @param data mmap'ed data buffer containing file contents
* @return ObjectFile representing closest match of file type
*/
static ObjectFile *tryFile(const std::string &fname,
size_t len, uint8_t *data);
};
#endif //__DTB_OBJECT_HH__

View File

@@ -72,15 +72,23 @@ EcoffObject::EcoffObject(const string &_filename, size_t _len, uint8_t *_data,
aoutHdr = &(execHdr->a);
entry = aoutHdr->entry;
}
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);
MemoryImage
EcoffObject::buildImage() const
{
MemoryImage image({
{ "text", aoutHdr->text_start,
fileData + ECOFF_TXTOFF(execHdr), aoutHdr->tsize },
{ "data", aoutHdr->data_start,
fileData + ECOFF_DATOFF(execHdr), aoutHdr->dsize },
{ "bss", aoutHdr->bss_start, nullptr, aoutHdr->bsize }
});
for (auto &seg: segments)
DPRINTFR(Loader, "%s\n", *seg);
for (auto &seg: image.segments())
DPRINTFR(Loader, "%s\n", seg);
return image;
}
bool

View File

@@ -51,12 +51,14 @@ class EcoffObject : public ObjectFile
public:
virtual ~EcoffObject() {}
virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addr_mask = maxAddr);
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addr_mask = maxAddr);
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addr_mask = maxAddr);
MemoryImage buildImage() const override;
bool loadAllSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
static ObjectFile *tryFile(const std::string &fname,
size_t len, uint8_t *data);

View File

@@ -339,26 +339,25 @@ ElfObject::ElfObject(const std::string &_filename, size_t _len,
section = elf_getscn(elf, ++sec_idx);
}
addSegment(name, phdr.p_paddr, fileData + phdr.p_offset,
phdr.p_filesz);
image.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);
image.addSegment(name + "(uninitialized)",
phdr.p_paddr + phdr.p_filesz, nullptr, uninitialized);
}
}
// should have found at least one loadable segment
warn_if(segments.empty(),
"No loadable segments in '%s'. ELF file corrupted?\n",
filename);
warn_if(image.segments().empty(),
"No loadable segments in '%s'. ELF file corrupted?\n", filename);
for (auto &seg: segments)
DPRINTFR(Loader, "%s\n", *seg);
for (auto &seg: image.segments())
DPRINTFR(Loader, "%s\n", seg);
elf_end(elf);
@@ -518,6 +517,5 @@ ElfObject::updateBias(Addr bias_addr)
entry += bias_addr;
// Patch segments with the bias_addr.
for (auto &segment : segments)
segment->base += bias_addr;
image.offset(bias_addr);
}

View File

@@ -86,34 +86,30 @@ class ElfObject : public ObjectFile
void getSections();
bool sectionExists(std::string sec);
MemoryImage image;
public:
virtual ~ElfObject() {}
virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addr_mask = maxAddr)
override;
MemoryImage buildImage() const override { return image; }
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addr_mask = maxAddr)
override;
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addr_mask = maxAddr)
override;
virtual bool loadWeakSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addr_mask = maxAddr)
override;
bool loadAllSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
bool loadWeakSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
virtual ObjectFile *getInterpreter() const override
{ return interpreter; }
virtual Addr bias() const override { return ldBias; }
virtual bool relocatable() const override { return relocate; }
virtual Addr mapSize() const override { return ldMax - ldMin; }
virtual void updateBias(Addr bias_addr) override;
ObjectFile *getInterpreter() const override { return interpreter; }
Addr bias() const override { return ldBias; }
bool relocatable() const override { return relocate; }
Addr mapSize() const override { return ldMax - ldMin; }
void updateBias(Addr bias_addr) override;
virtual bool hasTLS() override { return sectionExists(".tbss"); }
bool hasTLS() override { return sectionExists(".tbss"); }
static ObjectFile *tryFile(const std::string &fname,
size_t len, uint8_t *data,

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2002-2004 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
* Steve Reinhardt
*/
#include "base/loader/memory_image.hh"
#include "mem/port_proxy.hh"
bool
MemoryImage::writeSegment(const Segment &seg, const PortProxy &proxy) const
{
if (seg.size != 0) {
if (seg.data) {
proxy.writeBlob(seg.base, seg.data, seg.size);
} else {
// no image: must be bss
proxy.memsetBlob(seg.base, 0, seg.size);
}
}
return true;
}
bool
MemoryImage::write(const PortProxy &proxy) const
{
for (auto &seg: _segments)
if (!writeSegment(seg, proxy))
return false;
return true;
}
MemoryImage &
MemoryImage::move(std::function<Addr(Addr)> mapper)
{
for (auto &seg: _segments)
seg.base = mapper(seg.base);
return *this;
}

View File

@@ -0,0 +1,146 @@
/*
* Copyright (c) 2002-2004 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
* Steve Reinhardt
*/
#ifndef __BASE_LOADER_MEMORY_IMAGE_HH__
#define __BASE_LOADER_MEMORY_IMAGE_HH__
#include <functional>
#include <initializer_list>
#include <memory>
#include <string>
#include <vector>
#include "base/logging.hh"
#include "base/types.hh"
class PortProxy;
class Process;
class ProcessParams;
class SymbolTable;
class MemoryImage
{
public:
struct Segment
{
std::string name;
Addr base;
uint8_t *data;
size_t size;
};
MemoryImage() {}
MemoryImage(std::initializer_list<Segment> new_segs)
{
for (auto &seg: new_segs)
addSegment(seg);
}
private:
std::vector<Segment> _segments;
bool writeSegment(const Segment &seg, const PortProxy &proxy) const;
public:
const std::vector<Segment> &
segments() const
{
return _segments;
}
void
addSegment(const Segment &seg)
{
_segments.emplace_back(seg);
}
void
addSegment(std::string name, Addr base, uint8_t *data, size_t size)
{
_segments.push_back(Segment({name, base, data, size}));
}
bool write(const PortProxy &proxy) const;
MemoryImage &move(std::function<Addr(Addr)> mapper);
MemoryImage &
offset(Addr by)
{
return move([by](Addr a){ return by + a; });
}
MemoryImage &
mask(Addr m) {
return move([m](Addr a) { return a & m; });
}
Addr
maxAddr() const
{
Addr max = 0;
for (auto &seg: _segments) {
Addr end = seg.base + seg.size;
if (end > max)
max = end;
}
return max;
}
Addr
minAddr() 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;
}
};
static inline std::ostream &
operator << (std::ostream &os, const MemoryImage::Segment &seg)
{
ccprintf(os, "%s: %#x %d", seg.name, seg.base, seg.size);
return os;
}
#endif // __BASE_LOADER_MEMORY_IMAGE_HH__

View File

@@ -70,31 +70,6 @@ ObjectFile::~ObjectFile()
}
bool
ObjectFile::loadSegment(Segment *seg, const PortProxy &mem_proxy)
{
if (seg->size != 0) {
Addr addr = (seg->base & loadMask) + loadOffset;
if (seg->data) {
mem_proxy.writeBlob(addr, seg->data, seg->size);
} else {
// no image: must be bss
mem_proxy.memsetBlob(addr, 0, seg->size);
}
}
return true;
}
bool
ObjectFile::loadSegments(const PortProxy &proxy)
{
for (auto &seg: segments)
if (!loadSegment(seg.get(), proxy))
return false;
return true;
}
namespace
{

View File

@@ -37,6 +37,7 @@
#include <string>
#include <vector>
#include "base/loader/memory_image.hh"
#include "base/logging.hh"
#include "base/types.hh"
@@ -74,14 +75,10 @@ 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;
@@ -92,16 +89,16 @@ class ObjectFile
public:
virtual ~ObjectFile();
virtual bool loadSegments(const PortProxy &mem_proxy);
virtual MemoryImage buildImage() const = 0;
virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset=0, Addr mask=maxAddr) = 0;
Addr offset=0, Addr mask=MaxAddr) = 0;
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset=0, Addr mask=maxAddr) = 0;
Addr offset=0, Addr mask=MaxAddr) = 0;
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr mask=maxAddr) = 0;
Addr offset=0, Addr mask=MaxAddr) = 0;
virtual bool loadWeakSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr mask=maxAddr)
Addr offset=0, Addr mask=MaxAddr)
{ return false; }
virtual ObjectFile *getInterpreter() const { return nullptr; }
@@ -117,77 +114,12 @@ class ObjectFile
Arch getArch() const { return arch; }
OpSys getOpSys() const { return opSys; }
struct Segment
{
std::string name;
Addr base;
uint8_t *data;
size_t size;
};
protected:
Addr entry;
std::vector<std::unique_ptr<Segment>> segments;
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
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 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
* an object file when tryLoaders is called. If they can't because they
@@ -221,13 +153,6 @@ 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);

View File

@@ -43,10 +43,14 @@ 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),
data(new Segment{ "data", 0, fileData, len })
: ObjectFile(_filename, _len, _data, _arch, _opSys)
{
segments.emplace_back(data);
}
MemoryImage
RawObject::buildImage() const
{
return {{ "data", 0, fileData, len }};
}
bool

View File

@@ -39,18 +39,17 @@ class RawObject: public ObjectFile
RawObject(const std::string &_filename, size_t _len,
uint8_t *_data, Arch _arch, OpSys _opSys);
Segment *data;
public:
virtual ~RawObject() {}
virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addr_mask = maxAddr);
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0,
Addr addr_mask = maxAddr);
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0,
Addr offset = 0, Addr addr_mask = maxAddr);
MemoryImage buildImage() const override;
bool loadAllSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
Addr offset=0, Addr addr_mask=MaxAddr) override;
static ObjectFile *tryFile(const std::string &fname, size_t len,
uint8_t *data);

View File

@@ -129,6 +129,8 @@ Process::Process(ProcessParams *params, EmulationPageTable *pTable,
exitGroup = new bool();
sigchld = new bool();
image = objFile->buildImage();
if (!debugSymbolTable) {
debugSymbolTable = new SymbolTable();
if (!objFile->loadGlobalSymbols(debugSymbolTable) ||
@@ -270,6 +272,16 @@ Process::revokeThreadContext(int context_id)
warn("Unable to find thread context to revoke");
}
void
Process::init()
{
// Patch the ld_bias for dynamic executables.
updateBias();
if (objFile->getInterpreter())
interpImage = objFile->getInterpreter()->buildImage();
}
void
Process::initState()
{
@@ -283,6 +295,10 @@ Process::initState()
tc->activate();
pTable->initState();
// load object file into target memory
image.write(initVirtMem);
interpImage.write(initVirtMem);
}
DrainState

View File

@@ -41,6 +41,7 @@
#include <vector>
#include "arch/registers.hh"
#include "base/loader/memory_image.hh"
#include "base/statistics.hh"
#include "base/types.hh"
#include "config/the_isa.hh"
@@ -69,6 +70,7 @@ class Process : public SimObject
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
void init() override;
void initState() override;
DrainState drain() override;
@@ -182,6 +184,8 @@ class Process : public SimObject
SETranslatingPortProxy initVirtMem; // memory proxy for initial image load
ObjectFile *objFile;
MemoryImage image;
MemoryImage interpImage;
std::vector<std::string> argv;
std::vector<std::string> envp;
std::string executable;

View File

@@ -1886,17 +1886,14 @@ mmapImpl(SyscallDesc *desc, int num, ThreadContext *tc, bool is_mmap2)
// executing inside the loader by checking the program counter value.
// XXX: with multiprogrammed workloads or multi-node configurations,
// this will not work since there is a single global symbol table.
ObjectFile *interpreter = p->getInterpreter();
if (interpreter) {
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 (p->interpImage.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->minSegmentAddr(), start);
}
if (lib) {
lib->loadAllSymbols(debugSymbolTable,
lib->buildImage().minAddr(), start);
}
}

View File

@@ -152,16 +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);
kernelImage = kernel->buildImage();
// setup entry points
kernelStart = kernel->minSegmentAddr();
kernelEnd = kernel->maxSegmentAddr();
kernelStart = kernelImage.minAddr();
kernelEnd = kernelImage.maxAddr();
kernelEntry = kernel->entryPoint();
// If load_addr_mask is set to 0x0, then auto-calculate
@@ -170,9 +170,12 @@ System::System(Params *p)
if (loadAddrMask == 0) {
Addr shift_amt = findMsbSet(kernelEnd - kernelStart) + 1;
loadAddrMask = ((Addr)1 << shift_amt) - 1;
kernel->setLoadMask(loadAddrMask);
}
kernelImage.move([this](Addr a) {
return (a & loadAddrMask) + loadAddrOffset;
});
// load symbols
if (!kernel->loadGlobalSymbols(kernelSymtab))
fatal("could not load kernel symbols\n");
@@ -195,8 +198,6 @@ 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);
}
}
@@ -316,25 +317,24 @@ System::initState()
/**
* Load the kernel code into memory
*/
auto mapper = [this](Addr a) {
return (a & loadAddrMask) + loadAddrOffset;
};
if (params()->kernel != "") {
if (params()->kernel_addr_check) {
// Validate kernel mapping before loading binary
if (!(isMemAddr((kernelStart & loadAddrMask) +
loadAddrOffset) &&
isMemAddr((kernelEnd & loadAddrMask) +
loadAddrOffset))) {
if (!isMemAddr(mapper(kernelStart)) ||
!isMemAddr(mapper(kernelEnd))) {
fatal("Kernel is mapped to invalid location (not memory). "
"kernelStart 0x(%x) - kernelEnd 0x(%x) %#x:%#x\n",
kernelStart,
kernelEnd, (kernelStart & loadAddrMask) +
loadAddrOffset,
(kernelEnd & loadAddrMask) + loadAddrOffset);
kernelStart, kernelEnd,
mapper(kernelStart), mapper(kernelEnd));
}
}
// Load program sections into memory
kernel->loadSegments(physProxy);
kernelImage.write(physProxy);
for (const auto &extra_kernel : kernelExtras)
extra_kernel->loadSegments(physProxy);
extra_kernel->buildImage().move(mapper).write(physProxy);
DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd);

View File

@@ -53,6 +53,7 @@
#include <vector>
#include "arch/isa_traits.hh"
#include "base/loader/memory_image.hh"
#include "base/loader/symtab.hh"
#include "base/statistics.hh"
#include "config/the_isa.hh"
@@ -224,6 +225,7 @@ class System : public SimObject
/** Object pointer for the kernel code */
ObjectFile *kernel;
MemoryImage kernelImage;
/** Additional object files */
std::vector<ObjectFile *> kernelExtras;