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); }
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(); } } }
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; }
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; }