1 //===- lib/ReaderWriter/ELF/ELFLinkingContext.cpp -------------------------===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lld/ReaderWriter/ELFLinkingContext.h"
12 #include "OrderPass.h"
13 #include "TargetHandler.h"
14 #include "lld/Core/Instrumentation.h"
15 #include "lld/Core/SharedLibraryFile.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/Triple.h"
18 #include "llvm/Config/config.h"
19 #include "llvm/Support/ELF.h"
20 #include "llvm/Support/Errc.h"
21 #include "llvm/Support/FileSystem.h"
22 #include "llvm/Support/Path.h"
24 #if defined(HAVE_CXXABI_H)
30 class CommandLineUndefinedAtom : public SimpleUndefinedAtom {
32 CommandLineUndefinedAtom(const File &f, StringRef name)
33 : SimpleUndefinedAtom(f, name) {}
35 CanBeNull canBeNull() const override {
36 return CanBeNull::canBeNullAtBuildtime;
40 ELFLinkingContext::ELFLinkingContext(
41 llvm::Triple triple, std::unique_ptr<TargetHandlerBase> targetHandler)
42 : _outputELFType(llvm::ELF::ET_EXEC), _triple(triple),
43 _targetHandler(std::move(targetHandler)), _baseAddress(0),
44 _isStaticExecutable(false), _noInhibitExec(false), _exportDynamic(false),
45 _mergeCommonStrings(false), _useShlibUndefines(true),
46 _dynamicLinkerArg(false), _noAllowDynamicLibraries(false),
47 _mergeRODataToTextSegment(true), _demangle(true),
48 _stripSymbols(false), _alignSegments(true), _collectStats(false),
49 _outputMagic(OutputMagic::DEFAULT), _initFunction("_init"),
50 _finiFunction("_fini"), _sysrootPath(""), _linkerScriptSema() {}
52 void ELFLinkingContext::addPasses(PassManager &pm) {
53 pm.add(llvm::make_unique<elf::OrderPass>());
56 uint16_t ELFLinkingContext::getOutputMachine() const {
57 switch (getTriple().getArch()) {
58 case llvm::Triple::x86:
59 return llvm::ELF::EM_386;
60 case llvm::Triple::x86_64:
61 return llvm::ELF::EM_X86_64;
62 case llvm::Triple::hexagon:
63 return llvm::ELF::EM_HEXAGON;
64 case llvm::Triple::mipsel:
65 case llvm::Triple::mips64el:
66 return llvm::ELF::EM_MIPS;
67 case llvm::Triple::aarch64:
68 return llvm::ELF::EM_AARCH64;
69 case llvm::Triple::arm:
70 return llvm::ELF::EM_ARM;
72 llvm_unreachable("Unhandled arch");
76 StringRef ELFLinkingContext::entrySymbolName() const {
77 if (_outputELFType == llvm::ELF::ET_EXEC && _entrySymbolName.empty())
79 return _entrySymbolName;
82 bool ELFLinkingContext::validateImpl(raw_ostream &diagnostics) {
83 switch (outputFileType()) {
84 case LinkingContext::OutputFileType::YAML:
85 _writer = createWriterYAML(*this);
87 case LinkingContext::OutputFileType::Native:
88 llvm_unreachable("Unimplemented");
91 _writer = createWriterELF(this->targetHandler());
95 // If -dead_strip, set up initial live symbols.
97 addDeadStripRoot(entrySymbolName());
101 bool ELFLinkingContext::isDynamic() const {
102 switch (_outputELFType) {
103 case llvm::ELF::ET_EXEC:
104 return !_isStaticExecutable;
105 case llvm::ELF::ET_DYN:
111 bool ELFLinkingContext::isRelativeReloc(const Reference &) const {
115 Writer &ELFLinkingContext::writer() const { return *_writer; }
117 static void buildSearchPath(SmallString<128> &path, StringRef dir,
119 if (!dir.startswith("=/"))
122 path.assign(sysRoot);
123 path.append(dir.substr(1));
127 ErrorOr<StringRef> ELFLinkingContext::searchLibrary(StringRef libName) const {
128 bool hasColonPrefix = libName[0] == ':';
129 SmallString<128> path;
130 for (StringRef dir : _inputSearchPaths) {
131 // Search for dynamic library
132 if (!_isStaticExecutable) {
133 buildSearchPath(path, dir, _sysrootPath);
134 llvm::sys::path::append(path, hasColonPrefix
135 ? libName.drop_front()
136 : Twine("lib", libName) + ".so");
137 if (llvm::sys::fs::exists(path.str()))
138 return StringRef(*new (_allocator) std::string(path.str()));
140 // Search for static libraries too
141 buildSearchPath(path, dir, _sysrootPath);
142 llvm::sys::path::append(path, hasColonPrefix
143 ? libName.drop_front()
144 : Twine("lib", libName) + ".a");
145 if (llvm::sys::fs::exists(path.str()))
146 return StringRef(*new (_allocator) std::string(path.str()));
148 if (hasColonPrefix && llvm::sys::fs::exists(libName.drop_front()))
149 return libName.drop_front();
151 return make_error_code(llvm::errc::no_such_file_or_directory);
154 ErrorOr<StringRef> ELFLinkingContext::searchFile(StringRef fileName,
155 bool isSysRooted) const {
156 SmallString<128> path;
157 if (llvm::sys::path::is_absolute(fileName) && isSysRooted) {
158 path.assign(_sysrootPath);
159 path.append(fileName);
160 if (llvm::sys::fs::exists(path.str()))
161 return StringRef(*new (_allocator) std::string(path.str()));
162 } else if (llvm::sys::fs::exists(fileName))
165 if (llvm::sys::path::is_absolute(fileName))
166 return make_error_code(llvm::errc::no_such_file_or_directory);
168 for (StringRef dir : _inputSearchPaths) {
169 buildSearchPath(path, dir, _sysrootPath);
170 llvm::sys::path::append(path, fileName);
171 if (llvm::sys::fs::exists(path.str()))
172 return StringRef(*new (_allocator) std::string(path.str()));
174 return make_error_code(llvm::errc::no_such_file_or_directory);
177 void ELFLinkingContext::createInternalFiles(
178 std::vector<std::unique_ptr<File>> &files) const {
179 std::unique_ptr<SimpleFile> file(
180 new SimpleFile("<internal file for --defsym>"));
181 for (auto &i : getAbsoluteSymbols()) {
182 StringRef sym = i.first;
183 uint64_t val = i.second;
184 file->addAtom(*(new (_allocator) SimpleAbsoluteAtom(
185 *file, sym, Atom::scopeGlobal, val)));
187 files.push_back(std::move(file));
188 LinkingContext::createInternalFiles(files);
191 void ELFLinkingContext::finalizeInputFiles() {
192 // Add virtual archive that resolves undefined symbols.
194 getNodes().push_back(llvm::make_unique<FileNode>(std::move(_resolver)));
197 std::unique_ptr<File> ELFLinkingContext::createUndefinedSymbolFile() const {
198 if (_initialUndefinedSymbols.empty())
200 std::unique_ptr<SimpleFile> undefinedSymFile(
201 new SimpleFile("command line option -u"));
202 for (auto undefSymStr : _initialUndefinedSymbols)
203 undefinedSymFile->addAtom(*(new (_allocator) CommandLineUndefinedAtom(
204 *undefinedSymFile, undefSymStr)));
205 return std::move(undefinedSymFile);
208 void ELFLinkingContext::notifySymbolTableCoalesce(const Atom *existingAtom,
211 // First suppose that the `existingAtom` is defined
212 // and the `newAtom` is undefined.
213 auto *da = dyn_cast<DefinedAtom>(existingAtom);
214 auto *ua = dyn_cast<UndefinedAtom>(newAtom);
216 // Then try to reverse the assumption.
217 da = dyn_cast<DefinedAtom>(newAtom);
218 ua = dyn_cast<UndefinedAtom>(existingAtom);
221 if (da && ua && da->scope() == Atom::scopeGlobal &&
222 isa<SharedLibraryFile>(ua->file()))
223 // If strong defined atom coalesces away an atom declared
224 // in the shared object the strong atom needs to be dynamically exported.
226 _dynamicallyExportedSymbols.insert(ua->name());
229 std::string ELFLinkingContext::demangle(StringRef symbolName) const {
230 if (!demangleSymbols())
233 // Only try to demangle symbols that look like C++ symbols
234 if (!symbolName.startswith("_Z"))
237 #if defined(HAVE_CXXABI_H)
238 SmallString<256> symBuff;
239 StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff);
240 const char *cstr = nullTermSym.data();
242 char *demangled = abi::__cxa_demangle(cstr, nullptr, nullptr, &status);
243 if (demangled != NULL) {
244 std::string result(demangled);
245 // __cxa_demangle() always uses a malloc'ed buffer to return the result.
254 void ELFLinkingContext::setUndefinesResolver(std::unique_ptr<File> resolver) {
255 assert(isa<ArchiveLibraryFile>(resolver.get()) && "Wrong resolver type");
256 _resolver = std::move(resolver);
259 } // end namespace lld