Mercurial > hg > CbC > CbC_llvm
diff lld/MachO/InputFiles.h @ 207:2e18cbf3894f
LLVM12
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 08 Jun 2021 06:07:14 +0900 |
parents | 0572611fdcc8 |
children | 5f17cb93ff66 |
line wrap: on
line diff
--- a/lld/MachO/InputFiles.h Mon May 25 11:55:54 2020 +0900 +++ b/lld/MachO/InputFiles.h Tue Jun 08 06:07:14 2021 +0900 @@ -9,66 +9,125 @@ #ifndef LLD_MACHO_INPUT_FILES_H #define LLD_MACHO_INPUT_FILES_H +#include "MachOStructs.h" +#include "Target.h" + #include "lld/Common/LLVM.h" +#include "lld/Common/Memory.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" #include "llvm/BinaryFormat/MachO.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/Object/Archive.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/TextAPI/TextAPIReader.h" #include <map> #include <vector> +namespace llvm { +namespace lto { +class InputFile; +} // namespace lto +namespace MachO { +class InterfaceFile; +} // namespace MachO +class TarWriter; +} // namespace llvm + namespace lld { namespace macho { +struct PlatformInfo; class InputSection; class Symbol; struct Reloc; +enum class RefState : uint8_t; + +// If --reproduce option is given, all input files are written +// to this tar archive. +extern std::unique_ptr<llvm::TarWriter> tar; // If .subsections_via_symbols is set, each InputSection will be split along -// symbol boundaries. The keys of a SubsectionMap represent the offsets of -// each subsection from the start of the original pre-split InputSection. -using SubsectionMap = std::map<uint32_t, InputSection *>; +// symbol boundaries. The field offset represents the offset of the subsection +// from the start of the original pre-split InputSection. +struct SubsectionEntry { + uint64_t offset; + InputSection *isec; +}; +using SubsectionMap = std::vector<SubsectionEntry>; class InputFile { public: enum Kind { ObjKind, + OpaqueKind, DylibKind, ArchiveKind, + BitcodeKind, }; virtual ~InputFile() = default; Kind kind() const { return fileKind; } - StringRef getName() const { return mb.getBufferIdentifier(); } + StringRef getName() const { return name; } MemoryBufferRef mb; + std::vector<Symbol *> symbols; - ArrayRef<llvm::MachO::section_64> sectionHeaders; std::vector<SubsectionMap> subsections; + // Provides an easy way to sort InputFiles deterministically. + const int id; + + // If not empty, this stores the name of the archive containing this file. + // We use this string for creating error messages. + std::string archiveName; protected: - InputFile(Kind kind, MemoryBufferRef mb) : mb(mb), fileKind(kind) {} - - void parseSections(ArrayRef<llvm::MachO::section_64>); + InputFile(Kind kind, MemoryBufferRef mb) + : mb(mb), id(idCount++), fileKind(kind), name(mb.getBufferIdentifier()) {} - void parseSymbols(ArrayRef<llvm::MachO::nlist_64> nList, const char *strtab, - bool subsectionsViaSymbols); - - void parseRelocations(const llvm::MachO::section_64 &, SubsectionMap &); + InputFile(Kind, const llvm::MachO::InterfaceFile &); private: const Kind fileKind; + const StringRef name; + + static int idCount; }; // .o file class ObjFile : public InputFile { public: - explicit ObjFile(MemoryBufferRef mb); + ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName); static bool classof(const InputFile *f) { return f->kind() == ObjKind; } + + llvm::DWARFUnit *compileUnit = nullptr; + const uint32_t modTime; + std::vector<InputSection *> debugSections; + +private: + template <class LP> void parse(); + template <class Section> void parseSections(ArrayRef<Section>); + template <class LP> + void parseSymbols(ArrayRef<typename LP::section> sectionHeaders, + ArrayRef<typename LP::nlist> nList, const char *strtab, + bool subsectionsViaSymbols); + template <class NList> + Symbol *parseNonSectionSymbol(const NList &sym, StringRef name); + template <class Section> + void parseRelocations(ArrayRef<Section> sectionHeaders, const Section &, + SubsectionMap &); + void parseDebugInfo(); }; -// .dylib file +// command-line -sectcreate file +class OpaqueFile : public InputFile { +public: + OpaqueFile(MemoryBufferRef mb, StringRef segName, StringRef sectName); + static bool classof(const InputFile *f) { return f->kind() == OpaqueKind; } +}; + +// .dylib or .tbd file class DylibFile : public InputFile { public: // Mach-O dylibs can re-export other dylibs as sub-libraries, meaning that the @@ -78,18 +137,47 @@ // the root dylib to ensure symbols in the child library are correctly bound // to the root. On the other hand, if a dylib is being directly loaded // (through an -lfoo flag), then `umbrella` should be a nullptr. - explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella = nullptr); + explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella, + bool isBundleLoader = false); + explicit DylibFile(const llvm::MachO::InterfaceFile &interface, + DylibFile *umbrella = nullptr, + bool isBundleLoader = false); + + void parseLoadCommands(MemoryBufferRef mb); + void parseReexports(const llvm::MachO::InterfaceFile &interface); + static bool classof(const InputFile *f) { return f->kind() == DylibKind; } - // Do not use this constructor!! This is meant only for createLibSystemMock(), - // but it cannot be made private as we call it via make(). - DylibFile(); - static DylibFile *createLibSystemMock(); + StringRef installName; + DylibFile *exportingFile = nullptr; + DylibFile *umbrella; + SmallVector<StringRef, 2> rpaths; + uint32_t compatibilityVersion = 0; + uint32_t currentVersion = 0; + int64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel + RefState refState; + bool reexport = false; + bool forceNeeded = false; + bool forceWeakImport = false; + bool deadStrippable = false; + bool explicitlyLinked = false; - StringRef dylibName; - uint64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel - bool reexport = false; - std::vector<DylibFile *> reexported; + unsigned numReferencedSymbols = 0; + + bool isReferenced() const { + return numReferencedSymbols > 0; + } + + // An executable can be used as a bundle loader that will load the output + // file being linked, and that contains symbols referenced, but not + // implemented in the bundle. When used like this, it is very similar + // to a Dylib, so we re-used the same class to represent it. + bool isBundleLoader; + +private: + bool handleLDSymbol(StringRef originalName); + void handleLDPreviousSymbol(StringRef name, StringRef originalName); + void handleLDInstallNameSymbol(StringRef name, StringRef originalName); }; // .a file @@ -106,10 +194,56 @@ llvm::DenseSet<uint64_t> seen; }; -extern std::vector<InputFile *> inputFiles; +class BitcodeFile : public InputFile { +public: + explicit BitcodeFile(MemoryBufferRef mb); + static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; } + + std::unique_ptr<llvm::lto::InputFile> obj; +}; + +extern llvm::SetVector<InputFile *> inputFiles; llvm::Optional<MemoryBufferRef> readFile(StringRef path); +namespace detail { + +template <class CommandType, class... Types> +std::vector<const CommandType *> +findCommands(const void *anyHdr, size_t maxCommands, Types... types) { + std::vector<const CommandType *> cmds; + std::initializer_list<uint32_t> typesList{types...}; + const auto *hdr = reinterpret_cast<const llvm::MachO::mach_header *>(anyHdr); + const uint8_t *p = + reinterpret_cast<const uint8_t *>(hdr) + target->headerSize; + for (uint32_t i = 0, n = hdr->ncmds; i < n; ++i) { + auto *cmd = reinterpret_cast<const CommandType *>(p); + if (llvm::is_contained(typesList, cmd->cmd)) { + cmds.push_back(cmd); + if (cmds.size() == maxCommands) + return cmds; + } + p += cmd->cmdsize; + } + return cmds; +} + +} // namespace detail + +// anyHdr should be a pointer to either mach_header or mach_header_64 +template <class CommandType = llvm::MachO::load_command, class... Types> +const CommandType *findCommand(const void *anyHdr, Types... types) { + std::vector<const CommandType *> cmds = + detail::findCommands<CommandType>(anyHdr, 1, types...); + return cmds.size() ? cmds[0] : nullptr; +} + +template <class CommandType = llvm::MachO::load_command, class... Types> +std::vector<const CommandType *> findCommands(const void *anyHdr, + Types... types) { + return detail::findCommands<CommandType>(anyHdr, 0, types...); +} + } // namespace macho std::string toString(const macho::InputFile *file);