xref: /llvm-project-15.0.7/lld/MachO/Driver.cpp (revision 0570de73)
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/StringRef.h"
25 #include "llvm/BinaryFormat/MachO.h"
26 #include "llvm/BinaryFormat/Magic.h"
27 #include "llvm/Option/ArgList.h"
28 #include "llvm/Option/Option.h"
29 #include "llvm/Support/MemoryBuffer.h"
30 
31 using namespace llvm;
32 using namespace llvm::MachO;
33 using namespace llvm::sys;
34 using namespace lld;
35 using namespace lld::macho;
36 
37 Configuration *lld::macho::config;
38 
39 // Create prefix string literals used in Options.td
40 #define PREFIX(NAME, VALUE) const char *NAME[] = VALUE;
41 #include "Options.inc"
42 #undef PREFIX
43 
44 // Create table mapping all options defined in Options.td
45 static const opt::OptTable::Info optInfo[] = {
46 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
47   {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
48    X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
49 #include "Options.inc"
50 #undef OPTION
51 };
52 
53 MachOOptTable::MachOOptTable() : OptTable(optInfo) {}
54 
55 opt::InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) {
56   // Make InputArgList from string vectors.
57   unsigned missingIndex;
58   unsigned missingCount;
59   SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
60 
61   opt::InputArgList args = ParseArgs(vec, missingIndex, missingCount);
62 
63   if (missingCount)
64     error(Twine(args.getArgString(missingIndex)) + ": missing argument");
65 
66   for (opt::Arg *arg : args.filtered(OPT_UNKNOWN))
67     error("unknown argument: " + arg->getSpelling());
68   return args;
69 }
70 
71 static TargetInfo *createTargetInfo(opt::InputArgList &args) {
72   StringRef s = args.getLastArgValue(OPT_arch, "x86_64");
73   if (s != "x86_64")
74     error("missing or unsupported -arch " + s);
75   return createX86_64TargetInfo();
76 }
77 
78 static void addFile(StringRef path) {
79   Optional<MemoryBufferRef> buffer = readFile(path);
80   if (!buffer)
81     return;
82   MemoryBufferRef mbref = *buffer;
83 
84   switch (identify_magic(mbref.getBuffer())) {
85   case file_magic::macho_object:
86     inputFiles.push_back(make<ObjFile>(mbref));
87     break;
88   default:
89     error(path + ": unhandled file type");
90   }
91 }
92 
93 bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
94                  raw_ostream &stdoutOS, raw_ostream &stderrOS) {
95   lld::stdoutOS = &stdoutOS;
96   lld::stderrOS = &stderrOS;
97 
98   MachOOptTable parser;
99   opt::InputArgList args = parser.parse(argsArr.slice(1));
100 
101   if (args.hasArg(OPT_v)) {
102     message(getLLDVersion());
103     freeArena();
104     return !errorCount();
105   }
106 
107   config = make<Configuration>();
108   symtab = make<SymbolTable>();
109   target = createTargetInfo(args);
110 
111   config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main"));
112   config->outputFile = args.getLastArgValue(OPT_o, "a.out");
113 
114   getOrCreateOutputSegment("__TEXT", VM_PROT_READ | VM_PROT_EXECUTE);
115   getOrCreateOutputSegment("__DATA", VM_PROT_READ | VM_PROT_WRITE);
116 
117   for (opt::Arg *arg : args) {
118     switch (arg->getOption().getID()) {
119     case OPT_INPUT:
120       addFile(arg->getValue());
121       break;
122     }
123   }
124 
125   if (!isa<Defined>(config->entry)) {
126     error("undefined symbol: " + config->entry->getName());
127     return false;
128   }
129 
130   // Initialize InputSections.
131   for (InputFile *file : inputFiles)
132     for (InputSection *sec : file->sections)
133       inputSections.push_back(sec);
134 
135   // Add input sections to output segments.
136   for (InputSection *isec : inputSections) {
137     OutputSegment *os =
138         getOrCreateOutputSegment(isec->segname, VM_PROT_READ | VM_PROT_WRITE);
139     os->sections[isec->name].push_back(isec);
140   }
141 
142   // Write to an output file.
143   writeResult();
144 
145   if (canExitEarly)
146     exitLld(errorCount() ? 1 : 0);
147 
148   freeArena();
149   return !errorCount();
150 }
151