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