xref: /llvm-project-15.0.7/lld/ELF/Driver.cpp (revision b4e2e7a2)
1 //===- Driver.cpp ---------------------------------------------------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "Driver.h"
11 #include "Config.h"
12 #include "Error.h"
13 #include "InputFiles.h"
14 #include "SymbolTable.h"
15 #include "Writer.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/Support/FileSystem.h"
19 #include "llvm/Support/Path.h"
20 
21 using namespace llvm;
22 
23 using namespace lld;
24 using namespace lld::elf2;
25 
26 namespace lld {
27 namespace elf2 {
28 
29 Configuration *Config;
30 std::vector<std::unique_ptr<MemoryBuffer>> *MemoryBufferPool;
31 
32 void link(ArrayRef<const char *> Args) {
33   Configuration C;
34   Config = &C;
35   std::vector<std::unique_ptr<MemoryBuffer>> V;
36   MemoryBufferPool = &V;
37   LinkerDriver().link(Args.slice(1));
38 }
39 
40 // Opens a file. Path has to be resolved already.
41 // Newly created memory buffers are owned by this driver.
42 MemoryBufferRef openFile(StringRef Path) {
43   ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = MemoryBuffer::getFile(Path);
44   error(MBOrErr, Twine("cannot open ") + Path);
45   std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
46   MemoryBufferRef MBRef = MB->getMemBufferRef();
47   MemoryBufferPool->push_back(std::move(MB)); // transfer ownership
48   return MBRef;
49 }
50 }
51 }
52 
53 // Makes a path by concatenating Dir and File.
54 // If Dir starts with '=' the result will be preceded by Sysroot,
55 // which can be set with --sysroot command line switch.
56 static std::string buildSysrootedPath(StringRef Dir, StringRef File) {
57   SmallString<128> Path;
58   if (Dir.startswith("="))
59     sys::path::append(Path, Config->Sysroot, Dir.substr(1), File);
60   else
61     sys::path::append(Path, Dir, File);
62   return Path.str().str();
63 }
64 
65 // Searches a given library from input search paths, which are filled
66 // from -L command line switches. Returns a path to an existent library file.
67 static std::string searchLibrary(StringRef Path) {
68   std::vector<std::string> Names;
69   if (Path[0] == ':') {
70     Names.push_back(Path.drop_front().str());
71   } else {
72     Names.push_back((Twine("lib") + Path + ".so").str());
73     Names.push_back((Twine("lib") + Path + ".a").str());
74   }
75   for (StringRef Dir : Config->InputSearchPaths) {
76     for (const std::string &Name : Names) {
77       std::string FullPath = buildSysrootedPath(Dir, Name);
78       if (sys::fs::exists(FullPath))
79         return FullPath;
80     }
81   }
82   error(Twine("Unable to find library -l") + Path);
83 }
84 
85 // Returns true if MB looks like a linker script.
86 static bool isLinkerScript(MemoryBufferRef MB) {
87   using namespace llvm::sys::fs;
88   return identify_magic(MB.getBuffer()) == file_magic::unknown;
89 }
90 
91 void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
92   // Parse command line options.
93   opt::InputArgList Args = Parser.parse(ArgsArr);
94 
95   if (auto *Arg = Args.getLastArg(OPT_output))
96     Config->OutputFile = Arg->getValue();
97 
98   if (auto *Arg = Args.getLastArg(OPT_dynamic_linker))
99     Config->DynamicLinker = Arg->getValue();
100 
101   if (auto *Arg = Args.getLastArg(OPT_sysroot))
102     Config->Sysroot = Arg->getValue();
103 
104   std::vector<StringRef> RPaths;
105   for (auto *Arg : Args.filtered(OPT_rpath))
106     RPaths.push_back(Arg->getValue());
107   if (!RPaths.empty())
108     Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":");
109 
110   for (auto *Arg : Args.filtered(OPT_L))
111     Config->InputSearchPaths.push_back(Arg->getValue());
112 
113   if (auto *Arg = Args.getLastArg(OPT_entry))
114     Config->Entry = Arg->getValue();
115 
116   Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
117   Config->DiscardAll = Args.hasArg(OPT_discard_all);
118   Config->DiscardLocals = Args.hasArg(OPT_discard_locals);
119   Config->DiscardNone = Args.hasArg(OPT_discard_none);
120   Config->ExportDynamic = Args.hasArg(OPT_export_dynamic);
121   Config->NoInhibitExec = Args.hasArg(OPT_noinhibit_exec);
122   Config->Shared = Args.hasArg(OPT_shared);
123 
124   // Create a symbol table.
125   SymbolTable Symtab;
126 
127   for (auto *Arg : Args.filtered(OPT_l, OPT_INPUT)) {
128     std::string Path = Arg->getValue();
129     if (Arg->getOption().getID() == OPT_l)
130       Path = searchLibrary(Path);
131     MemoryBufferRef MB = openFile(Path);
132     if (isLinkerScript(MB)) {
133       // readLinkerScript may add files to the symbol table.
134       readLinkerScript(&Symtab, MB);
135       continue;
136     }
137     Symtab.addFile(createFile(MB));
138   }
139 
140   if (Symtab.getObjectFiles().empty())
141     error("no input files.");
142 
143   // Write the result.
144   const ELFFileBase *FirstObj = Symtab.getFirstELF();
145   switch (FirstObj->getELFKind()) {
146   case ELF32LEKind:
147     writeResult<object::ELF32LE>(&Symtab);
148     return;
149   case ELF32BEKind:
150     writeResult<object::ELF32BE>(&Symtab);
151     return;
152   case ELF64LEKind:
153     writeResult<object::ELF64LE>(&Symtab);
154     return;
155   case ELF64BEKind:
156     writeResult<object::ELF64BE>(&Symtab);
157     return;
158   }
159 }
160