base: support dynamic loading of Linux ELF objects in SE mode
This commit is contained in:
parent
4fc69db8f8
commit
9b4249410e
|
@ -67,6 +67,9 @@ AlphaLiveProcess::AlphaLiveProcess(LiveProcessParams *params,
|
||||||
void
|
void
|
||||||
AlphaLiveProcess::argsInit(int intSize, int pageSize)
|
AlphaLiveProcess::argsInit(int intSize, int pageSize)
|
||||||
{
|
{
|
||||||
|
// Patch the ld_bias for dynamic executables.
|
||||||
|
updateBias();
|
||||||
|
|
||||||
objFile->loadSections(initVirtMem);
|
objFile->loadSections(initVirtMem);
|
||||||
|
|
||||||
typedef AuxVector<uint64_t> auxv_t;
|
typedef AuxVector<uint64_t> auxv_t;
|
||||||
|
@ -88,6 +91,10 @@ AlphaLiveProcess::argsInit(int intSize, int pageSize)
|
||||||
auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable()));
|
auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable()));
|
||||||
DPRINTF(Loader, "auxv at PHDR %08p\n", elfObject->programHeaderTable());
|
DPRINTF(Loader, "auxv at PHDR %08p\n", elfObject->programHeaderTable());
|
||||||
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
||||||
|
// This is the base address of the ELF interpreter; it should be
|
||||||
|
// zero for static executables or contain the base address for
|
||||||
|
// dynamic executables.
|
||||||
|
auxv.push_back(auxv_t(M5_AT_BASE, getBias()));
|
||||||
auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint()));
|
auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint()));
|
||||||
auxv.push_back(auxv_t(M5_AT_UID, uid()));
|
auxv.push_back(auxv_t(M5_AT_UID, uid()));
|
||||||
auxv.push_back(auxv_t(M5_AT_EUID, euid()));
|
auxv.push_back(auxv_t(M5_AT_EUID, euid()));
|
||||||
|
@ -163,7 +170,7 @@ AlphaLiveProcess::argsInit(int intSize, int pageSize)
|
||||||
setSyscallArg(tc, 1, argv_array_base);
|
setSyscallArg(tc, 1, argv_array_base);
|
||||||
tc->setIntReg(StackPointerReg, stack_min);
|
tc->setIntReg(StackPointerReg, stack_min);
|
||||||
|
|
||||||
tc->pcState(objFile->entryPoint());
|
tc->pcState(getStartPC());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -156,6 +156,9 @@ ArmLiveProcess::argsInit(int pageSize, IntRegIndex spIndex)
|
||||||
//We want 16 byte alignment
|
//We want 16 byte alignment
|
||||||
uint64_t align = 16;
|
uint64_t align = 16;
|
||||||
|
|
||||||
|
// Patch the ld_bias for dynamic executables.
|
||||||
|
updateBias();
|
||||||
|
|
||||||
// load object file into target memory
|
// load object file into target memory
|
||||||
objFile->loadSections(initVirtMem);
|
objFile->loadSections(initVirtMem);
|
||||||
|
|
||||||
|
@ -225,10 +228,10 @@ ArmLiveProcess::argsInit(int pageSize, IntRegIndex spIndex)
|
||||||
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
|
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
|
||||||
// This is the number of program headers from the original elf file.
|
// This is the number of program headers from the original elf file.
|
||||||
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
||||||
//This is the address of the elf "interpreter", It should be set
|
// This is the base address of the ELF interpreter; it should be
|
||||||
//to 0 for regular executables. It should be something else
|
// zero for static executables or contain the base address for
|
||||||
//(not sure what) for dynamic libraries.
|
// dynamic executables.
|
||||||
auxv.push_back(auxv_t(M5_AT_BASE, 0));
|
auxv.push_back(auxv_t(M5_AT_BASE, getBias()));
|
||||||
//XXX Figure out what this should be.
|
//XXX Figure out what this should be.
|
||||||
auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
|
auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
|
||||||
//The entry point to the program
|
//The entry point to the program
|
||||||
|
@ -392,7 +395,7 @@ ArmLiveProcess::argsInit(int pageSize, IntRegIndex spIndex)
|
||||||
pc.nextThumb(pc.thumb());
|
pc.nextThumb(pc.thumb());
|
||||||
pc.aarch64(arch == ObjectFile::Arm64);
|
pc.aarch64(arch == ObjectFile::Arm64);
|
||||||
pc.nextAArch64(pc.aarch64());
|
pc.nextAArch64(pc.aarch64());
|
||||||
pc.set(objFile->entryPoint() & ~mask(1));
|
pc.set(getStartPC() & ~mask(1));
|
||||||
tc->pcState(pc);
|
tc->pcState(pc);
|
||||||
|
|
||||||
//Align the "stack_min" to a page boundary.
|
//Align the "stack_min" to a page boundary.
|
||||||
|
|
|
@ -78,6 +78,9 @@ MipsLiveProcess::argsInit(int pageSize)
|
||||||
{
|
{
|
||||||
int intSize = sizeof(IntType);
|
int intSize = sizeof(IntType);
|
||||||
|
|
||||||
|
// Patch the ld_bias for dynamic executables.
|
||||||
|
updateBias();
|
||||||
|
|
||||||
// load object file into target memory
|
// load object file into target memory
|
||||||
objFile->loadSections(initVirtMem);
|
objFile->loadSections(initVirtMem);
|
||||||
|
|
||||||
|
@ -100,6 +103,10 @@ MipsLiveProcess::argsInit(int pageSize)
|
||||||
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
|
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
|
||||||
// This is the number of program headers from the original elf file.
|
// This is the number of program headers from the original elf file.
|
||||||
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
||||||
|
// This is the base address of the ELF interpreter; it should be
|
||||||
|
// zero for static executables or contain the base address for
|
||||||
|
// dynamic executables.
|
||||||
|
auxv.push_back(auxv_t(M5_AT_BASE, getBias()));
|
||||||
//The entry point to the program
|
//The entry point to the program
|
||||||
auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint()));
|
auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint()));
|
||||||
//Different user and group IDs
|
//Different user and group IDs
|
||||||
|
@ -177,7 +184,7 @@ MipsLiveProcess::argsInit(int pageSize)
|
||||||
setSyscallArg(tc, 1, argv_array_base);
|
setSyscallArg(tc, 1, argv_array_base);
|
||||||
tc->setIntReg(StackPointerReg, stack_min);
|
tc->setIntReg(StackPointerReg, stack_min);
|
||||||
|
|
||||||
tc->pcState(objFile->entryPoint());
|
tc->pcState(getStartPC());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,9 @@ PowerLiveProcess::argsInit(int intSize, int pageSize)
|
||||||
//We want 16 byte alignment
|
//We want 16 byte alignment
|
||||||
uint64_t align = 16;
|
uint64_t align = 16;
|
||||||
|
|
||||||
|
// Patch the ld_bias for dynamic executables.
|
||||||
|
updateBias();
|
||||||
|
|
||||||
// load object file into target memory
|
// load object file into target memory
|
||||||
objFile->loadSections(initVirtMem);
|
objFile->loadSections(initVirtMem);
|
||||||
|
|
||||||
|
@ -108,11 +111,10 @@ PowerLiveProcess::argsInit(int intSize, int pageSize)
|
||||||
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
|
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
|
||||||
// This is the number of program headers from the original elf file.
|
// This is the number of program headers from the original elf file.
|
||||||
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
||||||
//This is the address of the elf "interpreter", It should be set
|
// This is the base address of the ELF interpreter; it should be
|
||||||
//to 0 for regular executables. It should be something else
|
// zero for static executables or contain the base address for
|
||||||
//(not sure what) for dynamic libraries.
|
// dynamic executables.
|
||||||
auxv.push_back(auxv_t(M5_AT_BASE, 0));
|
auxv.push_back(auxv_t(M5_AT_BASE, getBias()));
|
||||||
|
|
||||||
//XXX Figure out what this should be.
|
//XXX Figure out what this should be.
|
||||||
auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
|
auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
|
||||||
//The entry point to the program
|
//The entry point to the program
|
||||||
|
@ -255,7 +257,7 @@ PowerLiveProcess::argsInit(int intSize, int pageSize)
|
||||||
//Set the stack pointer register
|
//Set the stack pointer register
|
||||||
tc->setIntReg(StackPointerReg, stack_min);
|
tc->setIntReg(StackPointerReg, stack_min);
|
||||||
|
|
||||||
tc->pcState(objFile->entryPoint());
|
tc->pcState(getStartPC());
|
||||||
|
|
||||||
//Align the "stack_min" to a page boundary.
|
//Align the "stack_min" to a page boundary.
|
||||||
stack_min = roundDown(stack_min, pageSize);
|
stack_min = roundDown(stack_min, pageSize);
|
||||||
|
|
|
@ -203,6 +203,9 @@ SparcLiveProcess::argsInit(int pageSize)
|
||||||
// maintain double word alignment of the stack pointer.
|
// maintain double word alignment of the stack pointer.
|
||||||
uint64_t align = 16;
|
uint64_t align = 16;
|
||||||
|
|
||||||
|
// Patch the ld_bias for dynamic executables.
|
||||||
|
updateBias();
|
||||||
|
|
||||||
// load object file into target memory
|
// load object file into target memory
|
||||||
objFile->loadSections(initVirtMem);
|
objFile->loadSections(initVirtMem);
|
||||||
|
|
||||||
|
@ -245,10 +248,10 @@ SparcLiveProcess::argsInit(int pageSize)
|
||||||
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
|
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
|
||||||
// This is the number of program headers from the original elf file.
|
// This is the number of program headers from the original elf file.
|
||||||
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
||||||
// This is the address of the elf "interpreter", It should be set
|
// This is the base address of the ELF interpreter; it should be
|
||||||
// to 0 for regular executables. It should be something else
|
// zero for static executables or contain the base address for
|
||||||
// (not sure what) for dynamic libraries.
|
// dynamic executables.
|
||||||
auxv.push_back(auxv_t(M5_AT_BASE, 0));
|
auxv.push_back(auxv_t(M5_AT_BASE, getBias()));
|
||||||
// This is hardwired to 0 in the elf loading code in the kernel
|
// This is hardwired to 0 in the elf loading code in the kernel
|
||||||
auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
|
auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
|
||||||
// The entry point to the program
|
// The entry point to the program
|
||||||
|
@ -402,7 +405,7 @@ SparcLiveProcess::argsInit(int pageSize)
|
||||||
// don't have anything like that, it should be set to 0.
|
// don't have anything like that, it should be set to 0.
|
||||||
tc->setIntReg(1, 0);
|
tc->setIntReg(1, 0);
|
||||||
|
|
||||||
tc->pcState(objFile->entryPoint());
|
tc->pcState(getStartPC());
|
||||||
|
|
||||||
// Align the "stack_min" to a page boundary.
|
// Align the "stack_min" to a page boundary.
|
||||||
stack_min = roundDown(stack_min, pageSize);
|
stack_min = roundDown(stack_min, pageSize);
|
||||||
|
|
|
@ -756,6 +756,9 @@ X86LiveProcess::argsInit(int pageSize,
|
||||||
//We want 16 byte alignment
|
//We want 16 byte alignment
|
||||||
uint64_t align = 16;
|
uint64_t align = 16;
|
||||||
|
|
||||||
|
// Patch the ld_bias for dynamic executables.
|
||||||
|
updateBias();
|
||||||
|
|
||||||
// load object file into target memory
|
// load object file into target memory
|
||||||
objFile->loadSections(initVirtMem);
|
objFile->loadSections(initVirtMem);
|
||||||
|
|
||||||
|
@ -798,8 +801,10 @@ X86LiveProcess::argsInit(int pageSize,
|
||||||
X86_IA64Processor = 1 << 30
|
X86_IA64Processor = 1 << 30
|
||||||
};
|
};
|
||||||
|
|
||||||
// Setup the auxilliary vectors. These will already have endian conversion.
|
// Setup the auxiliary vectors. These will already have endian
|
||||||
// Auxilliary vectors are loaded only for elf formatted executables.
|
// conversion. Auxiliary vectors are loaded only for elf formatted
|
||||||
|
// executables; the auxv is responsible for passing information from
|
||||||
|
// the OS to the interpreter.
|
||||||
ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);
|
ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);
|
||||||
if (elfObject) {
|
if (elfObject) {
|
||||||
uint64_t features =
|
uint64_t features =
|
||||||
|
@ -842,18 +847,17 @@ X86LiveProcess::argsInit(int pageSize,
|
||||||
//Frequency at which times() increments
|
//Frequency at which times() increments
|
||||||
//Defined to be 100 in the kernel source.
|
//Defined to be 100 in the kernel source.
|
||||||
auxv.push_back(auxv_t(M5_AT_CLKTCK, 100));
|
auxv.push_back(auxv_t(M5_AT_CLKTCK, 100));
|
||||||
// For statically linked executables, this is the virtual address of the
|
// This is the virtual address of the program header tables if they
|
||||||
// program header tables if they appear in the executable image
|
// appear in the executable image.
|
||||||
auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable()));
|
auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable()));
|
||||||
// This is the size of a program header entry from the elf file.
|
// This is the size of a program header entry from the elf file.
|
||||||
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
|
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
|
||||||
// This is the number of program headers from the original elf file.
|
// This is the number of program headers from the original elf file.
|
||||||
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
|
||||||
//This is the address of the elf "interpreter", It should be set
|
// This is the base address of the ELF interpreter; it should be
|
||||||
//to 0 for regular executables. It should be something else
|
// zero for static executables or contain the base address for
|
||||||
//(not sure what) for dynamic libraries.
|
// dynamic executables.
|
||||||
auxv.push_back(auxv_t(M5_AT_BASE, 0));
|
auxv.push_back(auxv_t(M5_AT_BASE, getBias()));
|
||||||
|
|
||||||
//XXX Figure out what this should be.
|
//XXX Figure out what this should be.
|
||||||
auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
|
auxv.push_back(auxv_t(M5_AT_FLAGS, 0));
|
||||||
//The entry point to the program
|
//The entry point to the program
|
||||||
|
@ -1014,7 +1018,7 @@ X86LiveProcess::argsInit(int pageSize,
|
||||||
|
|
||||||
// There doesn't need to be any segment base added in since we're dealing
|
// There doesn't need to be any segment base added in since we're dealing
|
||||||
// with the flat segmentation model.
|
// with the flat segmentation model.
|
||||||
tc->pcState(objFile->entryPoint());
|
tc->pcState(getStartPC());
|
||||||
|
|
||||||
//Align the "stack_min" to a page boundary.
|
//Align the "stack_min" to a page boundary.
|
||||||
stack_min = roundDown(stack_min, pageSize);
|
stack_min = roundDown(stack_min, pageSize);
|
||||||
|
|
|
@ -41,22 +41,30 @@
|
||||||
* Ali Saidi
|
* Ali Saidi
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "base/loader/elf_object.hh"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "base/loader/elf_object.hh"
|
|
||||||
#include "base/loader/symtab.hh"
|
|
||||||
#include "base/bitfield.hh"
|
#include "base/bitfield.hh"
|
||||||
|
#include "base/loader/symtab.hh"
|
||||||
#include "base/misc.hh"
|
#include "base/misc.hh"
|
||||||
#include "base/trace.hh"
|
#include "base/trace.hh"
|
||||||
#include "debug/Loader.hh"
|
#include "debug/Loader.hh"
|
||||||
#include "sim/byteswap.hh"
|
|
||||||
#include "gelf.h"
|
#include "gelf.h"
|
||||||
|
#include "sim/byteswap.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
ObjectFile *
|
ObjectFile *
|
||||||
ElfObject::tryFile(const string &fname, size_t len, uint8_t *data)
|
ElfObject::tryFile(const string &fname, size_t len, uint8_t *data,
|
||||||
|
bool skip_interp_check)
|
||||||
{
|
{
|
||||||
Elf *elf;
|
Elf *elf;
|
||||||
GElf_Ehdr ehdr;
|
GElf_Ehdr ehdr;
|
||||||
|
@ -243,6 +251,41 @@ ElfObject::tryFile(const string &fname, size_t len, uint8_t *data)
|
||||||
result->_programHeaderTable = 0;
|
result->_programHeaderTable = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (!skip_interp_check) {
|
||||||
|
for (int i = 0; i < ehdr.e_phnum; i++) {
|
||||||
|
GElf_Phdr phdr;
|
||||||
|
M5_VAR_USED void *check_p = gelf_getphdr(elf, i, &phdr);
|
||||||
|
assert(check_p != nullptr);
|
||||||
|
|
||||||
|
if (phdr.p_type != PT_INTERP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char *interp_path = (char*)data + phdr.p_offset;
|
||||||
|
int fd = open(interp_path, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
fatal("Unable to open dynamic executable's "
|
||||||
|
"interpreter.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stat sb;
|
||||||
|
M5_VAR_USED int check_i = fstat(fd, &sb);
|
||||||
|
assert(check_i == 0);
|
||||||
|
|
||||||
|
void *mm = mmap(nullptr, sb.st_size, PROT_READ,
|
||||||
|
MAP_PRIVATE, fd, 0);
|
||||||
|
assert(mm != MAP_FAILED);
|
||||||
|
::close(fd);
|
||||||
|
|
||||||
|
uint8_t *interp_image = (uint8_t*)mm;
|
||||||
|
ObjectFile *obj = tryFile(interp_path, sb.st_size,
|
||||||
|
interp_image, true);
|
||||||
|
assert(obj != nullptr);
|
||||||
|
result->interpreter = dynamic_cast<ElfObject*>(obj);
|
||||||
|
assert(result->interpreter != nullptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
elf_end(elf);
|
elf_end(elf);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -252,8 +295,10 @@ ElfObject::tryFile(const string &fname, size_t len, uint8_t *data)
|
||||||
ElfObject::ElfObject(const string &_filename, size_t _len, uint8_t *_data,
|
ElfObject::ElfObject(const string &_filename, size_t _len, uint8_t *_data,
|
||||||
Arch _arch, OpSys _opSys)
|
Arch _arch, OpSys _opSys)
|
||||||
: ObjectFile(_filename, _len, _data, _arch, _opSys),
|
: ObjectFile(_filename, _len, _data, _arch, _opSys),
|
||||||
_programHeaderTable(0), _programHeaderSize(0), _programHeaderCount(0)
|
_programHeaderTable(0), _programHeaderSize(0), _programHeaderCount(0),
|
||||||
|
interpreter(nullptr), ldBias(0), relocate(true),
|
||||||
|
ldMin(std::numeric_limits<Addr>::max()),
|
||||||
|
ldMax(std::numeric_limits<Addr>::min())
|
||||||
{
|
{
|
||||||
Elf *elf;
|
Elf *elf;
|
||||||
GElf_Ehdr ehdr;
|
GElf_Ehdr ehdr;
|
||||||
|
@ -326,6 +371,9 @@ ElfObject::ElfObject(const string &_filename, size_t _len, uint8_t *_data,
|
||||||
if (!(phdr.p_type & PT_LOAD))
|
if (!(phdr.p_type & PT_LOAD))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
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.
|
// Check to see if this segment contains the bss section.
|
||||||
if (phdr.p_paddr <= bssSecStart &&
|
if (phdr.p_paddr <= bssSecStart &&
|
||||||
phdr.p_paddr + phdr.p_memsz > bssSecStart &&
|
phdr.p_paddr + phdr.p_memsz > bssSecStart &&
|
||||||
|
@ -338,6 +386,11 @@ ElfObject::ElfObject(const string &_filename, size_t _len, uint8_t *_data,
|
||||||
// Check to see if this is the text or data segment
|
// Check to see if this is the text or data segment
|
||||||
if (phdr.p_vaddr <= textSecStart &&
|
if (phdr.p_vaddr <= textSecStart &&
|
||||||
phdr.p_vaddr + phdr.p_filesz > textSecStart) {
|
phdr.p_vaddr + phdr.p_filesz > textSecStart) {
|
||||||
|
|
||||||
|
// If this value is nonzero, we need to flip the relocate flag.
|
||||||
|
if (phdr.p_vaddr != 0)
|
||||||
|
relocate = false;
|
||||||
|
|
||||||
text.baseAddr = phdr.p_paddr;
|
text.baseAddr = phdr.p_paddr;
|
||||||
text.size = phdr.p_filesz;
|
text.size = phdr.p_filesz;
|
||||||
text.fileImage = fileData + phdr.p_offset;
|
text.fileImage = fileData + phdr.p_offset;
|
||||||
|
@ -462,6 +515,10 @@ ElfObject::loadSections(PortProxy& memProxy, Addr addrMask, Addr offset)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (interpreter)
|
||||||
|
interpreter->loadSections(memProxy, addrMask, offset);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,3 +567,19 @@ ElfObject::sectionExists(string sec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ElfObject::updateBias(Addr bias_addr)
|
||||||
|
{
|
||||||
|
// Record the bias.
|
||||||
|
ldBias = bias_addr;
|
||||||
|
|
||||||
|
// Patch the entry point with bias_addr.
|
||||||
|
entry += bias_addr;
|
||||||
|
|
||||||
|
// Patch segments with the bias_addr.
|
||||||
|
text.baseAddr += bias_addr;
|
||||||
|
data.baseAddr += bias_addr;
|
||||||
|
bss.baseAddr += bias_addr;
|
||||||
|
for (auto &segment : extraSegments)
|
||||||
|
segment.baseAddr += bias_addr;
|
||||||
|
}
|
||||||
|
|
|
@ -62,6 +62,24 @@ class ElfObject : public ObjectFile
|
||||||
uint16_t _programHeaderCount;
|
uint16_t _programHeaderCount;
|
||||||
std::set<std::string> sectionNames;
|
std::set<std::string> sectionNames;
|
||||||
|
|
||||||
|
ElfObject *interpreter;
|
||||||
|
|
||||||
|
// An interpreter load bias is the location in the process address space
|
||||||
|
// where the interpreter is chosen to reside. Typically, this is carved
|
||||||
|
// out of the top of the mmap reserve section.
|
||||||
|
Addr ldBias;
|
||||||
|
|
||||||
|
// The interpreter is typically a relocatable shared library and will
|
||||||
|
// have a default value of zero which means that it does not care where
|
||||||
|
// it is placed. However, the loader can be compiled and linked so that
|
||||||
|
// it does care and needs a specific entry point.
|
||||||
|
bool relocate;
|
||||||
|
|
||||||
|
// The ldMin and ldMax fields are required to know how large of an
|
||||||
|
// area is required to map the interpreter.
|
||||||
|
Addr ldMin;
|
||||||
|
Addr ldMax;
|
||||||
|
|
||||||
/// Helper functions for loadGlobalSymbols() and loadLocalSymbols().
|
/// Helper functions for loadGlobalSymbols() and loadLocalSymbols().
|
||||||
bool loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask);
|
bool loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask);
|
||||||
|
|
||||||
|
@ -78,19 +96,26 @@ class ElfObject : public ObjectFile
|
||||||
|
|
||||||
bool loadSections(PortProxy& memProxy,
|
bool loadSections(PortProxy& memProxy,
|
||||||
Addr addrMask = std::numeric_limits<Addr>::max(),
|
Addr addrMask = std::numeric_limits<Addr>::max(),
|
||||||
Addr offset = 0);
|
Addr offset = 0) override;
|
||||||
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
|
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
|
||||||
std::numeric_limits<Addr>::max());
|
std::numeric_limits<Addr>::max()) override;
|
||||||
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
|
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
|
||||||
std::numeric_limits<Addr>::max());
|
std::numeric_limits<Addr>::max()) override;
|
||||||
virtual bool loadWeakSymbols(SymbolTable *symtab, Addr addrMask =
|
virtual bool loadWeakSymbols(SymbolTable *symtab, Addr addrMask =
|
||||||
std::numeric_limits<Addr>::max());
|
std::numeric_limits<Addr>::max()) override;
|
||||||
|
|
||||||
virtual bool isDynamic() { return sectionExists(".interp"); }
|
virtual ObjectFile *getInterpreter() const override
|
||||||
virtual bool hasTLS() { return sectionExists(".tbss"); }
|
{ 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;
|
||||||
|
|
||||||
|
virtual bool hasTLS() override { return sectionExists(".tbss"); }
|
||||||
|
|
||||||
static ObjectFile *tryFile(const std::string &fname,
|
static ObjectFile *tryFile(const std::string &fname,
|
||||||
size_t len, uint8_t *data);
|
size_t len, uint8_t *data,
|
||||||
|
bool skip_interp_check = false);
|
||||||
Addr programHeaderTable() {return _programHeaderTable;}
|
Addr programHeaderTable() {return _programHeaderTable;}
|
||||||
uint16_t programHeaderSize() {return _programHeaderSize;}
|
uint16_t programHeaderSize() {return _programHeaderSize;}
|
||||||
uint16_t programHeaderCount() {return _programHeaderCount;}
|
uint16_t programHeaderCount() {return _programHeaderCount;}
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/misc.hh"
|
||||||
#include "base/types.hh"
|
#include "base/types.hh"
|
||||||
|
|
||||||
class PortProxy;
|
class PortProxy;
|
||||||
|
@ -94,7 +95,14 @@ class ObjectFile
|
||||||
std::numeric_limits<Addr>::max())
|
std::numeric_limits<Addr>::max())
|
||||||
{ return false; }
|
{ return false; }
|
||||||
|
|
||||||
virtual bool isDynamic() { return false; }
|
virtual ObjectFile *getInterpreter() const { return nullptr; }
|
||||||
|
virtual bool relocatable() const { return false; }
|
||||||
|
virtual Addr mapSize() const
|
||||||
|
{ panic("mapSize() should only be called on relocatable objects\n"); }
|
||||||
|
virtual void updateBias(Addr bias_addr)
|
||||||
|
{ panic("updateBias() should only be called on relocatable objects\n"); }
|
||||||
|
virtual Addr bias() const { return 0; }
|
||||||
|
|
||||||
virtual bool hasTLS() { return false; }
|
virtual bool hasTLS() { return false; }
|
||||||
|
|
||||||
Arch getArch() const { return arch; }
|
Arch getArch() const { return arch; }
|
||||||
|
|
|
@ -518,6 +518,48 @@ LiveProcess::findDriver(std::string filename)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LiveProcess::updateBias()
|
||||||
|
{
|
||||||
|
ObjectFile *interp = objFile->getInterpreter();
|
||||||
|
|
||||||
|
if (!interp || !interp->relocatable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Determine how large the interpreters footprint will be in the process
|
||||||
|
// address space.
|
||||||
|
Addr interp_mapsize = roundUp(interp->mapSize(), TheISA::PageBytes);
|
||||||
|
|
||||||
|
// We are allocating the memory area; set the bias to the lowest address
|
||||||
|
// in the allocated memory region.
|
||||||
|
Addr ld_bias = mmapGrowsDown() ? mmap_end - interp_mapsize : mmap_end;
|
||||||
|
|
||||||
|
// Adjust the process mmap area to give the interpreter room; the real
|
||||||
|
// execve system call would just invoke the kernel's internal mmap
|
||||||
|
// functions to make these adjustments.
|
||||||
|
mmap_end = mmapGrowsDown() ? ld_bias : mmap_end + interp_mapsize;
|
||||||
|
|
||||||
|
interp->updateBias(ld_bias);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Addr
|
||||||
|
LiveProcess::getBias()
|
||||||
|
{
|
||||||
|
ObjectFile *interp = objFile->getInterpreter();
|
||||||
|
|
||||||
|
return interp ? interp->bias() : objFile->bias();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Addr
|
||||||
|
LiveProcess::getStartPC()
|
||||||
|
{
|
||||||
|
ObjectFile *interp = objFile->getInterpreter();
|
||||||
|
|
||||||
|
return interp ? interp->entryPoint() : objFile->entryPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LiveProcess *
|
LiveProcess *
|
||||||
LiveProcess::create(LiveProcessParams * params)
|
LiveProcess::create(LiveProcessParams * params)
|
||||||
|
@ -535,11 +577,6 @@ LiveProcess::create(LiveProcessParams * params)
|
||||||
fatal("Can't load object file %s", params->executable);
|
fatal("Can't load object file %s", params->executable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objFile->isDynamic())
|
|
||||||
fatal("Object file is a dynamic executable however only static "
|
|
||||||
"executables are supported!\n Please recompile your "
|
|
||||||
"executable as a static binary and try again.\n");
|
|
||||||
|
|
||||||
#if THE_ISA == ALPHA_ISA
|
#if THE_ISA == ALPHA_ISA
|
||||||
if (objFile->getArch() != ObjectFile::Alpha)
|
if (objFile->getArch() != ObjectFile::Alpha)
|
||||||
fatal("Object file architecture does not match compiled ISA (Alpha).");
|
fatal("Object file architecture does not match compiled ISA (Alpha).");
|
||||||
|
|
|
@ -336,6 +336,14 @@ class LiveProcess : public Process
|
||||||
*/
|
*/
|
||||||
EmulatedDriver *findDriver(std::string filename);
|
EmulatedDriver *findDriver(std::string filename);
|
||||||
|
|
||||||
|
// This function acts as a callback to update the bias value in
|
||||||
|
// the object file because the parameters needed to calculate the
|
||||||
|
// bias are not available when the object file is created.
|
||||||
|
void updateBias();
|
||||||
|
|
||||||
|
Addr getBias();
|
||||||
|
Addr getStartPC();
|
||||||
|
|
||||||
// this function is used to create the LiveProcess object, since
|
// this function is used to create the LiveProcess object, since
|
||||||
// we can't tell which subclass of LiveProcess to use until we
|
// we can't tell which subclass of LiveProcess to use until we
|
||||||
// open and look at the object file.
|
// open and look at the object file.
|
||||||
|
|
Loading…
Reference in a new issue