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/BinaryFormat/MachO.h"
18 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
19 #include "llvm/Object/Archive.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "llvm/TextAPI/MachO/InterfaceFile.h"
22 #include "llvm/TextAPI/MachO/TextAPIReader.h"
23 
24 #include <map>
25 #include <vector>
26 
27 namespace llvm {
28 namespace lto {
29 class InputFile;
30 } // namespace lto
31 class TarWriter;
32 } // namespace llvm
33 
34 namespace lld {
35 namespace macho {
36 
37 class InputSection;
38 class Symbol;
39 struct Reloc;
40 
41 // If --reproduce option is given, all input files are written
42 // to this tar archive.
43 extern std::unique_ptr<llvm::TarWriter> tar;
44 
45 // If .subsections_via_symbols is set, each InputSection will be split along
46 // symbol boundaries. The keys of a SubsectionMap represent the offsets of
47 // each subsection from the start of the original pre-split InputSection.
48 using SubsectionMap = std::map<uint32_t, InputSection *>;
49 
50 class InputFile {
51 public:
52   enum Kind {
53     ObjKind,
54     OpaqueKind,
55     DylibKind,
56     ArchiveKind,
57     BitcodeKind,
58   };
59 
60   virtual ~InputFile() = default;
kind()61   Kind kind() const { return fileKind; }
getName()62   StringRef getName() const { return name; }
63 
64   MemoryBufferRef mb;
65 
66   std::vector<Symbol *> symbols;
67   std::vector<SubsectionMap> subsections;
68   // Provides an easy way to sort InputFiles deterministically.
69   const int id;
70 
71   // If not empty, this stores the name of the archive containing this file.
72   // We use this string for creating error messages.
73   std::string archiveName;
74 
75 protected:
InputFile(Kind kind,MemoryBufferRef mb)76   InputFile(Kind kind, MemoryBufferRef mb)
77       : mb(mb), id(idCount++), fileKind(kind), name(mb.getBufferIdentifier()) {}
78 
InputFile(Kind kind,const llvm::MachO::InterfaceFile & interface)79   InputFile(Kind kind, const llvm::MachO::InterfaceFile &interface)
80       : id(idCount++), fileKind(kind), name(saver.save(interface.getPath())) {}
81 
82 private:
83   const Kind fileKind;
84   const StringRef name;
85 
86   static int idCount;
87 };
88 
89 // .o file
90 class ObjFile : public InputFile {
91 public:
92   ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName);
classof(const InputFile * f)93   static bool classof(const InputFile *f) { return f->kind() == ObjKind; }
94 
95   llvm::DWARFUnit *compileUnit = nullptr;
96   const uint32_t modTime;
97   ArrayRef<llvm::MachO::section_64> sectionHeaders;
98 
99 private:
100   void parseSections(ArrayRef<llvm::MachO::section_64>);
101   void parseSymbols(ArrayRef<lld::structs::nlist_64> nList, const char *strtab,
102                     bool subsectionsViaSymbols);
103   Symbol *parseNonSectionSymbol(const structs::nlist_64 &sym, StringRef name);
104   void parseRelocations(const llvm::MachO::section_64 &, SubsectionMap &);
105   void parseDebugInfo();
106 };
107 
108 // command-line -sectcreate file
109 class OpaqueFile : public InputFile {
110 public:
111   OpaqueFile(MemoryBufferRef mb, StringRef segName, StringRef sectName);
classof(const InputFile * f)112   static bool classof(const InputFile *f) { return f->kind() == OpaqueKind; }
113 };
114 
115 // .dylib file
116 class DylibFile : public InputFile {
117 public:
118   // Mach-O dylibs can re-export other dylibs as sub-libraries, meaning that the
119   // symbols in those sub-libraries will be available under the umbrella
120   // library's namespace. Those sub-libraries can also have their own
121   // re-exports. When loading a re-exported dylib, `umbrella` should be set to
122   // the root dylib to ensure symbols in the child library are correctly bound
123   // to the root. On the other hand, if a dylib is being directly loaded
124   // (through an -lfoo flag), then `umbrella` should be a nullptr.
125   explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella = nullptr);
126 
127   explicit DylibFile(const llvm::MachO::InterfaceFile &interface,
128                      DylibFile *umbrella = nullptr);
129 
classof(const InputFile * f)130   static bool classof(const InputFile *f) { return f->kind() == DylibKind; }
131 
132   StringRef dylibName;
133   uint64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel
134   bool reexport = false;
135   bool forceWeakImport = false;
136   std::vector<DylibFile *> reexported;
137 };
138 
139 // .a file
140 class ArchiveFile : public InputFile {
141 public:
142   explicit ArchiveFile(std::unique_ptr<llvm::object::Archive> &&file);
classof(const InputFile * f)143   static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
144   void fetch(const llvm::object::Archive::Symbol &sym);
145 
146 private:
147   std::unique_ptr<llvm::object::Archive> file;
148   // Keep track of children fetched from the archive by tracking
149   // which address offsets have been fetched already.
150   llvm::DenseSet<uint64_t> seen;
151 };
152 
153 class BitcodeFile : public InputFile {
154 public:
155   explicit BitcodeFile(MemoryBufferRef mb);
classof(const InputFile * f)156   static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
157 
158   std::unique_ptr<llvm::lto::InputFile> obj;
159 };
160 
161 extern std::vector<InputFile *> inputFiles;
162 
163 llvm::Optional<MemoryBufferRef> readFile(StringRef path);
164 
165 const llvm::MachO::load_command *
166 findCommand(const llvm::MachO::mach_header_64 *, uint32_t type);
167 
168 } // namespace macho
169 
170 std::string toString(const macho::InputFile *file);
171 } // namespace lld
172 
173 #endif
174