xref: /llvm-project-15.0.7/lld/MachO/Driver.cpp (revision e2d0b44a)
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/FileSystem.h"
34 #include "llvm/Support/Host.h"
35 #include "llvm/Support/MemoryBuffer.h"
36 #include "llvm/Support/Path.h"
37 
38 using namespace llvm;
39 using namespace llvm::MachO;
40 using namespace llvm::sys;
41 using namespace llvm::opt;
42 using namespace lld;
43 using namespace lld::macho;
44 
45 Configuration *lld::macho::config;
46 
47 // Create prefix string literals used in Options.td
48 #define PREFIX(NAME, VALUE) const char *NAME[] = VALUE;
49 #include "Options.inc"
50 #undef PREFIX
51 
52 // Create table mapping all options defined in Options.td
53 static const opt::OptTable::Info optInfo[] = {
54 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
55   {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
56    X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
57 #include "Options.inc"
58 #undef OPTION
59 };
60 
61 MachOOptTable::MachOOptTable() : OptTable(optInfo) {}
62 
63 opt::InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) {
64   // Make InputArgList from string vectors.
65   unsigned missingIndex;
66   unsigned missingCount;
67   SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
68 
69   opt::InputArgList args = ParseArgs(vec, missingIndex, missingCount);
70 
71   if (missingCount)
72     error(Twine(args.getArgString(missingIndex)) + ": missing argument");
73 
74   for (opt::Arg *arg : args.filtered(OPT_UNKNOWN))
75     error("unknown argument: " + arg->getSpelling());
76   return args;
77 }
78 
79 void MachOOptTable::printHelp(const char *argv0, bool showHidden) const {
80   PrintHelp(lld::outs(), (std::string(argv0) + " [options] file...").c_str(),
81             "LLVM Linker", showHidden);
82   lld::outs() << "\n";
83 }
84 
85 static Optional<std::string> findLibrary(StringRef name) {
86   std::string stub = (llvm::Twine("lib") + name + ".tbd").str();
87   std::string shared = (llvm::Twine("lib") + name + ".dylib").str();
88   std::string archive = (llvm::Twine("lib") + name + ".a").str();
89   llvm::SmallString<260> location;
90 
91   for (StringRef dir : config->librarySearchPaths) {
92     for (StringRef library : {stub, shared, archive}) {
93       location = dir;
94       llvm::sys::path::append(location, library);
95       if (fs::exists(location))
96         return location.str().str();
97     }
98   }
99   return {};
100 }
101 
102 static Optional<std::string> findFramework(StringRef name) {
103   // TODO: support .tbd files
104   llvm::SmallString<260> symlink;
105   llvm::SmallString<260> location;
106   StringRef suffix;
107   std::tie(name, suffix) = name.split(",");
108   for (StringRef dir : config->frameworkSearchPaths) {
109     symlink = dir;
110     path::append(symlink, name + ".framework", name);
111     // If the symlink fails to resolve, skip to the next search path.
112     // NOTE: we must resolve the symlink before trying the suffixes, because
113     // there are no symlinks for the suffixed paths.
114     if (fs::real_path(symlink, location))
115       continue;
116     if (!suffix.empty()) {
117       llvm::Twine suffixed = location + suffix;
118       if (fs::exists(suffixed))
119         return suffixed.str();
120       // Suffix lookup failed, fall through to the no-suffix case.
121     }
122     if (fs::exists(location))
123       return location.str().str();
124   }
125   return {};
126 }
127 
128 static TargetInfo *createTargetInfo(opt::InputArgList &args) {
129   StringRef arch = args.getLastArgValue(OPT_arch, "x86_64");
130   config->arch = llvm::MachO::getArchitectureFromName(
131       args.getLastArgValue(OPT_arch, arch));
132   switch (config->arch) {
133   case llvm::MachO::AK_x86_64:
134   case llvm::MachO::AK_x86_64h:
135     return createX86_64TargetInfo();
136   default:
137     fatal("missing or unsupported -arch " + arch);
138   }
139 }
140 
141 static bool isDirectory(StringRef option, StringRef path) {
142   if (!fs::exists(path)) {
143     warn("directory not found for option -" + option + path);
144     return false;
145   } else if (!fs::is_directory(path)) {
146     warn("option -" + option + path + " references a non-directory path");
147     return false;
148   }
149   return true;
150 }
151 
152 static void getSearchPaths(std::vector<StringRef> &paths, unsigned optionCode,
153                            opt::InputArgList &args,
154                            const SmallVector<StringRef, 2> &systemPaths) {
155   StringRef optionLetter{(optionCode == OPT_F ? "F" : "L")};
156   for (auto const &path : args::getStrings(args, optionCode)) {
157     if (isDirectory(optionLetter, path))
158       paths.push_back(path);
159   }
160   if (!args.hasArg(OPT_Z) && Triple(sys::getProcessTriple()).isOSDarwin()) {
161     for (auto const &path : systemPaths) {
162       if (isDirectory(optionLetter, path))
163         paths.push_back(path);
164     }
165   }
166 }
167 
168 static void getLibrarySearchPaths(std::vector<StringRef> &paths,
169                                   opt::InputArgList &args) {
170   getSearchPaths(paths, OPT_L, args, {"/usr/lib", "/usr/local/lib"});
171 }
172 
173 static void getFrameworkSearchPaths(std::vector<StringRef> &paths,
174                                     opt::InputArgList &args) {
175   getSearchPaths(paths, OPT_F, args,
176                  {"/Library/Frameworks", "/System/Library/Frameworks"});
177 }
178 
179 static void addFile(StringRef path) {
180   Optional<MemoryBufferRef> buffer = readFile(path);
181   if (!buffer)
182     return;
183   MemoryBufferRef mbref = *buffer;
184 
185   switch (identify_magic(mbref.getBuffer())) {
186   case file_magic::archive: {
187     std::unique_ptr<object::Archive> file = CHECK(
188         object::Archive::create(mbref), path + ": failed to parse archive");
189 
190     if (!file->isEmpty() && !file->hasSymbolTable())
191       error(path + ": archive has no index; run ranlib to add one");
192 
193     inputFiles.push_back(make<ArchiveFile>(std::move(file)));
194     break;
195   }
196   case file_magic::macho_object:
197     inputFiles.push_back(make<ObjFile>(mbref));
198     break;
199   case file_magic::macho_dynamically_linked_shared_lib:
200     inputFiles.push_back(make<DylibFile>(mbref));
201     break;
202   case file_magic::tapi_file: {
203     llvm::Expected<std::unique_ptr<llvm::MachO::InterfaceFile>> result =
204         TextAPIReader::get(mbref);
205     if (!result)
206       return;
207 
208     inputFiles.push_back(make<DylibFile>(std::move(*result)));
209     break;
210   }
211   default:
212     error(path + ": unhandled file type");
213   }
214 }
215 
216 static void addFileList(StringRef path) {
217   Optional<MemoryBufferRef> buffer = readFile(path);
218   if (!buffer)
219     return;
220   MemoryBufferRef mbref = *buffer;
221   for (StringRef path : args::getLines(mbref))
222     addFile(path);
223 }
224 
225 static std::array<StringRef, 6> archNames{"arm",    "arm64", "i386",
226                                           "x86_64", "ppc",   "ppc64"};
227 static bool isArchString(StringRef s) {
228   static DenseSet<StringRef> archNamesSet(archNames.begin(), archNames.end());
229   return archNamesSet.find(s) != archNamesSet.end();
230 }
231 
232 // An order file has one entry per line, in the following format:
233 //
234 //   <arch>:<object file>:<symbol name>
235 //
236 // <arch> and <object file> are optional. If not specified, then that entry
237 // matches any symbol of that name.
238 //
239 // If a symbol is matched by multiple entries, then it takes the lowest-ordered
240 // entry (the one nearest to the front of the list.)
241 //
242 // The file can also have line comments that start with '#'.
243 static void parseOrderFile(StringRef path) {
244   Optional<MemoryBufferRef> buffer = readFile(path);
245   if (!buffer) {
246     error("Could not read order file at " + path);
247     return;
248   }
249 
250   MemoryBufferRef mbref = *buffer;
251   size_t priority = std::numeric_limits<size_t>::max();
252   for (StringRef rest : args::getLines(mbref)) {
253     StringRef arch, objectFile, symbol;
254 
255     std::array<StringRef, 3> fields;
256     uint8_t fieldCount = 0;
257     while (rest != "" && fieldCount < 3) {
258       std::pair<StringRef, StringRef> p = getToken(rest, ": \t\n\v\f\r");
259       StringRef tok = p.first;
260       rest = p.second;
261 
262       // Check if we have a comment
263       if (tok == "" || tok[0] == '#')
264         break;
265 
266       fields[fieldCount++] = tok;
267     }
268 
269     switch (fieldCount) {
270     case 3:
271       arch = fields[0];
272       objectFile = fields[1];
273       symbol = fields[2];
274       break;
275     case 2:
276       (isArchString(fields[0]) ? arch : objectFile) = fields[0];
277       symbol = fields[1];
278       break;
279     case 1:
280       symbol = fields[0];
281       break;
282     case 0:
283       break;
284     default:
285       llvm_unreachable("too many fields in order file");
286     }
287 
288     if (!arch.empty()) {
289       if (!isArchString(arch)) {
290         error("invalid arch \"" + arch + "\" in order file: expected one of " +
291               llvm::join(archNames, ", "));
292         continue;
293       }
294 
295       // TODO: Update when we extend support for other archs
296       if (arch != "x86_64")
297         continue;
298     }
299 
300     if (!objectFile.empty() && !objectFile.endswith(".o")) {
301       error("invalid object file name \"" + objectFile +
302             "\" in order file: should end with .o");
303       continue;
304     }
305 
306     if (!symbol.empty()) {
307       SymbolPriorityEntry &entry = config->priorities[symbol];
308       if (!objectFile.empty())
309         entry.objectFiles.insert(std::make_pair(objectFile, priority));
310       else
311         entry.anyObjectFile = std::max(entry.anyObjectFile, priority);
312     }
313 
314     --priority;
315   }
316 }
317 
318 // We expect sub-library names of the form "libfoo", which will match a dylib
319 // with a path of .*/libfoo.dylib.
320 static bool markSubLibrary(StringRef searchName) {
321   for (InputFile *file : inputFiles) {
322     if (auto *dylibFile = dyn_cast<DylibFile>(file)) {
323       StringRef filename = path::filename(dylibFile->getName());
324       if (filename.consume_front(searchName) && filename == ".dylib") {
325         dylibFile->reexport = true;
326         return true;
327       }
328     }
329   }
330   return false;
331 }
332 
333 static void handlePlatformVersion(const opt::Arg *arg) {
334   // TODO: implementation coming very soon ...
335 }
336 
337 static void warnIfDeprecatedOption(const opt::Option &opt) {
338   if (!opt.getGroup().isValid())
339     return;
340   if (opt.getGroup().getID() == OPT_grp_deprecated) {
341     warn("Option `" + opt.getPrefixedName() + "' is deprecated in ld64:");
342     warn(opt.getHelpText());
343   }
344 }
345 
346 static void warnIfUnimplementedOption(const opt::Option &opt) {
347   if (!opt.getGroup().isValid())
348     return;
349   switch (opt.getGroup().getID()) {
350   case OPT_grp_deprecated:
351     // warn about deprecated options elsewhere
352     break;
353   case OPT_grp_undocumented:
354     warn("Option `" + opt.getPrefixedName() +
355          "' is undocumented. Should lld implement it?");
356     break;
357   case OPT_grp_obsolete:
358     warn("Option `" + opt.getPrefixedName() +
359          "' is obsolete. Please modernize your usage.");
360     break;
361   case OPT_grp_ignored:
362     warn("Option `" + opt.getPrefixedName() + "' is ignored.");
363     break;
364   default:
365     warn("Option `" + opt.getPrefixedName() +
366          "' is not yet implemented. Stay tuned...");
367     break;
368   }
369 }
370 
371 bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
372                  raw_ostream &stdoutOS, raw_ostream &stderrOS) {
373   lld::stdoutOS = &stdoutOS;
374   lld::stderrOS = &stderrOS;
375 
376   stderrOS.enable_colors(stderrOS.has_colors());
377   // TODO: Set up error handler properly, e.g. the errorLimitExceededMsg
378 
379   MachOOptTable parser;
380   opt::InputArgList args = parser.parse(argsArr.slice(1));
381 
382   if (args.hasArg(OPT_help_hidden)) {
383     parser.printHelp(argsArr[0], /*showHidden=*/true);
384     return true;
385   } else if (args.hasArg(OPT_help)) {
386     parser.printHelp(argsArr[0], /*showHidden=*/false);
387     return true;
388   }
389 
390   config = make<Configuration>();
391   symtab = make<SymbolTable>();
392   target = createTargetInfo(args);
393 
394   config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main"));
395   config->outputFile = args.getLastArgValue(OPT_o, "a.out");
396   config->installName =
397       args.getLastArgValue(OPT_install_name, config->outputFile);
398   getLibrarySearchPaths(config->librarySearchPaths, args);
399   getFrameworkSearchPaths(config->frameworkSearchPaths, args);
400   config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE;
401 
402   if (args.hasArg(OPT_v)) {
403     message(getLLDVersion());
404     message(StringRef("Library search paths:") +
405             (config->librarySearchPaths.size()
406                  ? "\n\t" + llvm::join(config->librarySearchPaths, "\n\t")
407                  : ""));
408     message(StringRef("Framework search paths:") +
409             (config->frameworkSearchPaths.size()
410                  ? "\n\t" + llvm::join(config->frameworkSearchPaths, "\n\t")
411                  : ""));
412     freeArena();
413     return !errorCount();
414   }
415 
416   for (const auto &arg : args) {
417     const auto &opt = arg->getOption();
418     warnIfDeprecatedOption(opt);
419     switch (arg->getOption().getID()) {
420     case OPT_INPUT:
421       addFile(arg->getValue());
422       break;
423     case OPT_filelist:
424       addFileList(arg->getValue());
425       break;
426     case OPT_l: {
427       StringRef name = arg->getValue();
428       if (Optional<std::string> path = findLibrary(name)) {
429         addFile(*path);
430         break;
431       }
432       error("library not found for -l" + name);
433       break;
434     }
435     case OPT_framework: {
436       StringRef name = arg->getValue();
437       if (Optional<std::string> path = findFramework(name)) {
438         addFile(*path);
439         break;
440       }
441       error("framework not found for -framework " + name);
442       break;
443     }
444     case OPT_platform_version:
445       handlePlatformVersion(arg);
446       break;
447     case OPT_o:
448     case OPT_dylib:
449     case OPT_e:
450     case OPT_F:
451     case OPT_L:
452     case OPT_install_name:
453     case OPT_Z:
454     case OPT_arch:
455       // handled elsewhere
456       break;
457     default:
458       warnIfUnimplementedOption(opt);
459       break;
460     }
461   }
462 
463   // Now that all dylibs have been loaded, search for those that should be
464   // re-exported.
465   for (opt::Arg *arg : args.filtered(OPT_sub_library)) {
466     config->hasReexports = true;
467     StringRef searchName = arg->getValue();
468     if (!markSubLibrary(searchName))
469       error("-sub_library " + searchName + " does not match a supplied dylib");
470   }
471 
472   StringRef orderFile = args.getLastArgValue(OPT_order_file);
473   if (!orderFile.empty())
474     parseOrderFile(orderFile);
475 
476   if (config->outputType == MH_EXECUTE && !isa<Defined>(config->entry)) {
477     error("undefined symbol: " + config->entry->getName());
478     return false;
479   }
480 
481   createSyntheticSections();
482 
483   // Initialize InputSections.
484   for (InputFile *file : inputFiles) {
485     for (SubsectionMap &map : file->subsections) {
486       for (auto &p : map) {
487         InputSection *isec = p.second;
488         inputSections.push_back(isec);
489       }
490     }
491   }
492 
493   // Write to an output file.
494   writeResult();
495 
496   if (canExitEarly)
497     exitLld(errorCount() ? 1 : 0);
498 
499   freeArena();
500   return !errorCount();
501 }
502