Loader: Load all segments of an elf, rather than just the "text" and "data".

--HG--
extra : convert_revision : b28bb9ac5cde72878e948d64f629de6e4b42c2e8
This commit is contained in:
Gabe Black 2007-09-25 20:03:51 -07:00
parent 85d46ce470
commit 9ef0f6a7f1
2 changed files with 75 additions and 25 deletions

View file

@ -216,50 +216,76 @@ ElfObject::ElfObject(const string &_filename, int _fd,
entry = ehdr.e_entry; entry = ehdr.e_entry;
// initialize segment sizes to 0 in case they're not present // initialize segment sizes to 0 in case they're not present
text.size = data.size = bss.size = 0; text.size = data.size = bss.size = 0;
int secIdx = 1;
Elf_Scn *section;
GElf_Shdr shdr;
// The first address of some important sections.
Addr textSecStart = 0;
Addr dataSecStart = 0;
Addr bssSecStart = 0;
// Get the first section
section = elf_getscn(elf, secIdx);
// Find the beginning of the most interesting sections.
while (section != NULL) {
gelf_getshdr(section, &shdr);
char * secName = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
if (!strcmp(".text", secName)) {
textSecStart = shdr.sh_addr;
} else if (!strcmp(".data", secName)) {
dataSecStart = shdr.sh_addr;
} else if (!strcmp(".bss", secName)) {
bssSecStart = shdr.sh_addr;
}
section = elf_getscn(elf, ++secIdx);
}
// 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.
for (int i = 0; i < ehdr.e_phnum; ++i) { for (int i = 0; i < ehdr.e_phnum; ++i) {
GElf_Phdr phdr; GElf_Phdr phdr;
if (gelf_getphdr(elf, i, &phdr) == 0) { if (gelf_getphdr(elf, i, &phdr) == 0) {
panic("gelf_getphdr failed for section %d", i); panic("gelf_getphdr failed for segment %d.", i);
} }
// for now we don't care about non-loadable segments // for now we don't care about non-loadable segments
if (!(phdr.p_type & PT_LOAD)) if (!(phdr.p_type & PT_LOAD))
continue; continue;
// the headers don't explicitly distinguish text from data, // Check to see if this segment contains the bss section.
// but empirically the text segment comes first. if (phdr.p_vaddr <= bssSecStart &&
if (text.size == 0) { // haven't seen text segment yet phdr.p_vaddr + phdr.p_memsz > bssSecStart &&
phdr.p_memsz - phdr.p_filesz > 0) {
bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
bss.size = phdr.p_memsz - phdr.p_filesz;
bss.fileImage = NULL;
}
// Check to see if this is the text or data segment
if (phdr.p_vaddr <= textSecStart &&
phdr.p_vaddr + phdr.p_filesz > textSecStart) {
text.baseAddr = phdr.p_vaddr; text.baseAddr = phdr.p_vaddr;
text.size = phdr.p_filesz; text.size = phdr.p_filesz;
text.fileImage = fileData + phdr.p_offset; text.fileImage = fileData + phdr.p_offset;
// if there's any padding at the end that's not in the } else if (phdr.p_vaddr <= dataSecStart &&
// file, call it the bss. This happens in the "text" phdr.p_vaddr + phdr.p_filesz > dataSecStart) {
// segment if there's only one loadable segment (as for
// kernel images).
bss.size = phdr.p_memsz - phdr.p_filesz;
bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
bss.fileImage = NULL;
} else if (data.size == 0) { // have text, this must be data
data.baseAddr = phdr.p_vaddr; data.baseAddr = phdr.p_vaddr;
data.size = phdr.p_filesz; data.size = phdr.p_filesz;
data.fileImage = fileData + phdr.p_offset; data.fileImage = fileData + phdr.p_offset;
// if there's any padding at the end that's not in the
// file, call it the bss. Warn if this happens for both
// the text & data segments (should only have one bss).
if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) {
warn("Two implied bss segments in file!\n");
}
bss.size = phdr.p_memsz - phdr.p_filesz;
bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
bss.fileImage = NULL;
} else { } else {
warn("More than two loadable segments in ELF object."); Segment extra;
warn("Ignoring segment @ 0x%x length 0x%x.", extra.baseAddr = phdr.p_vaddr;
phdr.p_vaddr, phdr.p_filesz); extra.size = phdr.p_filesz;
extra.fileImage = fileData + phdr.p_offset;
extraSegments.push_back(extra);
} }
} }
@ -343,6 +369,22 @@ ElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask)
return loadSomeSymbols(symtab, STB_LOCAL); return loadSomeSymbols(symtab, STB_LOCAL);
} }
bool
ElfObject::loadSections(Port *memPort, Addr addrMask)
{
if (!ObjectFile::loadSections(memPort, addrMask))
return false;
vector<Segment>::iterator extraIt;
for (extraIt = extraSegments.begin();
extraIt != extraSegments.end(); extraIt++) {
if (!loadSection(&(*extraIt), memPort, addrMask)) {
return false;
}
}
return true;
}
void void
ElfObject::getSections() ElfObject::getSections()
{ {

View file

@ -33,11 +33,15 @@
#include "base/loader/object_file.hh" #include "base/loader/object_file.hh"
#include <set> #include <set>
#include <vector>
class ElfObject : public ObjectFile class ElfObject : public ObjectFile
{ {
protected: protected:
//The global definition of a "Section" is closest to elf's segments.
typedef ObjectFile::Section Segment;
//These values are provided to a linux process by the kernel, so we //These values are provided to a linux process by the kernel, so we
//need to keep them around. //need to keep them around.
Addr _programHeaderTable; Addr _programHeaderTable;
@ -55,9 +59,13 @@ class ElfObject : public ObjectFile
void getSections(); void getSections();
bool sectionExists(std::string sec); bool sectionExists(std::string sec);
std::vector<Segment> extraSegments;
public: public:
virtual ~ElfObject() {} virtual ~ElfObject() {}
bool loadSections(Port *memPort,
Addr addrMask = std::numeric_limits<Addr>::max());
virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
std::numeric_limits<Addr>::max()); std::numeric_limits<Addr>::max());
virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =