xref: /llvm-project-15.0.7/lld/MachO/Driver.cpp (revision eaebcbc6)
1 //===- Driver.cpp ---------------------------------------------------------===//
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 #include "Driver.h"
10 #include "Config.h"
11 #include "InputFiles.h"
12 #include "OutputSection.h"
13 #include "OutputSegment.h"
14 #include "SymbolTable.h"
15 #include "Symbols.h"
16 #include "Target.h"
17 #include "Writer.h"
18 
19 #include "lld/Common/Args.h"
20 #include "lld/Common/Driver.h"
21 #include "lld/Common/ErrorHandler.h"
22 #include "lld/Common/LLVM.h"
23 #include "lld/Common/Memory.h"
24 #include "lld/Common/Version.h"
25 #include "llvm/ADT/DenseSet.h"
26 #include "llvm/ADT/StringExtras.h"
27 #include "llvm/ADT/StringRef.h"
28 #include "llvm/BinaryFormat/MachO.h"
29 #include "llvm/BinaryFormat/Magic.h"
30 #include "llvm/Object/Archive.h"
31 #include "llvm/Option/ArgList.h"
32 #include "llvm/Option/Option.h"
33 #include "llvm/Support/MemoryBuffer.h"
34 #include "llvm/Support/Path.h"
35 
36 using namespace llvm;
37 using namespace llvm::MachO;
38 using namespace llvm::sys;
39 using namespace lld;
40 using namespace lld::macho;
41 
42 Configuration *lld::macho::config;
43 
44 // Create prefix string literals used in Options.td
45 #define PREFIX(NAME, VALUE) const char *NAME[] = VALUE;
46 #include "Options.inc"
47 #undef PREFIX
48 
49 // Create table mapping all options defined in Options.td
50 static const opt::OptTable::Info optInfo[] = {
51 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
52   {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
53    X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
54 #include "Options.inc"
55 #undef OPTION
56 };
57 
58 MachOOptTable::MachOOptTable() : OptTable(optInfo) {}
59 
60 opt::InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) {
61   // Make InputArgList from string vectors.
62   unsigned missingIndex;
63   unsigned missingCount;
64   SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
65 
66   opt::InputArgList args = ParseArgs(vec, missingIndex, missingCount);
67 
68   if (missingCount)
69     error(Twine(args.getArgString(missingIndex)) + ": missing argument");
70 
71   for (opt::Arg *arg : args.filtered(OPT_UNKNOWN))
72     error("unknown argument: " + arg->getSpelling());
73   return args;
74 }
75 
76 // This is for -lfoo. We'll look for libfoo.dylib from search paths.
77 static Optional<std::string> findDylib(StringRef name) {
78   for (StringRef dir : config->searchPaths) {
79     std::string path = (dir + "/lib" + name + ".dylib").str();
80     if (fs::exists(path))
81       return path;
82   }
83   error("library not found for -l" + name);
84   return None;
85 }
86 
87 static TargetInfo *createTargetInfo(opt::InputArgList &args) {
88   StringRef s = args.getLastArgValue(OPT_arch, "x86_64");
89   if (s != "x86_64")
90     error("missing or unsupported -arch " + s);
91   return createX86_64TargetInfo();
92 }
93 
94 static std::vector<StringRef> getSearchPaths(opt::InputArgList &args) {
95   std::vector<StringRef> ret{args::getStrings(args, OPT_L)};
96   if (!args.hasArg(OPT_Z)) {
97     ret.push_back("/usr/lib");
98     ret.push_back("/usr/local/lib");
99   }
100   return ret;
101 }
102 
103 static void addFile(StringRef path) {
104   Optional<MemoryBufferRef> buffer = readFile(path);
105   if (!buffer)
106     return;
107   MemoryBufferRef mbref = *buffer;
108 
109   switch (identify_magic(mbref.getBuffer())) {
110   case file_magic::archive: {
111     std::unique_ptr<object::Archive> file = CHECK(
112         object::Archive::create(mbref), path + ": failed to parse archive");
113 
114     if (!file->isEmpty() && !file->hasSymbolTable())
115       error(path + ": archive has no index; run ranlib to add one");
116 
117     inputFiles.push_back(make<ArchiveFile>(std::move(file)));
118     break;
119   }
120   case file_magic::macho_object:
121     inputFiles.push_back(make<ObjFile>(mbref));
122     break;
123   case file_magic::macho_dynamically_linked_shared_lib:
124     inputFiles.push_back(make<DylibFile>(mbref));
125     break;
126   default:
127     error(path + ": unhandled file type");
128   }
129 }
130 
131 static std::array<StringRef, 6> archNames{"arm",    "arm64", "i386",
132                                           "x86_64", "ppc",   "ppc64"};
133 static bool isArchString(StringRef s) {
134   static DenseSet<StringRef> archNamesSet(archNames.begin(), archNames.end());
135   return archNamesSet.find(s) != archNamesSet.end();
136 }
137 
138 // An order file has one entry per line, in the following format:
139 //
140 //   <arch>:<object file>:<symbol name>
141 //
142 // <arch> and <object file> are optional. If not specified, then that entry
143 // matches any symbol of that name.
144 //
145 // If a symbol is matched by multiple entries, then it takes the lowest-ordered
146 // entry (the one nearest to the front of the list.)
147 //
148 // The file can also have line comments that start with '#'.
149 void parseOrderFile(StringRef path) {
150   Optional<MemoryBufferRef> buffer = readFile(path);
151   if (!buffer) {
152     error("Could not read order file at " + path);
153     return;
154   }
155 
156   MemoryBufferRef mbref = *buffer;
157   size_t priority = std::numeric_limits<size_t>::max();
158   for (StringRef rest : args::getLines(mbref)) {
159     StringRef arch, objectFile, symbol;
160 
161     std::array<StringRef, 3> fields;
162     uint8_t fieldCount = 0;
163     while (rest != "" && fieldCount < 3) {
164       std::pair<StringRef, StringRef> p = getToken(rest, ": \t\n\v\f\r");
165       StringRef tok = p.first;
166       rest = p.second;
167 
168       // Check if we have a comment
169       if (tok == "" || tok[0] == '#')
170         break;
171 
172       fields[fieldCount++] = tok;
173     }
174 
175     switch (fieldCount) {
176     case 3:
177       arch = fields[0];
178       objectFile = fields[1];
179       symbol = fields[2];
180       break;
181     case 2:
182       (isArchString(fields[0]) ? arch : objectFile) = fields[0];
183       symbol = fields[1];
184       break;
185     case 1:
186       symbol = fields[0];
187       break;
188     case 0:
189       break;
190     default:
191       llvm_unreachable("too many fields in order file");
192     }
193 
194     if (!arch.empty()) {
195       if (!isArchString(arch)) {
196         error("invalid arch \"" + arch + "\" in order file: expected one of " +
197               llvm::join(archNames, ", "));
198         continue;
199       }
200 
201       // TODO: Update when we extend support for other archs
202       if (arch != "x86_64")
203         continue;
204     }
205 
206     if (!objectFile.empty() && !objectFile.endswith(".o")) {
207       error("invalid object file name \"" + objectFile +
208             "\" in order file: should end with .o");
209       continue;
210     }
211 
212     if (!symbol.empty()) {
213       SymbolPriorityEntry &entry = config->priorities[symbol];
214       if (!objectFile.empty())
215         entry.objectFiles.insert(std::make_pair(objectFile, priority));
216       else
217         entry.anyObjectFile = std::max(entry.anyObjectFile, priority);
218     }
219 
220     --priority;
221   }
222 }
223 
224 // We expect sub-library names of the form "libfoo", which will match a dylib
225 // with a path of .*/libfoo.dylib.
226 static bool markSubLibrary(StringRef searchName) {
227   for (InputFile *file : inputFiles) {
228     if (auto *dylibFile = dyn_cast<DylibFile>(file)) {
229       StringRef filename = path::filename(dylibFile->getName());
230       if (filename.consume_front(searchName) && filename == ".dylib") {
231         dylibFile->reexport = true;
232         return true;
233       }
234     }
235   }
236   return false;
237 }
238 
239 static void handlePlatformVersion(opt::ArgList::iterator &it,
240                                   const opt::ArgList::iterator &end) {
241   // -platform_version takes 3 args, which LLVM's option library doesn't
242   // support directly.  So this explicitly handles that.
243   // FIXME: stash skipped args for later use.
244   for (int i = 0; i < 3; ++i) {
245     ++it;
246     if (it == end || (*it)->getOption().getID() != OPT_INPUT)
247       fatal("usage: -platform_version platform min_version sdk_version");
248   }
249 }
250 
251 bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
252                  raw_ostream &stdoutOS, raw_ostream &stderrOS) {
253   lld::stdoutOS = &stdoutOS;
254   lld::stderrOS = &stderrOS;
255 
256   stderrOS.enable_colors(stderrOS.has_colors());
257   // TODO: Set up error handler properly, e.g. the errorLimitExceededMsg
258 
259   MachOOptTable parser;
260   opt::InputArgList args = parser.parse(argsArr.slice(1));
261 
262   config = make<Configuration>();
263   symtab = make<SymbolTable>();
264   target = createTargetInfo(args);
265 
266   config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main"));
267   config->outputFile = args.getLastArgValue(OPT_o, "a.out");
268   config->installName =
269       args.getLastArgValue(OPT_install_name, config->outputFile);
270   config->searchPaths = getSearchPaths(args);
271   config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE;
272 
273   if (args.hasArg(OPT_v)) {
274     message(getLLDVersion());
275     std::vector<StringRef> &searchPaths = config->searchPaths;
276     message("Library search paths:\n" +
277             llvm::join(searchPaths.begin(), searchPaths.end(), "\n"));
278     freeArena();
279     return !errorCount();
280   }
281 
282   for (opt::ArgList::iterator it = args.begin(), end = args.end(); it != end;
283        ++it) {
284     const opt::Arg *arg = *it;
285     switch (arg->getOption().getID()) {
286     case OPT_INPUT:
287       addFile(arg->getValue());
288       break;
289     case OPT_l:
290       if (Optional<std::string> path = findDylib(arg->getValue()))
291         addFile(*path);
292       break;
293     case OPT_platform_version: {
294       handlePlatformVersion(it, end); // Can advance "it".
295       break;
296     }
297     }
298   }
299 
300   // Now that all dylibs have been loaded, search for those that should be
301   // re-exported.
302   for (opt::Arg *arg : args.filtered(OPT_sub_library)) {
303     config->hasReexports = true;
304     StringRef searchName = arg->getValue();
305     if (!markSubLibrary(searchName))
306       error("-sub_library " + searchName + " does not match a supplied dylib");
307   }
308 
309   StringRef orderFile = args.getLastArgValue(OPT_order_file);
310   if (!orderFile.empty())
311     parseOrderFile(orderFile);
312 
313   // dyld requires us to load libSystem. Since we may run tests on non-OSX
314   // systems which do not have libSystem, we mock it out here.
315   // TODO: Replace this with a stub tbd file once we have TAPI support.
316   if (StringRef(getenv("LLD_IN_TEST")) == "1" &&
317       config->outputType == MH_EXECUTE) {
318     inputFiles.push_back(DylibFile::createLibSystemMock());
319   }
320 
321   if (config->outputType == MH_EXECUTE && !isa<Defined>(config->entry)) {
322     error("undefined symbol: " + config->entry->getName());
323     return false;
324   }
325 
326   createSyntheticSections();
327 
328   // Initialize InputSections.
329   for (InputFile *file : inputFiles) {
330     for (SubsectionMap &map : file->subsections) {
331       for (auto &p : map) {
332         InputSection *isec = p.second;
333         inputSections.push_back(isec);
334       }
335     }
336   }
337 
338   // Write to an output file.
339   writeResult();
340 
341   if (canExitEarly)
342     exitLld(errorCount() ? 1 : 0);
343 
344   freeArena();
345   return !errorCount();
346 }
347