xref: /llvm-project-15.0.7/lld/MachO/Driver.cpp (revision e29cae1e)
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 #include "llvm/Support/Path.h"
33 
34 using namespace llvm;
35 using namespace llvm::MachO;
36 using namespace llvm::sys;
37 using namespace lld;
38 using namespace lld::macho;
39 
40 Configuration *lld::macho::config;
41 
42 // Create prefix string literals used in Options.td
43 #define PREFIX(NAME, VALUE) const char *NAME[] = VALUE;
44 #include "Options.inc"
45 #undef PREFIX
46 
47 // Create table mapping all options defined in Options.td
48 static const opt::OptTable::Info optInfo[] = {
49 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
50   {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
51    X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
52 #include "Options.inc"
53 #undef OPTION
54 };
55 
56 MachOOptTable::MachOOptTable() : OptTable(optInfo) {}
57 
58 opt::InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) {
59   // Make InputArgList from string vectors.
60   unsigned missingIndex;
61   unsigned missingCount;
62   SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
63 
64   opt::InputArgList args = ParseArgs(vec, missingIndex, missingCount);
65 
66   if (missingCount)
67     error(Twine(args.getArgString(missingIndex)) + ": missing argument");
68 
69   for (opt::Arg *arg : args.filtered(OPT_UNKNOWN))
70     error("unknown argument: " + arg->getSpelling());
71   return args;
72 }
73 
74 // This is for -lfoo. We'll look for libfoo.dylib from search paths.
75 static Optional<std::string> findDylib(StringRef name) {
76   for (StringRef dir : config->searchPaths) {
77     std::string path = (dir + "/lib" + name + ".dylib").str();
78     if (fs::exists(path))
79       return path;
80   }
81   error("library not found for -l" + name);
82   return None;
83 }
84 
85 static TargetInfo *createTargetInfo(opt::InputArgList &args) {
86   StringRef s = args.getLastArgValue(OPT_arch, "x86_64");
87   if (s != "x86_64")
88     error("missing or unsupported -arch " + s);
89   return createX86_64TargetInfo();
90 }
91 
92 static std::vector<StringRef> getSearchPaths(opt::InputArgList &args) {
93   std::vector<StringRef> ret{args::getStrings(args, OPT_L)};
94   if (!args.hasArg(OPT_Z)) {
95     ret.push_back("/usr/lib");
96     ret.push_back("/usr/local/lib");
97   }
98   return ret;
99 }
100 
101 static void addFile(StringRef path) {
102   Optional<MemoryBufferRef> buffer = readFile(path);
103   if (!buffer)
104     return;
105   MemoryBufferRef mbref = *buffer;
106 
107   switch (identify_magic(mbref.getBuffer())) {
108   case file_magic::macho_object:
109     inputFiles.push_back(make<ObjFile>(mbref));
110     break;
111   case file_magic::macho_dynamically_linked_shared_lib:
112     inputFiles.push_back(make<DylibFile>(mbref));
113     break;
114   default:
115     error(path + ": unhandled file type");
116   }
117 }
118 
119 // We expect sub-library names of the form "libfoo", which will match a dylib
120 // with a path of .*/libfoo.dylib.
121 static bool markSubLibrary(StringRef searchName) {
122   for (InputFile *file : inputFiles) {
123     if (auto *dylibFile = dyn_cast<DylibFile>(file)) {
124       StringRef filename = path::filename(dylibFile->getName());
125       if (filename.consume_front(searchName) && filename == ".dylib") {
126         dylibFile->reexport = true;
127         return true;
128       }
129     }
130   }
131   return false;
132 }
133 
134 static void handlePlatformVersion(opt::ArgList::iterator &it,
135                                   const opt::ArgList::iterator &end) {
136   // -platform_version takes 3 args, which LLVM's option library doesn't
137   // support directly.  So this explicitly handles that.
138   // FIXME: stash skipped args for later use.
139   for (int i = 0; i < 3; ++i) {
140     ++it;
141     if (it == end || (*it)->getOption().getID() != OPT_INPUT)
142       fatal("usage: -platform_version platform min_version sdk_version");
143   }
144 }
145 
146 bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
147                  raw_ostream &stdoutOS, raw_ostream &stderrOS) {
148   lld::stdoutOS = &stdoutOS;
149   lld::stderrOS = &stderrOS;
150 
151   stderrOS.enable_colors(stderrOS.has_colors());
152   // TODO: Set up error handler properly, e.g. the errorLimitExceededMsg
153 
154   MachOOptTable parser;
155   opt::InputArgList args = parser.parse(argsArr.slice(1));
156 
157   config = make<Configuration>();
158   symtab = make<SymbolTable>();
159   target = createTargetInfo(args);
160 
161   config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main"));
162   config->outputFile = args.getLastArgValue(OPT_o, "a.out");
163   config->installName =
164       args.getLastArgValue(OPT_install_name, config->outputFile);
165   config->searchPaths = getSearchPaths(args);
166   config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE;
167 
168   if (args.hasArg(OPT_v)) {
169     message(getLLDVersion());
170     std::vector<StringRef> &searchPaths = config->searchPaths;
171     message("Library search paths:\n" +
172             llvm::join(searchPaths.begin(), searchPaths.end(), "\n"));
173     freeArena();
174     return !errorCount();
175   }
176 
177   for (opt::ArgList::iterator it = args.begin(), end = args.end(); it != end;
178        ++it) {
179     const opt::Arg *arg = *it;
180     switch (arg->getOption().getID()) {
181     case OPT_INPUT:
182       addFile(arg->getValue());
183       break;
184     case OPT_l:
185       if (Optional<std::string> path = findDylib(arg->getValue()))
186         addFile(*path);
187       break;
188     case OPT_platform_version: {
189       handlePlatformVersion(it, end); // Can advance "it".
190       break;
191     }
192     }
193   }
194 
195   // Now that all dylibs have been loaded, search for those that should be
196   // re-exported.
197   for (opt::Arg *arg : args.filtered(OPT_sub_library)) {
198     config->hasReexports = true;
199     StringRef searchName = arg->getValue();
200     if (!markSubLibrary(searchName))
201       error("-sub_library " + searchName + " does not match a supplied dylib");
202   }
203 
204   // dyld requires us to load libSystem. Since we may run tests on non-OSX
205   // systems which do not have libSystem, we mock it out here.
206   // TODO: Replace this with a stub tbd file once we have TAPI support.
207   if (StringRef(getenv("LLD_IN_TEST")) == "1" &&
208       config->outputType == MH_EXECUTE) {
209     inputFiles.push_back(DylibFile::createLibSystemMock());
210   }
211 
212   if (config->outputType == MH_EXECUTE && !isa<Defined>(config->entry)) {
213     error("undefined symbol: " + config->entry->getName());
214     return false;
215   }
216 
217   createSyntheticSections();
218 
219   // Initialize InputSections.
220   for (InputFile *file : inputFiles)
221     for (InputSection *sec : file->sections)
222       inputSections.push_back(sec);
223 
224   // Write to an output file.
225   writeResult();
226 
227   if (canExitEarly)
228     exitLld(errorCount() ? 1 : 0);
229 
230   freeArena();
231   return !errorCount();
232 }
233