void ElfSectionManager::AddSection(ElfSection & aSection){ EnsureSectionStringTableSectionAdded(); if (aSection.GetName().size() > 0){ // rename sections for GDB (yuk!) String sectionName(aSection.GetName()); String ro("ER_RO"); String text(".text"); if (sectionName == ro){ sectionName = text; } else { String rw("ER_RW"); String data(".data"); if (sectionName == rw){ sectionName = data; } else { String zi("ER_ZI"); String bss(".bss"); if (sectionName == zi) sectionName = bss; } } size_t nameOffset = iStringTable.AddName(sectionName); aSection.SetNameOffset(nameOffset); } else { // use the initial Null String. size_t nameOffset = iStringTable.AllocateInitialNullString(); aSection.SetNameOffset(nameOffset); } aSection.SetIndex(iSections.size()); iSections.push_back(aSection); iElf32Header.AddSectionHdr(); }
status_t DwarfImageDebugInfo::Init() { status_t error = fLock.InitCheck(); if (error != B_OK) return error; fTextSegment = fFile->GetElfFile()->TextSegment(); if (fTextSegment == NULL) return B_ENTRY_NOT_FOUND; fRelocationDelta = fImageInfo.TextBase() - fTextSegment->LoadAddress(); ElfSection* section = fFile->GetElfFile()->FindSection(".text"); if (section != NULL) { fTextSectionStart = section->LoadAddress() + fRelocationDelta; fTextSectionEnd = fTextSectionStart + section->Size(); } section = fFile->GetElfFile()->FindSection(".plt"); if (section != NULL) { fPLTSectionStart = section->LoadAddress() + fRelocationDelta; fPLTSectionEnd = fPLTSectionStart + section->Size(); } return B_OK; }
void ElfFile::loadSectionNames() { if (fileHeader.e_shstrndx == SHN_UNDEF) return; // check if the string table is actually a string table // sometimes it gives the wrong section id int strTablePos = sections[fileHeader.e_shstrndx]->getOffset(); int strTableSize = sections[fileHeader.e_shstrndx]->getSize(); for (int i = 0; i < strTableSize; i++) { if (fileData[strTablePos+i] != 0 && fileData[strTablePos+i] < 0x20) return; if (fileData[strTablePos+i] > 0x7F) return; } for (int i = 0; i < (int)sections.size(); i++) { ElfSection* section = sections[i]; if (section->getType() == SHT_NULL) continue; int strTablePos = sections[fileHeader.e_shstrndx]->getOffset(); int offset = strTablePos+section->getNameOffset(); char* name = (char*) fileData.data(offset); std::string strName = name; section->setName(strName); } }
void ElfSymbol::Write(Bytes& bytes, const ElfConfig& config, Diagnostic& diags) { // Pull referenced elf symbol information type and size if (m_value_rel) { ElfSymbol* elfrel = m_value_rel->getAssocData<ElfSymbol>(); if (elfrel) { if (!hasType() && elfrel->hasType()) m_type = elfrel->m_type; if (!hasSize() && elfrel->hasSize()) { m_size = elfrel->m_size; m_size_source = elfrel->m_size_source; // just in case, simplify it SimplifyCalcDist(m_size, diags); if (!m_size.isIntNum()) diags.Report(m_size_source, diag::err_size_integer); } } } bytes.resize(0); config.setEndian(bytes); Write32(bytes, m_name_index); if (config.cls == ELFCLASS32) { Write32(bytes, m_value); Write32(bytes, hasSize() && m_size.isIntNum() ? m_size.getIntNum() : 0); } Write8(bytes, ELF_ST_INFO(m_bind, m_type)); Write8(bytes, ELF_ST_OTHER(m_vis)); if (m_sect) { ElfSection* elfsect = m_sect->getAssocData<ElfSection>(); assert(elfsect != 0); Write16(bytes, elfsect->getIndex()); } else { Write16(bytes, m_index); } if (config.cls == ELFCLASS64) { Write64(bytes, m_value); Write64(bytes, hasSize() ? m_size.getIntNum() : 0); } if (config.cls == ELFCLASS32) assert(bytes.size() == SYMTAB32_SIZE); else if (config.cls == ELFCLASS64) assert(bytes.size() == SYMTAB64_SIZE); }
ElfSection* ElfFile::GetSection(const char* name) { ElfSection* section = FindSection(name); if (section != NULL && section->Load() == B_OK) return section; return NULL; }
ElfSection* ElfFile::FindSection(uint32 type) const { int32 count = fSections.CountItems(); for (int32 i = 0; i < count; i++) { ElfSection* section = fSections.ItemAt(i); if (section->Type() == type) return section; } return NULL; }
ElfSection* ElfFile::FindSection(const char* name) const { int32 count = fSections.CountItems(); for (int32 i = 0; i < count; i++) { ElfSection* section = fSections.ItemAt(i); if (strcmp(section->Name(), name) == 0) return section; } return NULL; }
ElfSymbol::ElfSymbol(const ElfConfig& config, const llvm::MemoryBuffer& in, const ElfSection& symtab_sect, ElfSymbolIndex index, Section* sections[], Diagnostic& diags) : m_sect(0) , m_name_index(0) , m_value(0) , m_symindex(index) , m_in_table(true) , m_weak_ref(false) , m_weak_refr(false) { InputBuffer inbuf(in); ElfSize symsize = symtab_sect.getEntSize(); inbuf.setPosition(symtab_sect.getFileOffset() + index * symsize); if (inbuf.getReadableSize() < symsize) { diags.Report(SourceLocation(), diag::err_symbol_unreadable); return; } config.setEndian(inbuf); m_name_index = ReadU32(inbuf); if (config.cls == ELFCLASS32) { m_value = ReadU32(inbuf); m_size = Expr(ReadU32(inbuf)); } unsigned char info = ReadU8(inbuf); m_bind = ELF_ST_BIND(info); m_type = ELF_ST_TYPE(info); m_vis = ELF_ST_VISIBILITY(ReadU8(inbuf)); m_index = static_cast<ElfSectionIndex>(ReadU16(inbuf)); if (m_index != SHN_UNDEF && m_index < config.secthead_count) m_sect = sections[m_index]; if (config.cls == ELFCLASS64) { m_value = ReadU64(inbuf); m_size = Expr(ReadU64(inbuf)); } }
bool ElfFile::_FindSymbolSections(ElfSection*& _symbolSection, ElfSection*& _stringSection, uint32 type) const { // get the symbol table section ElfSection* symbolSection = FindSection(type); if (symbolSection == NULL) return false; // The symbol table section is linked to the corresponding string section. ElfSection* stringSection = SectionAt(symbolSection->LinkIndex()); if (stringSection == NULL || stringSection->Type() != SHT_STRTAB) return false; _symbolSection = symbolSection; _stringSection = stringSection; return true; }
bool ElfConfig::ReadSymbolTable(const MemoryBuffer& in, const ElfSection& symtab_sect, ElfSymtab& symtab, Object& object, const StringTable& strtab, Section* sections[], DiagnosticsEngine& diags) const { ElfSize symsize = symtab_sect.getEntSize(); if (symsize == 0) { diags.Report(SourceLocation(), diag::err_symbol_entity_size_zero); return false; } unsigned long size = symtab_sect.getSize().getUInt(); // Symbol table always starts with null entry symtab.push_back(SymbolRef(0)); ElfSymbolIndex index = 1; for (unsigned long pos=symsize; pos<size; pos += symsize, ++index) { std::auto_ptr<ElfSymbol> elfsym( new ElfSymbol(*this, in, symtab_sect, index, sections, diags)); if (diags.hasErrorOccurred()) return false; SymbolRef sym = elfsym->CreateSymbol(object, strtab); symtab.push_back(sym); if (sym) sym->AddAssocData(elfsym); // Associate symbol data with symbol } return true; }
void serialize(std::ofstream &file, char ei_class, char ei_data) { // Readjust code offsets for (std::vector<ElfSection *>::iterator c = code.begin(); c != code.end(); c++) (*c)->getShdr().sh_addr += getAddr(); // Apply relocations for (ElfSection *rel = elf->getSection(1); rel != NULL; rel = rel->getNext()) if ((rel->getType() == SHT_REL) || (rel->getType() == SHT_RELA)) { ElfSection *section = rel->getInfo().section; if ((section->getType() == SHT_PROGBITS) && (section->getFlags() & SHF_EXECINSTR)) { if (rel->getType() == SHT_REL) apply_relocations((ElfRel_Section<Elf_Rel> *)rel, section); else apply_relocations((ElfRel_Section<Elf_Rela> *)rel, section); } } ElfSection::serialize(file, ei_class, ei_data); }
bool ElfFile::load(ByteArray& data, bool sort) { fileData = data; memcpy(&fileHeader,&fileData[0],sizeof(Elf32_Ehdr)); symTab = NULL; strTab = NULL; // load segments for (int i = 0; i < fileHeader.e_phnum; i++) { int pos = fileHeader.e_phoff+i*fileHeader.e_phentsize; Elf32_Phdr sectionHeader; memcpy(§ionHeader,&fileData[pos],sizeof(Elf32_Phdr)); ByteArray segmentData = fileData.mid(sectionHeader.p_offset,sectionHeader.p_filesz); ElfSegment* segment = new ElfSegment(sectionHeader,segmentData); segments.push_back(segment); } // load sections and assign them to segments for (int i = 0; i < fileHeader.e_shnum; i++) { int pos = fileHeader.e_shoff+i*fileHeader.e_shentsize; Elf32_Shdr sectionHeader; memcpy(§ionHeader,&fileData[pos],sizeof(Elf32_Shdr)); ElfSection* section = new ElfSection(sectionHeader); sections.push_back(section); // check if the section belongs to a segment ElfSegment* owner = NULL; for (int k = 0; k < (int)segments.size(); k++) { if (segments[k]->isSectionPartOf(section)) { owner = segments[k]; break; } } if (owner != NULL) { owner->addSection(section); } else { if (section->getType() != SHT_NOBITS && section->getType() != SHT_NULL) { ByteArray data = fileData.mid(section->getOffset(),section->getSize()); section->setData(data); } switch (section->getType()) { case SHT_SYMTAB: symTab = section; break; case SHT_STRTAB: strTab = section; break; } segmentlessSections.push_back(section); } } determinePartOrder(); loadSectionNames(); if (sort) { std::sort(segmentlessSections.begin(),segmentlessSections.end(),compareSection); for (int i = 0; i < (int)segments.size(); i++) { segments[i]->sortSections(); } } return true; }
bool ElfRelocator::init(const std::wstring& inputName) { relocator = Arch->getElfRelocator(); if (relocator == NULL) { Logger::printError(Logger::Error,L"Object importing not supported for this architecture"); return false; } auto inputFiles = loadArArchive(inputName); if (inputFiles.size() == 0) { Logger::printError(Logger::Error,L"Could not load library"); return false; } for (ArFileEntry& entry: inputFiles) { ElfRelocatorFile file; ElfFile* elf = new ElfFile(); if (elf->load(entry.data,false) == false) { Logger::printError(Logger::Error,L"Could not load object file %s",entry.name); return false; } if (elf->getType() != 1) { Logger::printError(Logger::Error,L"Unexpected ELF type %d in object file %s",elf->getType(),entry.name); return false; } if (elf->getSegmentCount() != 0) { Logger::printError(Logger::Error,L"Unexpected segment count %d in object file %s",elf->getSegmentCount(),entry.name); return false; } // load all relevant sections of this file for (size_t s = 0; s < elf->getSegmentlessSectionCount(); s++) { ElfSection* sec = elf->getSegmentlessSection(s); if (!(sec->getFlags() & SHF_ALLOC)) continue; if (sec->getType() == SHT_PROGBITS || sec->getType() == SHT_NOBITS || sec->getType() == SHT_INIT_ARRAY) { ElfRelocatorSection sectionEntry; sectionEntry.section = sec; sectionEntry.index = s; sectionEntry.relSection = NULL; sectionEntry.label = NULL; // search relocation section for (size_t k = 0; k < elf->getSegmentlessSectionCount(); k++) { ElfSection* relSection = elf->getSegmentlessSection(k); if (relSection->getType() != SHT_REL) continue; if (relSection->getInfo() != s) continue; // got it sectionEntry.relSection = relSection; break; } // keep track of constructor sections if (sec->getName() == ".ctors" || sec->getName() == ".init_array") { ElfRelocatorCtor ctor; ctor.symbolName = Global.symbolTable.getUniqueLabelName(); ctor.size = sec->getSize(); sectionEntry.label = Global.symbolTable.getLabel(ctor.symbolName,-1,-1); sectionEntry.label->setDefined(true); ctors.push_back(ctor); } file.sections.push_back(sectionEntry); } } // init exportable symbols for (int i = 0; i < elf->getSymbolCount(); i++) { Elf32_Sym symbol; bool found = elf->getSymbol(symbol, i); if (ELF32_ST_BIND(symbol.st_info) == STB_GLOBAL && symbol.st_shndx != 0) { ElfRelocatorSymbol symEntry; symEntry.type = ELF32_ST_TYPE(symbol.st_info); symEntry.name = convertUtf8ToWString(elf->getStrTableString(symbol.st_name)); symEntry.relativeAddress = symbol.st_value; symEntry.section = symbol.st_shndx; symEntry.size = symbol.st_size; symEntry.label = NULL; file.symbols.push_back(symEntry); } } file.elf = elf; file.name = entry.name; files.push_back(file); } return true; }
ElfRelHackCode_Section(Elf_Shdr &s, Elf &e) : ElfSection(s, NULL, NULL), parent(e) { std::string file(rundir); init = parent.getDynSection()->getSectionForType(DT_INIT); file += "/inject/"; switch (parent.getMachine()) { case EM_386: file += "x86"; break; case EM_X86_64: file += "x86_64"; break; case EM_ARM: file += "arm"; break; default: throw std::runtime_error("unsupported architecture"); } if (init == NULL) file += "-noinit"; file += ".o"; std::ifstream inject(file.c_str(), std::ios::in|std::ios::binary); elf = new Elf(inject); if (elf->getType() != ET_REL) throw std::runtime_error("object for injected code is not ET_REL"); if (elf->getMachine() != parent.getMachine()) throw std::runtime_error("architecture of object for injected code doesn't match"); ElfSymtab_Section *symtab = NULL; // Get all executable sections from the injected code object. // Most of the time, there will only be one for the init function, // but on e.g. x86, there is a separate section for // __i686.get_pc_thunk.$reg // Find the symbol table at the same time. for (ElfSection *section = elf->getSection(1); section != NULL; section = section->getNext()) { if ((section->getType() == SHT_PROGBITS) && (section->getFlags() & SHF_EXECINSTR)) { code.push_back(section); // We need to align this section depending on the greater // alignment required by code sections. if (shdr.sh_addralign < section->getAddrAlign()) shdr.sh_addralign = section->getAddrAlign(); } else if (section->getType() == SHT_SYMTAB) { symtab = (ElfSymtab_Section *) section; } } assert(code.size() != 0); if (symtab == NULL) throw std::runtime_error("Couldn't find a symbol table for the injected code"); // Find the init symbol entry_point = -1; int shndx = 0; for (std::vector<Elf_SymValue>::iterator sym = symtab->syms.begin(); sym != symtab->syms.end(); sym++) { if (strcmp(sym->name, "init") == 0) { entry_point = sym->value.getValue(); shndx = sym->value.getSection()->getIndex(); break; } } if (entry_point == -1) throw std::runtime_error("Couldn't find an 'init' symbol in the injected code"); // Adjust code sections offsets according to their size std::vector<ElfSection *>::iterator c = code.begin(); (*c)->getShdr().sh_addr = 0; for(ElfSection *last = *(c++); c != code.end(); c++) { unsigned int addr = last->getShdr().sh_addr + last->getSize(); if (addr & ((*c)->getAddrAlign() - 1)) addr = (addr | ((*c)->getAddrAlign() - 1)) + 1; (*c)->getShdr().sh_addr = addr; } shdr.sh_size = code.back()->getAddr() + code.back()->getSize(); data = new char[shdr.sh_size]; char *buf = data; for (c = code.begin(); c != code.end(); c++) { memcpy(buf, (*c)->getData(), (*c)->getSize()); buf += (*c)->getSize(); if ((*c)->getIndex() < shndx) entry_point += (*c)->getSize(); } name = elfhack_text; }
void ElfSymbol::Finalize(Symbol& sym, Diagnostic& diags) { // If symbol is a weakrefr, make it weak at this point. if (m_weak_refr) { if (!sym.isDefined() && (sym.getVisibility() & (Symbol::GLOBAL | Symbol::COMMON)) == 0) { if (sym.isUsed()) { setInTable(true); sym.Declare(Symbol::GLOBAL); setBinding(STB_WEAK); } else { setInTable(false); return; } } else if (!sym.isDefined() && (sym.getVisibility() & Symbol::GLOBAL) != 0) { setBinding(STB_GLOBAL); } } // Don't put the LHS of weakrefs into the symbol table unless they're // specifically requested. if (m_weak_ref && (sym.getVisibility() == Symbol::DLOCAL || sym.getVisibility() == Symbol::LOCAL)) { setInTable(false); return; } // If symbol is in a TLS section, force its type to TLS. Location loc; Section* sect; ElfSection* elfsect; if (sym.getLabel(&loc) && (sect = loc.bc->getContainer()->AsSection()) && (elfsect = sect->getAssocData<ElfSection>()) && (elfsect->getFlags() & SHF_TLS)) { m_type = STT_TLS; } // get size (if specified); expr overrides stored integer if (!m_size.isEmpty()) { if (!ExpandEqu(m_size)) { diags.Report(m_size_source, diag::err_equ_circular_reference); return; } SimplifyCalcDist(m_size, diags); if (!m_size.isIntNum()) diags.Report(m_size_source, diag::err_size_integer); } // get EQU value for constants const Expr* equ_expr_c = sym.getEqu(); if (equ_expr_c != 0) { Expr equ_expr = *equ_expr_c; if (!ExpandEqu(equ_expr)) { diags.Report(sym.getDefSource(), diag::err_equ_circular_reference); return; } SimplifyCalcDist(equ_expr, diags); // trivial case: simple integer if (equ_expr.isIntNum()) { m_index = SHN_ABS; m_value = equ_expr.getIntNum(); return; } // otherwise might contain relocatable value (e.g. symbol alias) std::auto_ptr<Expr> equ_expr_p(new Expr); equ_expr_p->swap(equ_expr); Value val(64, equ_expr_p); val.setSource(sym.getDefSource()); if (!val.Finalize(diags, diag::err_equ_too_complex)) return; if (val.isComplexRelative()) { diags.Report(sym.getDefSource(), diag::err_equ_too_complex); return; } // set section appropriately based on if value is relative if (val.isRelative()) { SymbolRef rel = val.getRelative(); Location loc; if (!rel->getLabel(&loc) || !loc.bc) { // Referencing an undefined label? Don't gen the symbol. diags.Report(sym.getDefSource(), diag::warn_equ_undef_ref); m_in_table = false; return; } m_sect = loc.bc->getContainer()->AsSection(); m_value = loc.getOffset(); m_value_rel = rel; } else { m_index = SHN_ABS; m_value = 0; } // add in any remaining absolute portion if (Expr* abs = val.getAbs()) { SimplifyCalcDist(*abs, diags); if (!abs->isIntNum()) { diags.Report(sym.getDefSource(), diag::err_equ_not_integer); return; } m_value += abs->getIntNum(); } } }
status_t ElfFile::Init(const char* fileName) { // open file fFD = open(fileName, O_RDONLY); if (fFD < 0) { WARNING("Failed to open \"%s\": %s\n", fileName, strerror(errno)); return errno; } // stat() file to get its size struct stat st; if (fstat(fFD, &st) < 0) { WARNING("Failed to stat \"%s\": %s\n", fileName, strerror(errno)); return errno; } fFileSize = st.st_size; // read the elf header fElfHeader = (Elf32_Ehdr*)malloc(sizeof(Elf32_Ehdr)); if (fElfHeader == NULL) return B_NO_MEMORY; ssize_t bytesRead = pread(fFD, fElfHeader, sizeof(Elf32_Ehdr), 0); if (bytesRead != (ssize_t)sizeof(Elf32_Ehdr)) return bytesRead < 0 ? errno : B_ERROR; // check the ELF header if (!_CheckRange(0, sizeof(Elf32_Ehdr)) || !_CheckElfHeader()) { WARNING("\"%s\": Not an ELF file\n", fileName); return B_BAD_DATA; } // check section header table values off_t sectionHeadersOffset = fElfHeader->e_shoff; size_t sectionHeaderSize = fElfHeader->e_shentsize; int sectionCount = fElfHeader->e_shnum; size_t sectionHeaderTableSize = sectionHeaderSize * sectionCount; if (!_CheckRange(sectionHeadersOffset, sectionHeaderTableSize)) { WARNING("\"%s\": Invalid ELF header\n", fileName); return B_BAD_DATA; } // read the section header table uint8* sectionHeaderTable = (uint8*)malloc(sectionHeaderTableSize); if (sectionHeaderTable == NULL) return B_NO_MEMORY; MemoryDeleter sectionHeaderTableDeleter(sectionHeaderTable); bytesRead = pread(fFD, sectionHeaderTable, sectionHeaderTableSize, sectionHeadersOffset); if (bytesRead != (ssize_t)sectionHeaderTableSize) return bytesRead < 0 ? errno : B_ERROR; // check and get the section header string section Elf32_Shdr* stringSectionHeader = (Elf32_Shdr*)(sectionHeaderTable + fElfHeader->e_shstrndx * sectionHeaderSize); if (!_CheckRange(stringSectionHeader->sh_offset, stringSectionHeader->sh_size)) { WARNING("\"%s\": Invalid string section header\n", fileName); return B_BAD_DATA; } size_t sectionStringSize = stringSectionHeader->sh_size; ElfSection* sectionStringSection = new(std::nothrow) ElfSection(".shstrtab", fFD, stringSectionHeader->sh_offset, sectionStringSize, stringSectionHeader->sh_addr, stringSectionHeader->sh_flags); if (sectionStringSection == NULL) return B_NO_MEMORY; fSections.Add(sectionStringSection); status_t error = sectionStringSection->Load(); if (error != B_OK) return error; const char* sectionStrings = (const char*)sectionStringSection->Data(); // read the other sections for (int i = 0; i < sectionCount; i++) { Elf32_Shdr* sectionHeader = (Elf32_Shdr*)(sectionHeaderTable + i * sectionHeaderSize); // skip invalid sections and the section header string section const char* name = sectionStrings + sectionHeader->sh_name; if (sectionHeader->sh_name >= sectionStringSize || !_CheckRange(sectionHeader->sh_offset, sectionHeader->sh_size) || i == fElfHeader->e_shstrndx) { continue; } // create an ElfSection ElfSection* section = new(std::nothrow) ElfSection(name, fFD, sectionHeader->sh_offset, sectionHeader->sh_size, sectionHeader->sh_addr, sectionHeader->sh_flags); if (section == NULL) return B_NO_MEMORY; fSections.Add(section); } // check program header table values off_t programHeadersOffset = fElfHeader->e_phoff; size_t programHeaderSize = fElfHeader->e_phentsize; int segmentCount = fElfHeader->e_phnum; size_t programHeaderTableSize = programHeaderSize * segmentCount; if (!_CheckRange(programHeadersOffset, programHeaderTableSize)) { WARNING("\"%s\": Invalid ELF header\n", fileName); return B_BAD_DATA; } // read the program header table uint8* programHeaderTable = (uint8*)malloc(programHeaderTableSize); if (programHeaderTable == NULL) return B_NO_MEMORY; MemoryDeleter programHeaderTableDeleter(programHeaderTable); bytesRead = pread(fFD, programHeaderTable, programHeaderTableSize, programHeadersOffset); if (bytesRead != (ssize_t)programHeaderTableSize) return bytesRead < 0 ? errno : B_ERROR; // read the program headers and create ElfSegment objects for (int i = 0; i < segmentCount; i++) { Elf32_Phdr* programHeader = (Elf32_Phdr*)(programHeaderTable + i * programHeaderSize); // skip program headers we aren't interested in or that are invalid if (programHeader->p_type != PT_LOAD || programHeader->p_filesz == 0 || programHeader->p_memsz == 0 || !_CheckRange(programHeader->p_offset, programHeader->p_filesz)) { continue; } // create an ElfSegment ElfSegment* segment = new(std::nothrow) ElfSegment( programHeader->p_offset, programHeader->p_filesz, programHeader->p_vaddr, programHeader->p_memsz, (programHeader->p_flags & PF_WRITE) != 0); if (segment == NULL) return B_NO_MEMORY; fSegments.Add(segment); } return B_OK; }
status_t ElfFile::_LoadFile(const char* fileName) { typedef typename ElfClass::Ehdr Ehdr; typedef typename ElfClass::Phdr Phdr; typedef typename ElfClass::Shdr Shdr; // read the elf header Ehdr elfHeader; ssize_t bytesRead = pread(fFD, &elfHeader, sizeof(elfHeader), 0); if (bytesRead != (ssize_t)sizeof(elfHeader)) return bytesRead < 0 ? errno : B_ERROR; // check the ELF header if (!_CheckRange(0, sizeof(elfHeader)) || !_CheckElfHeader<ElfClass>(elfHeader)) { WARNING("\"%s\": Not a valid ELF file\n", fileName); return B_BAD_DATA; } fType = Get(elfHeader.e_type); fMachine = Get(elfHeader.e_machine); if (Get(elfHeader.e_shnum) > 0) { // check section header table values uint64 sectionHeadersOffset = Get(elfHeader.e_shoff); size_t sectionHeaderSize = Get(elfHeader.e_shentsize); int sectionCount = Get(elfHeader.e_shnum); size_t sectionHeaderTableSize = sectionHeaderSize * sectionCount; if (!_CheckRange(sectionHeadersOffset, sectionHeaderTableSize)) { WARNING("\"%s\": Invalid ELF header\n", fileName); return B_BAD_DATA; } // read the section header table uint8* sectionHeaderTable = (uint8*)malloc(sectionHeaderTableSize); if (sectionHeaderTable == NULL) return B_NO_MEMORY; MemoryDeleter sectionHeaderTableDeleter(sectionHeaderTable); bytesRead = pread(fFD, sectionHeaderTable, sectionHeaderTableSize, sectionHeadersOffset); if (bytesRead != (ssize_t)sectionHeaderTableSize) return bytesRead < 0 ? errno : B_ERROR; // check and get the section header string section Shdr* stringSectionHeader = (Shdr*)(sectionHeaderTable + Get(elfHeader.e_shstrndx) * sectionHeaderSize); if (!_CheckRange(Get(stringSectionHeader->sh_offset), Get(stringSectionHeader->sh_size))) { WARNING("\"%s\": Invalid string section header\n", fileName); return B_BAD_DATA; } size_t sectionStringSize = Get(stringSectionHeader->sh_size); ElfSection* sectionStringSection = new(std::nothrow) ElfSection( ".shstrtab", Get(stringSectionHeader->sh_type),fFD, Get(stringSectionHeader->sh_offset), sectionStringSize, Get(stringSectionHeader->sh_addr), Get(stringSectionHeader->sh_flags), Get(stringSectionHeader->sh_link)); if (sectionStringSection == NULL) return B_NO_MEMORY; if (!fSections.AddItem(sectionStringSection)) { delete sectionStringSection; return B_NO_MEMORY; } status_t error = sectionStringSection->Load(); if (error != B_OK) return error; const char* sectionStrings = (const char*)sectionStringSection->Data(); // read the other sections for (int i = 0; i < sectionCount; i++) { Shdr* sectionHeader = (Shdr*)(sectionHeaderTable + i * sectionHeaderSize); // skip invalid sections and the section header string section const char* name = sectionStrings + Get(sectionHeader->sh_name); if (Get(sectionHeader->sh_name) >= sectionStringSize || !_CheckRange(Get(sectionHeader->sh_offset), Get(sectionHeader->sh_size)) || i == Get(elfHeader.e_shstrndx)) { continue; } // create an ElfSection ElfSection* section = new(std::nothrow) ElfSection(name, Get(sectionHeader->sh_type), fFD, Get(sectionHeader->sh_offset), Get(sectionHeader->sh_size), Get(sectionHeader->sh_addr), Get(sectionHeader->sh_flags), Get(sectionHeader->sh_link)); if (section == NULL) return B_NO_MEMORY; if (!fSections.AddItem(section)) { delete section; return B_NO_MEMORY; } } } if (Get(elfHeader.e_phnum) > 0) { // check program header table values uint64 programHeadersOffset = Get(elfHeader.e_phoff); size_t programHeaderSize = Get(elfHeader.e_phentsize); int segmentCount = Get(elfHeader.e_phnum); size_t programHeaderTableSize = programHeaderSize * segmentCount; if (!_CheckRange(programHeadersOffset, programHeaderTableSize)) { WARNING("\"%s\": Invalid ELF header\n", fileName); return B_BAD_DATA; } // read the program header table uint8* programHeaderTable = (uint8*)malloc(programHeaderTableSize); if (programHeaderTable == NULL) return B_NO_MEMORY; MemoryDeleter programHeaderTableDeleter(programHeaderTable); bytesRead = pread(fFD, programHeaderTable, programHeaderTableSize, programHeadersOffset); if (bytesRead != (ssize_t)programHeaderTableSize) return bytesRead < 0 ? errno : B_ERROR; // read the program headers and create ElfSegment objects for (int i = 0; i < segmentCount; i++) { Phdr* programHeader = (Phdr*)(programHeaderTable + i * programHeaderSize); // skip invalid program headers if (Get(programHeader->p_filesz) > 0 && !_CheckRange(Get(programHeader->p_offset), Get(programHeader->p_filesz))) { continue; } // create an ElfSegment ElfSegment* segment = new(std::nothrow) ElfSegment( Get(programHeader->p_type), Get(programHeader->p_offset), Get(programHeader->p_filesz), Get(programHeader->p_vaddr), Get(programHeader->p_memsz), Get(programHeader->p_flags)); if (segment == NULL) return B_NO_MEMORY; if (!fSegments.AddItem(segment)) { delete segment; return B_NO_MEMORY; } } } return B_OK; }
status_t ElfFile::CreateSymbolLookup(uint64 textDelta, ElfSymbolLookup*& _lookup) const { // Get the symbol table + corresponding string section. There may be two // symbol tables: the dynamic and the non-dynamic one. The former contains // only the symbols needed at run-time. The latter, if existing, is likely // more complete. So try to find and use the latter one, falling back to the // former. ElfSection* symbolSection; ElfSection* stringSection; if (!_FindSymbolSections(symbolSection, stringSection, SHT_SYMTAB) && !_FindSymbolSections(symbolSection, stringSection, SHT_DYNSYM)) { return B_ENTRY_NOT_FOUND; } // create a source with a segment for each section SymbolLookupSource* source = new(std::nothrow) SymbolLookupSource(fFD); if (source == NULL) return B_NO_MEMORY; BReference<SymbolLookupSource> sourceReference(source, true); if (!source->AddSegment(symbolSection->Offset(), symbolSection->Size(), symbolSection->Offset()) || !source->AddSegment(stringSection->Offset(), stringSection->Size(), stringSection->Offset())) { return B_NO_MEMORY; } // create the lookup size_t symbolTableEntrySize = Is64Bit() ? sizeof(ElfClass64::Sym) : sizeof(ElfClass32::Sym); uint32 symbolCount = uint32(symbolSection->Size() / symbolTableEntrySize); return ElfSymbolLookup::Create(source, symbolSection->Offset(), 0, stringSection->Offset(), symbolCount, symbolTableEntrySize, textDelta, f64Bit, fSwappedByteOrder, true, _lookup); }
bool ElfRelocator::relocateFile(ElfRelocatorFile& file, u64& relocationAddress) { ElfFile* elf = file.elf; u64 start = relocationAddress; // calculate address for each section std::map<u64,u64> relocationOffsets; for (ElfRelocatorSection& entry: file.sections) { ElfSection* section = entry.section; size_t index = entry.index; int size = section->getSize(); while (relocationAddress % section->getAlignment()) relocationAddress++; if (entry.label != NULL) entry.label->setValue(relocationAddress); relocationOffsets[index] = relocationAddress; relocationAddress += size; } size_t dataStart = outputData.size(); outputData.reserveBytes((size_t)(relocationAddress-start)); // load sections bool error = false; for (ElfRelocatorSection& entry: file.sections) { ElfSection* section = entry.section; size_t index = entry.index; if (section->getType() == SHT_NOBITS) { // reserveBytes initialized the data to 0 already continue; } ByteArray sectionData = section->getData(); // relocate if necessary ElfSection* relSection = entry.relSection; if (relSection != NULL) { for (unsigned int relOffset = 0; relOffset < relSection->getSize(); relOffset += sizeof(Elf32_Rel)) { Elf32_Rel rel; loadRelocation(rel, relSection->getData(), relOffset, elf->isBigEndian()); int pos = rel.r_offset; int symNum = rel.getSymbolNum(); if (symNum <= 0) { Logger::queueError(Logger::Warning,L"Invalid symbol num %06X",symNum); error = true; continue; } Elf32_Sym sym; auto found = elf->getSymbol(sym, symNum); int symSection = sym.st_shndx; RelocationData relData; relData.opcode = sectionData.getDoubleWord(pos, elf->isBigEndian()); relData.opcodeOffset = pos+relocationOffsets[index]; relocator->setSymbolAddress(relData,sym.st_value,sym.st_info & 0xF); // externs? if (relData.targetSymbolType == STT_NOTYPE && sym.st_shndx == 0) { std::wstring symName = toWLowercase(elf->getStrTableString(sym.st_name)); Label* label = Global.symbolTable.getLabel(symName,-1,-1); if (label == NULL) { Logger::queueError(Logger::Error,L"Invalid external symbol %s",symName); error = true; continue; } if (label->isDefined() == false) { Logger::queueError(Logger::Error,L"Undefined external symbol %s in file %s",symName,file.name); error = true; continue; } relData.relocationBase = (unsigned int) label->getValue(); relData.targetSymbolType = label->isData() ? STT_OBJECT : STT_FUNC; relData.targetSymbolInfo = label->getInfo(); } else { relData.relocationBase = relocationOffsets[symSection]+relData.symbolAddress; } if (relocator->relocateOpcode(rel.getType(),relData) == false) { Logger::queueError(Logger::Error,relData.errorMessage); error = true; continue; } sectionData.replaceDoubleWord(pos,relData.opcode, elf->isBigEndian()); } } size_t arrayStart = (size_t) (dataStart+relocationOffsets[index]-start); memcpy(outputData.data(arrayStart),sectionData.data(),sectionData.size()); } // now update symbols for (ElfRelocatorSymbol& sym: file.symbols) { u64 oldAddress = sym.relocatedAddress; switch (sym.section) { case SHN_ABS: // address does not change sym.relocatedAddress = sym.relativeAddress; break; case SHN_COMMON: // needs to be allocated. relativeAddress gives alignment constraint { u64 start = relocationAddress; while (relocationAddress % sym.relativeAddress) relocationAddress++; sym.relocatedAddress = relocationAddress; relocationAddress += sym.size; outputData.reserveBytes((size_t)(relocationAddress-start)); } break; default: // normal relocated symbol sym.relocatedAddress = sym.relativeAddress+relocationOffsets[sym.section]; break; } if (sym.label != NULL) sym.label->setValue(sym.relocatedAddress); if (oldAddress != sym.relocatedAddress) dataChanged = true; } return !error; }