1 //===- InputFiles.h ---------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLD_MACHO_INPUT_FILES_H
10 #define LLD_MACHO_INPUT_FILES_H
11 
12 #include "MachOStructs.h"
13 
14 #include "lld/Common/LLVM.h"
15 #include "lld/Common/Memory.h"
16 #include "llvm/ADT/DenseSet.h"
17 #include "llvm/ADT/SetVector.h"
18 #include "llvm/BinaryFormat/MachO.h"
19 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
20 #include "llvm/Object/Archive.h"
21 #include "llvm/Support/MemoryBuffer.h"
22 #include "llvm/TextAPI/TextAPIReader.h"
23 
24 #include <map>
25 #include <vector>
26 
27 namespace llvm {
28 namespace lto {
29 class InputFile;
30 } // namespace lto
31 namespace MachO {
32 class InterfaceFile;
33 } // namespace MachO
34 class TarWriter;
35 } // namespace llvm
36 
37 namespace lld {
38 namespace macho {
39 
40 struct PlatformInfo;
41 class InputSection;
42 class Symbol;
43 struct Reloc;
44 enum class RefState : uint8_t;
45 
46 // If --reproduce option is given, all input files are written
47 // to this tar archive.
48 extern std::unique_ptr<llvm::TarWriter> tar;
49 
50 // If .subsections_via_symbols is set, each InputSection will be split along
51 // symbol boundaries. The field offset represents the offset of the subsection
52 // from the start of the original pre-split InputSection.
53 struct SubsectionEntry {
54   uint64_t offset;
55   InputSection *isec;
56 };
57 using SubsectionMap = std::vector<SubsectionEntry>;
58 
59 class InputFile {
60 public:
61   enum Kind {
62     ObjKind,
63     OpaqueKind,
64     DylibKind,
65     ArchiveKind,
66     BitcodeKind,
67   };
68 
69   virtual ~InputFile() = default;
70   Kind kind() const { return fileKind; }
71   StringRef getName() const { return name; }
72 
73   MemoryBufferRef mb;
74 
75   std::vector<Symbol *> symbols;
76   std::vector<SubsectionMap> subsections;
77   // Provides an easy way to sort InputFiles deterministically.
78   const int id;
79 
80   // If not empty, this stores the name of the archive containing this file.
81   // We use this string for creating error messages.
82   std::string archiveName;
83 
84 protected:
85   InputFile(Kind kind, MemoryBufferRef mb)
86       : mb(mb), id(idCount++), fileKind(kind), name(mb.getBufferIdentifier()) {}
87 
88   InputFile(Kind, const llvm::MachO::InterfaceFile &);
89 
90 private:
91   const Kind fileKind;
92   const StringRef name;
93 
94   static int idCount;
95 };
96 
97 // .o file
98 class ObjFile : public InputFile {
99 public:
100   ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName);
101   static bool classof(const InputFile *f) { return f->kind() == ObjKind; }
102 
103   llvm::DWARFUnit *compileUnit = nullptr;
104   const uint32_t modTime;
105   std::vector<InputSection *> debugSections;
106 
107 private:
108   template <class LP> void parse();
109   template <class Section> void parseSections(ArrayRef<Section>);
110   template <class LP>
111   void parseSymbols(ArrayRef<typename LP::section> sectionHeaders,
112                     ArrayRef<typename LP::nlist> nList, const char *strtab,
113                     bool subsectionsViaSymbols);
114   template <class NList>
115   Symbol *parseNonSectionSymbol(const NList &sym, StringRef name);
116   template <class Section>
117   void parseRelocations(ArrayRef<Section> sectionHeaders, const Section &,
118                         SubsectionMap &);
119   void parseDebugInfo();
120 };
121 
122 // command-line -sectcreate file
123 class OpaqueFile : public InputFile {
124 public:
125   OpaqueFile(MemoryBufferRef mb, StringRef segName, StringRef sectName);
126   static bool classof(const InputFile *f) { return f->kind() == OpaqueKind; }
127 };
128 
129 // .dylib file
130 class DylibFile : public InputFile {
131 public:
132   // Mach-O dylibs can re-export other dylibs as sub-libraries, meaning that the
133   // symbols in those sub-libraries will be available under the umbrella
134   // library's namespace. Those sub-libraries can also have their own
135   // re-exports. When loading a re-exported dylib, `umbrella` should be set to
136   // the root dylib to ensure symbols in the child library are correctly bound
137   // to the root. On the other hand, if a dylib is being directly loaded
138   // (through an -lfoo flag), then `umbrella` should be a nullptr.
139   explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
140                      bool isBundleLoader = false);
141 
142   explicit DylibFile(const llvm::MachO::InterfaceFile &interface,
143                      DylibFile *umbrella = nullptr,
144                      bool isBundleLoader = false);
145 
146   static bool classof(const InputFile *f) { return f->kind() == DylibKind; }
147 
148   StringRef dylibName;
149   uint32_t compatibilityVersion = 0;
150   uint32_t currentVersion = 0;
151   int64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel
152   RefState refState;
153   bool reexport = false;
154   bool forceWeakImport = false;
155 
156   // An executable can be used as a bundle loader that will load the output
157   // file being linked, and that contains symbols referenced, but not
158   // implemented in the bundle. When used like this, it is very similar
159   // to a Dylib, so we re-used the same class to represent it.
160   bool isBundleLoader;
161 
162 private:
163   template <class LP> void parse(DylibFile *umbrella);
164 };
165 
166 // .a file
167 class ArchiveFile : public InputFile {
168 public:
169   explicit ArchiveFile(std::unique_ptr<llvm::object::Archive> &&file);
170   static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
171   void fetch(const llvm::object::Archive::Symbol &sym);
172 
173 private:
174   std::unique_ptr<llvm::object::Archive> file;
175   // Keep track of children fetched from the archive by tracking
176   // which address offsets have been fetched already.
177   llvm::DenseSet<uint64_t> seen;
178 };
179 
180 class BitcodeFile : public InputFile {
181 public:
182   explicit BitcodeFile(MemoryBufferRef mb);
183   static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
184 
185   std::unique_ptr<llvm::lto::InputFile> obj;
186 };
187 
188 extern llvm::SetVector<InputFile *> inputFiles;
189 
190 llvm::Optional<MemoryBufferRef> readFile(StringRef path);
191 
192 template <class CommandType = llvm::MachO::load_command, class Header,
193           class... Types>
194 const CommandType *findCommand(const Header *hdr, Types... types) {
195   std::initializer_list<uint32_t> typesList{types...};
196   const uint8_t *p = reinterpret_cast<const uint8_t *>(hdr) + sizeof(Header);
197 
198   for (uint32_t i = 0, n = hdr->ncmds; i < n; ++i) {
199     auto *cmd = reinterpret_cast<const CommandType *>(p);
200     if (llvm::is_contained(typesList, cmd->cmd))
201       return cmd;
202     p += cmd->cmdsize;
203   }
204   return nullptr;
205 }
206 
207 } // namespace macho
208 
209 std::string toString(const macho::InputFile *file);
210 } // namespace lld
211 
212 #endif
213