//===- lib/ReaderWriter/MachO/File.h --------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_READER_WRITER_MACHO_FILE_H #define LLD_READER_WRITER_MACHO_FILE_H #include "llvm/ADT/StringMap.h" #include "Atoms.h" #include "lld/Core/Simple.h" #include "lld/Core/SharedLibraryFile.h" #include namespace lld { namespace mach_o { using lld::mach_o::normalized::Section; class MachOFile : public SimpleFile { public: MachOFile(StringRef path) : SimpleFile(path) {} void addDefinedAtom(StringRef name, Atom::Scope scope, DefinedAtom::ContentType type, DefinedAtom::Merge merge, uint64_t sectionOffset, uint64_t contentSize, bool thumb, bool copyRefs, const Section *inSection) { assert(sectionOffset+contentSize <= inSection->content.size()); ArrayRef content = inSection->content.slice(sectionOffset, contentSize); if (copyRefs) { // Make a copy of the atom's name and content that is owned by this file. name = name.copy(_allocator); content = content.copy(_allocator); } MachODefinedAtom *atom = new (_allocator) MachODefinedAtom(*this, name, scope, type, merge, thumb, content); addAtomForSection(inSection, atom, sectionOffset); } void addDefinedAtomInCustomSection(StringRef name, Atom::Scope scope, DefinedAtom::ContentType type, DefinedAtom::Merge merge, bool thumb, uint64_t sectionOffset, uint64_t contentSize, StringRef sectionName, bool copyRefs, const Section *inSection) { assert(sectionOffset+contentSize <= inSection->content.size()); ArrayRef content = inSection->content.slice(sectionOffset, contentSize); if (copyRefs) { // Make a copy of the atom's name and content that is owned by this file. name = name.copy(_allocator); content = content.copy(_allocator); sectionName = sectionName.copy(_allocator); } MachODefinedCustomSectionAtom *atom = new (_allocator) MachODefinedCustomSectionAtom(*this, name, scope, type, merge, thumb, content, sectionName); addAtomForSection(inSection, atom, sectionOffset); } void addZeroFillDefinedAtom(StringRef name, Atom::Scope scope, uint64_t sectionOffset, uint64_t size, bool copyRefs, const Section *inSection) { if (copyRefs) { // Make a copy of the atom's name and content that is owned by this file. name = name.copy(_allocator); } MachODefinedAtom *atom = new (_allocator) MachODefinedAtom(*this, name, scope, size); addAtomForSection(inSection, atom, sectionOffset); } void addUndefinedAtom(StringRef name, bool copyRefs) { if (copyRefs) { // Make a copy of the atom's name that is owned by this file. name = name.copy(_allocator); } SimpleUndefinedAtom *atom = new (_allocator) SimpleUndefinedAtom(*this, name); addAtom(*atom); _undefAtoms[name] = atom; } void addTentativeDefAtom(StringRef name, Atom::Scope scope, uint64_t size, DefinedAtom::Alignment align, bool copyRefs) { if (copyRefs) { // Make a copy of the atom's name that is owned by this file. name = name.copy(_allocator); } MachOTentativeDefAtom *atom = new (_allocator) MachOTentativeDefAtom(*this, name, scope, size, align); addAtom(*atom); _undefAtoms[name] = atom; } /// Search this file for an the atom from 'section' that covers /// 'offsetInSect'. Returns nullptr is no atom found. MachODefinedAtom *findAtomCoveringAddress(const Section §ion, uint64_t offsetInSect, uint32_t *foundOffsetAtom=nullptr) { auto pos = _sectionAtoms.find(§ion); if (pos == _sectionAtoms.end()) return nullptr; auto vec = pos->second; assert(offsetInSect < section.content.size()); // Vector of atoms for section are already sorted, so do binary search. auto atomPos = std::lower_bound(vec.begin(), vec.end(), offsetInSect, [offsetInSect](const SectionOffsetAndAtom &ao, uint64_t targetAddr) -> bool { // Each atom has a start offset of its slice of the // section's content. This compare function must return true // iff the atom's range is before the offset being searched for. uint64_t atomsEndOffset = ao.offset+ao.atom->rawContent().size(); return (atomsEndOffset <= offsetInSect); }); if (atomPos == vec.end()) return nullptr; if (foundOffsetAtom) *foundOffsetAtom = offsetInSect - atomPos->offset; return atomPos->atom; } /// Searches this file for an UndefinedAtom named 'name'. Returns /// nullptr is no such atom found. const lld::Atom *findUndefAtom(StringRef name) { auto pos = _undefAtoms.find(name); if (pos == _undefAtoms.end()) return nullptr; return pos->second; } private: struct SectionOffsetAndAtom { uint64_t offset; MachODefinedAtom *atom; }; void addAtomForSection(const Section *inSection, MachODefinedAtom* atom, uint64_t sectionOffset) { SectionOffsetAndAtom offAndAtom; offAndAtom.offset = sectionOffset; offAndAtom.atom = atom; _sectionAtoms[inSection].push_back(offAndAtom); addAtom(*atom); } typedef llvm::DenseMap> SectionToAtoms; typedef llvm::StringMap NameToAtom; llvm::BumpPtrAllocator _allocator; SectionToAtoms _sectionAtoms; NameToAtom _undefAtoms; }; class MachODylibFile : public SharedLibraryFile { public: MachODylibFile(StringRef path) : SharedLibraryFile(path), _dylib_name(path) {} virtual const SharedLibraryAtom *exports(StringRef name, bool dataSymbolOnly) const { // FIXME: we obviously need to record code/data if we're going to make // proper use of dataSymbolOnly. auto sym = _nameToAtom.find(name); if (sym == _nameToAtom.end()) return nullptr; if (!sym->second) sym->second = new (_allocator) MachOSharedLibraryAtom(*this, name, _dylib_name); return sym->second; } const atom_collection &defined() const override { return _definedAtoms; } const atom_collection &undefined() const override { return _undefinedAtoms; } const atom_collection &sharedLibrary() const override { return _sharedLibraryAtoms; } const atom_collection &absolute() const override { return _absoluteAtoms; } void addSharedLibraryAtom(StringRef name, bool copyRefs) { if (copyRefs) { name = name.copy(_allocator); } _nameToAtom[name] = nullptr; } private: StringRef _dylib_name; atom_collection_vector _definedAtoms; atom_collection_vector _undefinedAtoms; atom_collection_vector _sharedLibraryAtoms; atom_collection_vector _absoluteAtoms; mutable std::unordered_map _nameToAtom; mutable llvm::BumpPtrAllocator _allocator; }; } // end namespace mach_o } // end namespace lld #endif