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