diff options
Diffstat (limited to 'src/base/loader')
-rw-r--r-- | src/base/loader/elf_object.cc | 92 | ||||
-rw-r--r-- | src/base/loader/elf_object.hh | 8 |
2 files changed, 75 insertions, 25 deletions
diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc index ecce175b2..553723e74 100644 --- a/src/base/loader/elf_object.cc +++ b/src/base/loader/elf_object.cc @@ -216,50 +216,76 @@ ElfObject::ElfObject(const string &_filename, int _fd, entry = ehdr.e_entry; - // initialize segment sizes to 0 in case they're not present 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) { GElf_Phdr phdr; 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 if (!(phdr.p_type & PT_LOAD)) continue; - // the headers don't explicitly distinguish text from data, - // but empirically the text segment comes first. - if (text.size == 0) { // haven't seen text segment yet + // Check to see if this segment contains the bss section. + if (phdr.p_vaddr <= bssSecStart && + 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.size = phdr.p_filesz; text.fileImage = fileData + phdr.p_offset; - // if there's any padding at the end that's not in the - // file, call it the bss. This happens in the "text" - // 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 + } else if (phdr.p_vaddr <= dataSecStart && + phdr.p_vaddr + phdr.p_filesz > dataSecStart) { data.baseAddr = phdr.p_vaddr; data.size = phdr.p_filesz; 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 { - warn("More than two loadable segments in ELF object."); - warn("Ignoring segment @ 0x%x length 0x%x.", - phdr.p_vaddr, phdr.p_filesz); + Segment extra; + extra.baseAddr = phdr.p_vaddr; + 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); } +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 ElfObject::getSections() { diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh index 3e7c85874..5c5f6907d 100644 --- a/src/base/loader/elf_object.hh +++ b/src/base/loader/elf_object.hh @@ -33,11 +33,15 @@ #include "base/loader/object_file.hh" #include <set> +#include <vector> class ElfObject : public ObjectFile { 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 //need to keep them around. Addr _programHeaderTable; @@ -55,9 +59,13 @@ class ElfObject : public ObjectFile void getSections(); bool sectionExists(std::string sec); + std::vector<Segment> extraSegments; + public: virtual ~ElfObject() {} + bool loadSections(Port *memPort, + Addr addrMask = std::numeric_limits<Addr>::max()); virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask = std::numeric_limits<Addr>::max()); virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = |