//===----------------------------------------------------------------------===// // X86GNULDBackend //===----------------------------------------------------------------------===// X86GNULDBackend::X86GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo, Relocation::Type pCopyRel) : GNULDBackend(pConfig, pInfo), m_pRelocator(NULL), m_pPLT(NULL), m_pRelDyn(NULL), m_pRelPLT(NULL), m_pDynamic(NULL), m_pGOTSymbol(NULL), m_CopyRel(pCopyRel) { Triple::ArchType arch = pConfig.targets().triple().getArch(); assert (arch == Triple::x86 || arch == Triple::x86_64); if (arch == Triple::x86 || pConfig.targets().triple().getEnvironment() == Triple::GNUX32) { m_RelEntrySize = 8; m_RelaEntrySize = 12; if (arch == Triple::x86) m_PointerRel = llvm::ELF::R_386_32; else m_PointerRel = llvm::ELF::R_X86_64_32; } else { m_RelEntrySize = 16; m_RelaEntrySize = 24; m_PointerRel = llvm::ELF::R_X86_64_64; } }
static bool MCLDEmulateX86ELF(LinkerScript& pScript, LinkerConfig& pConfig) { if (!MCLDEmulateELF(pScript, pConfig)) return false; // set up bitclass and endian pConfig.targets().setEndian(TargetOptions::Little); unsigned int bitclass; Triple::ArchType arch = pConfig.targets().triple().getArch(); assert (arch == Triple::x86 || arch == Triple::x86_64); if (arch == Triple::x86 || pConfig.targets().triple().getEnvironment() == Triple::GNUX32) { bitclass = 32; } else { bitclass = 64; } pConfig.targets().setBitClass(bitclass); // set up target-dependent constraints of attributes pConfig.attribute().constraint().enableWholeArchive(); pConfig.attribute().constraint().enableAsNeeded(); pConfig.attribute().constraint().setSharedSystem(); // set up the predefined attributes pConfig.attribute().predefined().unsetWholeArchive(); pConfig.attribute().predefined().unsetAsNeeded(); pConfig.attribute().predefined().setDynamic(); return true; }
static bool MCLDEmulateARMELF(LinkerConfig& pConfig) { if (!MCLDEmulateELF(pConfig)) return false; // set up bitclass and endian pConfig.targets().setEndian(TargetOptions::Little); pConfig.targets().setBitClass(32); // set up target-dependent constraints of attributes pConfig.attribute().constraint().enableWholeArchive(); pConfig.attribute().constraint().enableAsNeeded(); pConfig.attribute().constraint().setSharedSystem(); // set up the predefined attributes pConfig.attribute().predefined().unsetWholeArchive(); pConfig.attribute().predefined().unsetAsNeeded(); pConfig.attribute().predefined().setDynamic(); // set up section map if (pConfig.codeGenType() != LinkerConfig::Object) { bool exist = false; pConfig.scripts().sectionMap().append(".ARM.exidx", ".ARM.exidx", exist); pConfig.scripts().sectionMap().append(".ARM.extab", ".ARM.extab", exist); pConfig.scripts().sectionMap().append(".ARM.attributes", ".ARM.attributes", exist); } return true; }
//===----------------------------------------------------------------------===// // ELFDynObjReader //===----------------------------------------------------------------------===// ELFDynObjReader::ELFDynObjReader(GNULDBackend& pBackend, IRBuilder& pBuilder, const LinkerConfig& pConfig) : DynObjReader(), m_pELFReader(0), m_Builder(pBuilder) { if (pConfig.targets().is32Bits() && pConfig.targets().isLittleEndian()) m_pELFReader = new ELFReader<32, true>(pBackend); else if (pConfig.targets().is64Bits() && pConfig.targets().isLittleEndian()) m_pELFReader = new ELFReader<64, true>(pBackend); }
//===----------------------------------------------------------------------===// // emulateX86LD - the help function to emulate X86 ld //===----------------------------------------------------------------------===// bool emulateX86LD(LinkerScript& pScript, LinkerConfig& pConfig) { if (pConfig.targets().triple().isOSDarwin()) { assert(0 && "MachO linker has not supported yet"); return false; } if (pConfig.targets().triple().isOSWindows()) { assert(0 && "COFF linker has not supported yet"); return false; } return MCLDEmulateX86ELF(pScript, pConfig); }
/// emitRelocation void ELFObjectWriter::emitRelocation(const LinkerConfig& pConfig, const LDSection& pSection, MemoryRegion& pRegion) const { const RelocData* sect_data = pSection.getRelocData(); assert(NULL != sect_data && "SectionData is NULL in emitRelocation!"); if (pSection.type() == SHT_REL) { if (pConfig.targets().is32Bits()) emitRel<32>(pConfig, *sect_data, pRegion); else if (pConfig.targets().is64Bits()) emitRel<64>(pConfig, *sect_data, pRegion); else { fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str() << pConfig.targets().bitclass(); } } else if (pSection.type() == SHT_RELA) { if (pConfig.targets().is32Bits()) emitRela<32>(pConfig, *sect_data, pRegion); else if (pConfig.targets().is64Bits()) emitRela<64>(pConfig, *sect_data, pRegion); else { fatal(diag::unsupported_bitclass) << pConfig.targets().triple().str() << pConfig.targets().bitclass(); } } else llvm::report_fatal_error("unsupported relocation section type!"); }
/// configure the output filename bool OutputFormatOptions::parseOutput(Module& pModule, LinkerConfig& pConfig) { if (true == m_Shared || true == m_PIE) { // -shared or -pie m_FileType = mcld::LinkerConfig::DynObj; } else if (true == m_Relocatable) { // partial linking m_FileType = mcld::LinkerConfig::Object; } else if (mcld::LinkerConfig::Binary == m_OFormat) { // binary output m_FileType = mcld::LinkerConfig::Binary; } pConfig.setCodeGenType(m_FileType); std::string output_filename(m_OutputFilename.native()); if (m_OutputFilename.empty()) { if (llvm::Triple::Win32 == pConfig.targets().triple().getOS()) { output_filename.assign("_out"); switch (m_FileType) { case mcld::LinkerConfig::Object: { output_filename += ".obj"; break; } case mcld::LinkerConfig::DynObj: { output_filename += ".dll"; break; } case mcld::LinkerConfig::Exec: { output_filename += ".exe"; break; } case mcld::LinkerConfig::External: break; default: { return false; break; } } // switch } else { if (mcld::LinkerConfig::Object == m_FileType || mcld::LinkerConfig::DynObj == m_FileType || mcld::LinkerConfig::Exec == m_FileType || mcld::LinkerConfig::External == m_FileType) { output_filename.assign("a.out"); } else { return false; } } } // end of if empty m_OutputFilename pModule.setName(output_filename); return true; }
// FIXME: LinkerConfig& pConfig should be constant bool MCLDEmulateELF(LinkerScript& pScript, LinkerConfig& pConfig) { // set up section map if (pConfig.options().getScriptList().empty() && pConfig.codeGenType() != LinkerConfig::Object) { const unsigned int map_size = (sizeof(map) / sizeof(map[0])); for (unsigned int i = 0; i < map_size; ++i) { std::pair<SectionMap::mapping, bool> res = pScript.sectionMap().insert(map[i].from, map[i].to, map[i].policy); if (!res.second) return false; } } else { // FIXME: this is the hack to help assignment processing in current // implementation. pScript.sectionMap().insert("", ""); } if (!pConfig.options().nostdlib()) { // TODO: check if user sets the default search path instead via -Y option // set up default search path switch (pConfig.targets().triple().getOS()) { case llvm::Triple::NetBSD: pScript.directories().insert("=/usr/lib"); break; case llvm::Triple::Win32: pScript.directories().insert("=/mingw/lib"); break; default: pScript.directories().insert("=/lib"); pScript.directories().insert("=/usr/lib"); break; } } return true; }
//===----------------------------------------------------------------------===// // ELFObjectReader //===----------------------------------------------------------------------===// /// constructor ELFObjectReader::ELFObjectReader(GNULDBackend& pBackend, IRBuilder& pBuilder, const LinkerConfig& pConfig) : ObjectReader(), m_pELFReader(NULL), m_pEhFrameReader(NULL), m_Builder(pBuilder), m_ReadFlag(ParseEhFrame), m_Backend(pBackend), m_Config(pConfig) { if (pConfig.targets().is32Bits() && pConfig.targets().isLittleEndian()) { m_pELFReader = new ELFReader<32, true>(pBackend); } else if (pConfig.targets().is64Bits() && pConfig.targets().isLittleEndian()) { m_pELFReader = new ELFReader<64, true>(pBackend); } m_pEhFrameReader = new EhFrameReader(); }
void ELFObjectWriter::writeELFHeader(const LinkerConfig& pConfig, const Module& pModule, MemoryArea& pOutput) const { typedef typename ELFSizeTraits<SIZE>::Ehdr ElfXX_Ehdr; typedef typename ELFSizeTraits<SIZE>::Shdr ElfXX_Shdr; typedef typename ELFSizeTraits<SIZE>::Phdr ElfXX_Phdr; // ELF header must start from 0x0 MemoryRegion *region = pOutput.request(0, sizeof(ElfXX_Ehdr)); ElfXX_Ehdr* header = (ElfXX_Ehdr*)region->start(); memcpy(header->e_ident, ElfMagic, EI_MAG3+1); header->e_ident[EI_CLASS] = (SIZE == 32) ? ELFCLASS32 : ELFCLASS64; header->e_ident[EI_DATA] = pConfig.targets().isLittleEndian()? ELFDATA2LSB : ELFDATA2MSB; header->e_ident[EI_VERSION] = target().getInfo().ELFVersion(); header->e_ident[EI_OSABI] = target().getInfo().OSABI(); header->e_ident[EI_ABIVERSION] = target().getInfo().ABIVersion(); // FIXME: add processor-specific and core file types. switch(pConfig.codeGenType()) { case LinkerConfig::Object: header->e_type = ET_REL; break; case LinkerConfig::DynObj: header->e_type = ET_DYN; break; case LinkerConfig::Exec: header->e_type = ET_EXEC; break; default: llvm::errs() << "unspported output file type: " << pConfig.codeGenType() << ".\n"; header->e_type = ET_NONE; } header->e_machine = target().getInfo().machine(); header->e_version = header->e_ident[EI_VERSION]; header->e_entry = getEntryPoint(pConfig, pModule); if (LinkerConfig::Object != pConfig.codeGenType()) header->e_phoff = sizeof(ElfXX_Ehdr); else header->e_phoff = 0x0; header->e_shoff = getLastStartOffset<SIZE>(pModule); header->e_flags = target().getInfo().flags(); header->e_ehsize = sizeof(ElfXX_Ehdr); header->e_phentsize = sizeof(ElfXX_Phdr); header->e_phnum = target().elfSegmentTable().size(); header->e_shentsize = sizeof(ElfXX_Shdr); header->e_shnum = pModule.size(); header->e_shstrndx = pModule.getSection(".shstrtab")->index(); }
static bool MCLDEmulateHexagonELF(LinkerConfig& pConfig) { if (!MCLDEmulateELF(pConfig)) return false; // set up bitclass and endian pConfig.targets().setEndian(TargetOptions::Little); pConfig.targets().setBitClass(32); // set up target-dependent constraints of attributes pConfig.attribute().constraint().enableWholeArchive(); pConfig.attribute().constraint().enableAsNeeded(); pConfig.attribute().constraint().setSharedSystem(); // set up the predefined attributes pConfig.attribute().predefined().unsetWholeArchive(); pConfig.attribute().predefined().unsetAsNeeded(); pConfig.attribute().predefined().setDynamic(); return true; }
/// includeMember - include the object member in the given file offset, and /// return the size of the object /// @param pConfig - LinkerConfig /// @param pArchiveRoot - the archive root /// @param pFileOffset - file offset of the member header in the archive size_t GNUArchiveReader::includeMember(const LinkerConfig& pConfig, Archive& pArchive, uint32_t pFileOffset) { Input* cur_archive = &(pArchive.getARFile()); Input* member = NULL; uint32_t file_offset = pFileOffset; size_t size = 0; do { uint32_t nested_offset = 0; // use the file offset in current archive to find out the member we // want to include member = readMemberHeader(pArchive, *cur_archive, file_offset, nested_offset, size); assert(member != NULL); // bypass if we get an archive that is already in the map if (Input::Archive == member->type()) { cur_archive = member; file_offset = nested_offset; continue; } // insert a node into the subtree of current archive. Archive::ArchiveMember* parent = pArchive.getArchiveMember(cur_archive->name()); assert(NULL != parent); pArchive.inputs().insert(parent->lastPos, *(parent->move), *member); // move the iterator to new created node, and also adjust the // direction to Afterward for next insertion in this subtree parent->move->move(parent->lastPos); parent->move = &InputTree::Afterward; bool doContinue = false; if (m_ELFObjectReader.isMyFormat(*member, doContinue)) { member->setType(Input::Object); pArchive.addObjectMember(pFileOffset, parent->lastPos); m_ELFObjectReader.readHeader(*member); m_ELFObjectReader.readSections(*member); m_ELFObjectReader.readSymbols(*member); m_Module.getObjectList().push_back(member); } else if (doContinue && isMyFormat(*member, doContinue)) { member->setType(Input::Archive); // when adding a new archive node, set the iterator to archive // itself, and set the direction to Downward pArchive.addArchiveMember(member->name(), parent->lastPos, &InputTree::Downward); cur_archive = member; file_offset = nested_offset; } else { warning(diag::warn_unrecognized_input_file) << member->path() << pConfig.targets().triple().str(); } } while (Input::Object != member->type()); return size; }
bool GroupReader::readGroup(Module::input_iterator pRoot, InputBuilder& pBuilder, const LinkerConfig& pConfig) { // record the number of total objects included in this sub-tree size_t cur_obj_cnt = 0; size_t last_obj_cnt = 0; size_t non_ar_obj_cnt = 0; // record the archive files in this sub-tree typedef std::vector<ArchiveListEntry*> ArchiveListType; ArchiveListType ar_list; Module::input_iterator input = --pRoot; // Since the end of a sub-tree is the same node to the end of whole tree, we // take the end of the whole input tree for conventience. Module::input_iterator input_end = m_Module.input_end(); // first time read the sub-tree while (input != input_end) { // already got type - for example, bitcode or external OIR (object // intermediate representation) if ((*input)->type() == Input::Script || (*input)->type() == Input::Object || (*input)->type() == Input::DynObj || (*input)->type() == Input::Archive || (*input)->type() == Input::External) { ++input; continue; } // is an archive if (m_ArchiveReader.isMyFormat(**input)) { (*input)->setType(Input::Archive); // record the Archive used by each archive node Archive* ar = new Archive(**input, pBuilder); ArchiveListEntry* entry = new ArchiveListEntry(*ar, input); ar_list.push_back(entry); // read archive m_ArchiveReader.readArchive(*ar); cur_obj_cnt += ar->numOfObjectMember(); } // is a relocatable object file else if (m_ObjectReader.isMyFormat(**input)) { (*input)->setType(Input::Object); m_ObjectReader.readHeader(**input); m_ObjectReader.readSections(**input); m_ObjectReader.readSymbols(**input); m_Module.getObjectList().push_back(*input); ++cur_obj_cnt; ++non_ar_obj_cnt; } // is a shared object file else if (m_DynObjReader.isMyFormat(**input)) { (*input)->setType(Input::DynObj); m_DynObjReader.readHeader(**input); m_DynObjReader.readSymbols(**input); m_Module.getLibraryList().push_back(*input); } else { fatal(diag::err_unrecognized_input_file) << (*input)->path() << pConfig.targets().triple().str(); } ++input; } // after read in all the archives, traverse the archive list in a loop until // there is no unresolved symbols added ArchiveListType::iterator it = ar_list.begin(); ArchiveListType::iterator end = ar_list.end(); while (cur_obj_cnt != last_obj_cnt) { last_obj_cnt = cur_obj_cnt; cur_obj_cnt = non_ar_obj_cnt; for (it = ar_list.begin(); it != end; ++it) { Archive& ar = (*it)->archive; // if --whole-archive is given to this archive, no need to read it again if ( ar.getARFile().attribute()->isWholeArchive()) continue; m_ArchiveReader.readArchive(ar); cur_obj_cnt += ar.numOfObjectMember(); } } // after all needed member included, merge the archive sub-tree to main // InputTree for (it = ar_list.begin(); it != end; ++it) { Archive& ar = (*it)->archive; if (ar.numOfObjectMember() > 0) { m_Module.getInputTree().merge<InputTree::Inclusive>((*it)->input, ar.inputs()); } } // cleanup ar_list for (it = ar_list.begin(); it != end; ++it) { delete &((*it)->archive); delete (*it); } ar_list.clear(); return true; }