xref: /llvm-project-15.0.7/lld/MachO/Driver.cpp (revision f058d397)
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/StringExtras.h"
26 #include "llvm/ADT/StringRef.h"
27 #include "llvm/BinaryFormat/MachO.h"
28 #include "llvm/BinaryFormat/Magic.h"
29 #include "llvm/Option/ArgList.h"
30 #include "llvm/Option/Option.h"
31 #include "llvm/Support/MemoryBuffer.h"
32 
33 using namespace llvm;
34 using namespace llvm::MachO;
35 using namespace llvm::sys;
36 using namespace lld;
37 using namespace lld::macho;
38 
39 Configuration *lld::macho::config;
40 
41 // Create prefix string literals used in Options.td
42 #define PREFIX(NAME, VALUE) const char *NAME[] = VALUE;
43 #include "Options.inc"
44 #undef PREFIX
45 
46 // Create table mapping all options defined in Options.td
47 static const opt::OptTable::Info optInfo[] = {
48 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
49   {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
50    X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
51 #include "Options.inc"
52 #undef OPTION
53 };
54 
55 MachOOptTable::MachOOptTable() : OptTable(optInfo) {}
56 
57 opt::InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) {
58   // Make InputArgList from string vectors.
59   unsigned missingIndex;
60   unsigned missingCount;
61   SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
62 
63   opt::InputArgList args = ParseArgs(vec, missingIndex, missingCount);
64 
65   if (missingCount)
66     error(Twine(args.getArgString(missingIndex)) + ": missing argument");
67 
68   for (opt::Arg *arg : args.filtered(OPT_UNKNOWN))
69     error("unknown argument: " + arg->getSpelling());
70   return args;
71 }
72 
73 // This is for -lfoo. We'll look for libfoo.dylib from search paths.
74 static Optional<std::string> findDylib(StringRef name) {
75   for (StringRef dir : config->searchPaths) {
76     std::string path = (dir + "/lib" + name + ".dylib").str();
77     if (fs::exists(path))
78       return path;
79   }
80   error("library not found for -l" + name);
81   return None;
82 }
83 
84 static TargetInfo *createTargetInfo(opt::InputArgList &args) {
85   StringRef s = args.getLastArgValue(OPT_arch, "x86_64");
86   if (s != "x86_64")
87     error("missing or unsupported -arch " + s);
88   return createX86_64TargetInfo();
89 }
90 
91 static std::vector<StringRef> getSearchPaths(opt::InputArgList &args) {
92   std::vector<StringRef> ret{args::getStrings(args, OPT_L)};
93   if (!args.hasArg(OPT_Z)) {
94     ret.push_back("/usr/lib");
95     ret.push_back("/usr/local/lib");
96   }
97   return ret;
98 }
99 
100 static void addFile(StringRef path) {
101   Optional<MemoryBufferRef> buffer = readFile(path);
102   if (!buffer)
103     return;
104   MemoryBufferRef mbref = *buffer;
105 
106   switch (identify_magic(mbref.getBuffer())) {
107   case file_magic::macho_object:
108     inputFiles.push_back(make<ObjFile>(mbref));
109     break;
110   case file_magic::macho_dynamically_linked_shared_lib:
111     inputFiles.push_back(make<DylibFile>(mbref));
112     break;
113   default:
114     error(path + ": unhandled file type");
115   }
116 }
117 
118 bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
119                  raw_ostream &stdoutOS, raw_ostream &stderrOS) {
120   lld::stdoutOS = &stdoutOS;
121   lld::stderrOS = &stderrOS;
122 
123   stderrOS.enable_colors(stderrOS.has_colors());
124   // TODO: Set up error handler properly, e.g. the errorLimitExceededMsg
125 
126   MachOOptTable parser;
127   opt::InputArgList args = parser.parse(argsArr.slice(1));
128 
129   config = make<Configuration>();
130   symtab = make<SymbolTable>();
131   target = createTargetInfo(args);
132 
133   config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main"));
134   config->outputFile = args.getLastArgValue(OPT_o, "a.out");
135   config->installName =
136       args.getLastArgValue(OPT_install_name, config->outputFile);
137   config->searchPaths = getSearchPaths(args);
138   config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE;
139 
140   if (args.hasArg(OPT_v)) {
141     message(getLLDVersion());
142     std::vector<StringRef> &searchPaths = config->searchPaths;
143     message("Library search paths:\n" +
144             llvm::join(searchPaths.begin(), searchPaths.end(), "\n"));
145     freeArena();
146     return !errorCount();
147   }
148 
149   for (opt::Arg *arg : args) {
150     switch (arg->getOption().getID()) {
151     case OPT_INPUT:
152       addFile(arg->getValue());
153       break;
154     case OPT_l:
155       if (Optional<std::string> path = findDylib(arg->getValue()))
156         addFile(*path);
157       break;
158     }
159   }
160 
161   if (config->outputType == MH_EXECUTE && !isa<Defined>(config->entry)) {
162     error("undefined symbol: " + config->entry->getName());
163     return false;
164   }
165 
166   createSyntheticSections();
167 
168   // Initialize InputSections.
169   for (InputFile *file : inputFiles)
170     for (InputSection *sec : file->sections)
171       inputSections.push_back(sec);
172 
173   // Write to an output file.
174   writeResult();
175 
176   if (canExitEarly)
177     exitLld(errorCount() ? 1 : 0);
178 
179   freeArena();
180   return !errorCount();
181 }
182