2020-04-03 02:54:05 +08:00
|
|
|
//===- Driver.cpp ---------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Driver.h"
|
|
|
|
#include "Config.h"
|
|
|
|
#include "InputFiles.h"
|
2020-10-27 10:18:29 +08:00
|
|
|
#include "LTO.h"
|
2020-08-19 05:37:04 +08:00
|
|
|
#include "ObjC.h"
|
2020-05-02 07:29:06 +08:00
|
|
|
#include "OutputSection.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "OutputSegment.h"
|
|
|
|
#include "SymbolTable.h"
|
|
|
|
#include "Symbols.h"
|
2020-07-31 05:28:41 +08:00
|
|
|
#include "SyntheticSections.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "Target.h"
|
|
|
|
#include "Writer.h"
|
|
|
|
|
|
|
|
#include "lld/Common/Args.h"
|
|
|
|
#include "lld/Common/Driver.h"
|
|
|
|
#include "lld/Common/ErrorHandler.h"
|
|
|
|
#include "lld/Common/LLVM.h"
|
|
|
|
#include "lld/Common/Memory.h"
|
2020-12-02 12:31:57 +08:00
|
|
|
#include "lld/Common/Reproduce.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "lld/Common/Version.h"
|
2020-05-06 07:37:34 +08:00
|
|
|
#include "llvm/ADT/DenseSet.h"
|
2020-04-22 04:37:57 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/BinaryFormat/MachO.h"
|
|
|
|
#include "llvm/BinaryFormat/Magic.h"
|
2020-10-27 10:18:29 +08:00
|
|
|
#include "llvm/LTO/LTO.h"
|
2020-05-15 03:43:51 +08:00
|
|
|
#include "llvm/Object/Archive.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "llvm/Option/ArgList.h"
|
2020-12-09 20:06:50 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2020-07-27 03:46:46 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2020-06-18 10:59:27 +08:00
|
|
|
#include "llvm/Support/Host.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2020-04-24 11:16:49 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2020-11-29 11:38:27 +08:00
|
|
|
#include "llvm/Support/TarWriter.h"
|
2020-10-27 10:18:29 +08:00
|
|
|
#include "llvm/Support/TargetSelect.h"
|
2020-12-16 05:37:37 +08:00
|
|
|
#include "llvm/TextAPI/MachO/PackedVersion.h"
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2020-08-11 09:47:16 +08:00
|
|
|
#include <algorithm>
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::MachO;
|
2020-08-13 10:50:27 +08:00
|
|
|
using namespace llvm::object;
|
2020-06-16 03:36:32 +08:00
|
|
|
using namespace llvm::opt;
|
2020-08-13 10:50:27 +08:00
|
|
|
using namespace llvm::sys;
|
2020-04-03 02:54:05 +08:00
|
|
|
using namespace lld;
|
|
|
|
using namespace lld::macho;
|
|
|
|
|
|
|
|
Configuration *lld::macho::config;
|
|
|
|
|
2020-09-27 06:57:09 +08:00
|
|
|
static HeaderFileType getOutputType(const opt::InputArgList &args) {
|
2020-09-01 14:23:37 +08:00
|
|
|
// TODO: -r, -dylinker, -preload...
|
|
|
|
opt::Arg *outputArg = args.getLastArg(OPT_bundle, OPT_dylib, OPT_execute);
|
|
|
|
if (outputArg == nullptr)
|
|
|
|
return MH_EXECUTE;
|
|
|
|
|
|
|
|
switch (outputArg->getOption().getID()) {
|
|
|
|
case OPT_bundle:
|
|
|
|
return MH_BUNDLE;
|
|
|
|
case OPT_dylib:
|
|
|
|
return MH_DYLIB;
|
|
|
|
case OPT_execute:
|
|
|
|
return MH_EXECUTE;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("internal error");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-20 23:37:20 +08:00
|
|
|
static Optional<std::string>
|
|
|
|
findAlongPathsWithExtensions(StringRef name, ArrayRef<StringRef> extensions) {
|
2021-01-10 00:58:19 +08:00
|
|
|
SmallString<261> base;
|
2020-09-20 23:37:20 +08:00
|
|
|
for (StringRef dir : config->librarySearchPaths) {
|
|
|
|
base = dir;
|
|
|
|
path::append(base, Twine("lib") + name);
|
|
|
|
for (StringRef ext : extensions) {
|
|
|
|
Twine location = base + ext;
|
|
|
|
if (fs::exists(location))
|
|
|
|
return location.str();
|
|
|
|
}
|
2020-08-08 02:04:54 +08:00
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
2020-06-04 03:20:35 +08:00
|
|
|
|
2020-08-08 02:04:54 +08:00
|
|
|
static Optional<std::string> findLibrary(StringRef name) {
|
2020-09-20 23:37:20 +08:00
|
|
|
if (config->searchDylibsFirst) {
|
|
|
|
if (Optional<std::string> path =
|
|
|
|
findAlongPathsWithExtensions(name, {".tbd", ".dylib"}))
|
|
|
|
return path;
|
|
|
|
return findAlongPathsWithExtensions(name, {".a"});
|
2020-06-04 03:20:35 +08:00
|
|
|
}
|
2020-09-20 23:37:20 +08:00
|
|
|
return findAlongPathsWithExtensions(name, {".tbd", ".dylib", ".a"});
|
2020-04-22 04:37:57 +08:00
|
|
|
}
|
|
|
|
|
2020-07-27 03:46:46 +08:00
|
|
|
static Optional<std::string> findFramework(StringRef name) {
|
2021-01-10 00:58:19 +08:00
|
|
|
SmallString<260> symlink;
|
2020-07-27 03:46:46 +08:00
|
|
|
StringRef suffix;
|
|
|
|
std::tie(name, suffix) = name.split(",");
|
|
|
|
for (StringRef dir : config->frameworkSearchPaths) {
|
|
|
|
symlink = dir;
|
|
|
|
path::append(symlink, name + ".framework", name);
|
2020-08-08 02:04:54 +08:00
|
|
|
|
2020-07-27 03:46:46 +08:00
|
|
|
if (!suffix.empty()) {
|
2020-08-08 02:04:54 +08:00
|
|
|
// NOTE: we must resolve the symlink before trying the suffixes, because
|
|
|
|
// there are no symlinks for the suffixed paths.
|
2021-01-10 00:58:19 +08:00
|
|
|
SmallString<260> location;
|
2020-08-08 02:04:54 +08:00
|
|
|
if (!fs::real_path(symlink, location)) {
|
|
|
|
// only append suffix if realpath() succeeds
|
|
|
|
Twine suffixed = location + suffix;
|
|
|
|
if (fs::exists(suffixed))
|
|
|
|
return suffixed.str();
|
|
|
|
}
|
2020-07-27 03:46:46 +08:00
|
|
|
// Suffix lookup failed, fall through to the no-suffix case.
|
|
|
|
}
|
2020-08-08 02:04:54 +08:00
|
|
|
|
2020-08-14 04:48:47 +08:00
|
|
|
if (Optional<std::string> path = resolveDylibPath(symlink))
|
2020-08-08 02:04:54 +08:00
|
|
|
return path;
|
2020-07-27 03:46:46 +08:00
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
static TargetInfo *createTargetInfo(opt::InputArgList &args) {
|
2020-09-27 04:00:22 +08:00
|
|
|
// TODO: should unspecified arch be an error rather than defaulting?
|
|
|
|
// Jez: ld64 seems to make unspecified arch an error when LTO is
|
|
|
|
// being used. I'm not sure why though. Feels like we should be able
|
|
|
|
// to infer the arch from our input files regardless
|
|
|
|
StringRef archName = args.getLastArgValue(OPT_arch, "x86_64");
|
|
|
|
config->arch = MachO::getArchitectureFromName(archName);
|
|
|
|
switch (MachO::getCPUTypeFromArchitecture(config->arch).first) {
|
|
|
|
case MachO::CPU_TYPE_X86_64:
|
2020-06-06 10:54:58 +08:00
|
|
|
return createX86_64TargetInfo();
|
2020-09-27 04:00:22 +08:00
|
|
|
case MachO::CPU_TYPE_ARM64:
|
|
|
|
return createARM64TargetInfo();
|
2020-06-06 10:54:58 +08:00
|
|
|
default:
|
2020-09-27 04:00:22 +08:00
|
|
|
fatal("missing or unsupported -arch " + archName);
|
2020-06-06 10:54:58 +08:00
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
|
2020-08-14 04:03:00 +08:00
|
|
|
static bool warnIfNotDirectory(StringRef option, StringRef path) {
|
2020-06-18 10:59:27 +08:00
|
|
|
if (!fs::exists(path)) {
|
|
|
|
warn("directory not found for option -" + option + path);
|
|
|
|
return false;
|
|
|
|
} else if (!fs::is_directory(path)) {
|
|
|
|
warn("option -" + option + path + " references a non-directory path");
|
|
|
|
return false;
|
2020-04-22 04:37:57 +08:00
|
|
|
}
|
2020-06-18 10:59:27 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-09-19 11:51:38 +08:00
|
|
|
static std::vector<StringRef>
|
|
|
|
getSearchPaths(unsigned optionCode, opt::InputArgList &args,
|
|
|
|
const std::vector<StringRef> &roots,
|
|
|
|
const SmallVector<StringRef, 2> &systemPaths) {
|
|
|
|
std::vector<StringRef> paths;
|
2020-08-14 04:03:00 +08:00
|
|
|
StringRef optionLetter{optionCode == OPT_F ? "F" : "L"};
|
|
|
|
for (StringRef path : args::getStrings(args, optionCode)) {
|
2020-06-20 12:13:03 +08:00
|
|
|
// NOTE: only absolute paths are re-rooted to syslibroot(s)
|
2020-08-14 04:03:00 +08:00
|
|
|
bool found = false;
|
|
|
|
if (path::is_absolute(path, path::Style::posix)) {
|
2020-06-20 12:13:03 +08:00
|
|
|
for (StringRef root : roots) {
|
|
|
|
SmallString<261> buffer(root);
|
2020-08-14 04:03:00 +08:00
|
|
|
path::append(buffer, path);
|
2020-06-20 12:13:03 +08:00
|
|
|
// Do not warn about paths that are computed via the syslib roots
|
2020-08-14 04:03:00 +08:00
|
|
|
if (fs::is_directory(buffer)) {
|
2020-06-20 12:13:03 +08:00
|
|
|
paths.push_back(saver.save(buffer.str()));
|
2020-08-14 04:03:00 +08:00
|
|
|
found = true;
|
|
|
|
}
|
2020-06-20 12:13:03 +08:00
|
|
|
}
|
2020-06-18 10:59:27 +08:00
|
|
|
}
|
2020-08-14 04:03:00 +08:00
|
|
|
if (!found && warnIfNotDirectory(optionLetter, path))
|
|
|
|
paths.push_back(path);
|
2020-06-18 10:59:27 +08:00
|
|
|
}
|
2020-06-20 12:13:03 +08:00
|
|
|
|
|
|
|
// `-Z` suppresses the standard "system" search paths.
|
|
|
|
if (args.hasArg(OPT_Z))
|
2020-09-19 11:51:38 +08:00
|
|
|
return paths;
|
2020-06-20 12:13:03 +08:00
|
|
|
|
|
|
|
for (auto const &path : systemPaths) {
|
|
|
|
for (auto root : roots) {
|
|
|
|
SmallString<261> buffer(root);
|
2020-08-14 04:03:00 +08:00
|
|
|
path::append(buffer, path);
|
2020-11-21 05:05:33 +08:00
|
|
|
if (fs::is_directory(buffer))
|
2020-06-20 12:13:03 +08:00
|
|
|
paths.push_back(saver.save(buffer.str()));
|
|
|
|
}
|
|
|
|
}
|
2020-09-19 11:51:38 +08:00
|
|
|
return paths;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::vector<StringRef> getSystemLibraryRoots(opt::InputArgList &args) {
|
|
|
|
std::vector<StringRef> roots;
|
|
|
|
for (const Arg *arg : args.filtered(OPT_syslibroot))
|
|
|
|
roots.push_back(arg->getValue());
|
|
|
|
// NOTE: the final `-syslibroot` being `/` will ignore all roots
|
|
|
|
if (roots.size() && roots.back() == "/")
|
|
|
|
roots.clear();
|
|
|
|
// NOTE: roots can never be empty - add an empty root to simplify the library
|
|
|
|
// and framework search path computation.
|
|
|
|
if (roots.empty())
|
|
|
|
roots.emplace_back("");
|
|
|
|
return roots;
|
2020-06-18 10:59:27 +08:00
|
|
|
}
|
|
|
|
|
2020-09-19 11:51:38 +08:00
|
|
|
static std::vector<StringRef>
|
|
|
|
getLibrarySearchPaths(opt::InputArgList &args,
|
|
|
|
const std::vector<StringRef> &roots) {
|
|
|
|
return getSearchPaths(OPT_L, args, roots, {"/usr/lib", "/usr/local/lib"});
|
2020-06-18 10:59:27 +08:00
|
|
|
}
|
|
|
|
|
2020-09-19 11:51:38 +08:00
|
|
|
static std::vector<StringRef>
|
|
|
|
getFrameworkSearchPaths(opt::InputArgList &args,
|
|
|
|
const std::vector<StringRef> &roots) {
|
|
|
|
return getSearchPaths(OPT_F, args, roots,
|
|
|
|
{"/Library/Frameworks", "/System/Library/Frameworks"});
|
2020-04-22 04:37:57 +08:00
|
|
|
}
|
|
|
|
|
2020-12-02 06:45:11 +08:00
|
|
|
namespace {
|
|
|
|
struct ArchiveMember {
|
|
|
|
MemoryBufferRef mbref;
|
|
|
|
uint32_t modTime;
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
2020-08-19 05:37:04 +08:00
|
|
|
// Returns slices of MB by parsing MB as an archive file.
|
|
|
|
// Each slice consists of a member file in the archive.
|
2020-12-02 06:45:11 +08:00
|
|
|
static std::vector<ArchiveMember> getArchiveMembers(MemoryBufferRef mb) {
|
2020-08-19 05:37:04 +08:00
|
|
|
std::unique_ptr<Archive> file =
|
|
|
|
CHECK(Archive::create(mb),
|
|
|
|
mb.getBufferIdentifier() + ": failed to parse archive");
|
2020-11-20 23:14:57 +08:00
|
|
|
Archive *archive = file.get();
|
|
|
|
make<std::unique_ptr<Archive>>(std::move(file)); // take ownership
|
2020-08-19 05:37:04 +08:00
|
|
|
|
2020-12-02 06:45:11 +08:00
|
|
|
std::vector<ArchiveMember> v;
|
2020-08-19 05:37:04 +08:00
|
|
|
Error err = Error::success();
|
2020-12-02 12:31:57 +08:00
|
|
|
|
|
|
|
// Thin archives refer to .o files, so --reproduces needs the .o files too.
|
|
|
|
bool addToTar = archive->isThin() && tar;
|
|
|
|
|
2020-11-20 23:14:57 +08:00
|
|
|
for (const Archive::Child &c : archive->children(err)) {
|
2020-08-19 05:37:04 +08:00
|
|
|
MemoryBufferRef mbref =
|
|
|
|
CHECK(c.getMemoryBufferRef(),
|
|
|
|
mb.getBufferIdentifier() +
|
|
|
|
": could not get the buffer for a child of the archive");
|
2020-12-02 12:31:57 +08:00
|
|
|
if (addToTar)
|
|
|
|
tar->append(relativeToRoot(check(c.getFullName())), mbref.getBuffer());
|
2020-12-02 06:45:11 +08:00
|
|
|
uint32_t modTime = toTimeT(
|
|
|
|
CHECK(c.getLastModified(), mb.getBufferIdentifier() +
|
|
|
|
": could not get the modification "
|
|
|
|
"time for a child of the archive"));
|
|
|
|
v.push_back({mbref, modTime});
|
2020-08-19 05:37:04 +08:00
|
|
|
}
|
|
|
|
if (err)
|
|
|
|
fatal(mb.getBufferIdentifier() +
|
|
|
|
": Archive::children failed: " + toString(std::move(err)));
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2020-11-20 23:14:57 +08:00
|
|
|
static InputFile *addFile(StringRef path, bool forceLoadArchive) {
|
2020-04-03 02:54:05 +08:00
|
|
|
Optional<MemoryBufferRef> buffer = readFile(path);
|
|
|
|
if (!buffer)
|
2020-09-19 02:38:15 +08:00
|
|
|
return nullptr;
|
2020-04-03 02:54:05 +08:00
|
|
|
MemoryBufferRef mbref = *buffer;
|
2020-09-19 02:38:15 +08:00
|
|
|
InputFile *newFile = nullptr;
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2020-12-03 07:57:30 +08:00
|
|
|
auto magic = identify_magic(mbref.getBuffer());
|
|
|
|
switch (magic) {
|
2020-05-15 03:43:51 +08:00
|
|
|
case file_magic::archive: {
|
|
|
|
std::unique_ptr<object::Archive> file = CHECK(
|
|
|
|
object::Archive::create(mbref), path + ": failed to parse archive");
|
|
|
|
|
|
|
|
if (!file->isEmpty() && !file->hasSymbolTable())
|
|
|
|
error(path + ": archive has no index; run ranlib to add one");
|
|
|
|
|
2020-11-20 23:14:57 +08:00
|
|
|
if (config->allLoad || forceLoadArchive) {
|
|
|
|
if (Optional<MemoryBufferRef> buffer = readFile(path)) {
|
|
|
|
for (const ArchiveMember &member : getArchiveMembers(*buffer)) {
|
2021-02-04 02:31:42 +08:00
|
|
|
if (Optional<InputFile *> file = loadArchiveMember(
|
|
|
|
member.mbref, member.modTime, path, /*objCOnly=*/false)) {
|
|
|
|
inputFiles.insert(*file);
|
|
|
|
printArchiveMemberLoad(
|
|
|
|
(forceLoadArchive ? "-force_load" : "-all_load"),
|
|
|
|
inputFiles.back());
|
|
|
|
}
|
2020-11-20 23:14:57 +08:00
|
|
|
}
|
|
|
|
}
|
2020-08-26 11:00:42 +08:00
|
|
|
} else if (config->forceLoadObjC) {
|
2020-08-19 05:37:04 +08:00
|
|
|
for (const object::Archive::Symbol &sym : file->symbols())
|
|
|
|
if (sym.getName().startswith(objc::klass))
|
2021-02-04 02:31:40 +08:00
|
|
|
symtab->addUndefined(sym.getName(), /*file=*/nullptr,
|
|
|
|
/*isWeakRef=*/false);
|
2020-08-19 05:37:04 +08:00
|
|
|
|
|
|
|
// TODO: no need to look for ObjC sections for a given archive member if
|
|
|
|
// we already found that it contains an ObjC symbol. We should also
|
|
|
|
// consider creating a LazyObjFile class in order to avoid double-loading
|
|
|
|
// these files here and below (as part of the ArchiveFile).
|
2020-12-02 08:00:48 +08:00
|
|
|
if (Optional<MemoryBufferRef> buffer = readFile(path)) {
|
|
|
|
for (const ArchiveMember &member : getArchiveMembers(*buffer)) {
|
2021-02-04 02:31:42 +08:00
|
|
|
if (Optional<InputFile *> file = loadArchiveMember(
|
|
|
|
member.mbref, member.modTime, path, /*objCOnly=*/true)) {
|
|
|
|
inputFiles.insert(*file);
|
2020-12-03 07:57:30 +08:00
|
|
|
printArchiveMemberLoad("-ObjC", inputFiles.back());
|
2020-12-02 08:00:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-19 05:37:04 +08:00
|
|
|
}
|
|
|
|
|
2020-09-19 02:38:15 +08:00
|
|
|
newFile = make<ArchiveFile>(std::move(file));
|
2020-05-15 03:43:51 +08:00
|
|
|
break;
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
case file_magic::macho_object:
|
2020-12-02 08:00:48 +08:00
|
|
|
newFile = make<ObjFile>(mbref, getModTime(path), "");
|
2020-04-03 02:54:05 +08:00
|
|
|
break;
|
2020-04-22 04:37:57 +08:00
|
|
|
case file_magic::macho_dynamically_linked_shared_lib:
|
2020-10-08 05:50:42 +08:00
|
|
|
case file_magic::macho_dynamically_linked_shared_lib_stub:
|
2021-01-19 23:44:42 +08:00
|
|
|
case file_magic::tapi_file:
|
2020-12-10 14:29:28 +08:00
|
|
|
if (Optional<DylibFile *> dylibFile = loadDylib(mbref))
|
2020-10-27 10:18:29 +08:00
|
|
|
newFile = *dylibFile;
|
2020-06-06 02:18:33 +08:00
|
|
|
break;
|
2020-10-27 10:18:29 +08:00
|
|
|
case file_magic::bitcode:
|
|
|
|
newFile = make<BitcodeFile>(mbref);
|
|
|
|
break;
|
2020-04-03 02:54:05 +08:00
|
|
|
default:
|
|
|
|
error(path + ": unhandled file type");
|
|
|
|
}
|
2020-12-03 07:57:30 +08:00
|
|
|
if (newFile) {
|
|
|
|
// printArchiveMemberLoad() prints both .a and .o names, so no need to
|
|
|
|
// print the .a name here.
|
|
|
|
if (config->printEachFile && magic != file_magic::archive)
|
2020-12-18 05:19:06 +08:00
|
|
|
message(toString(newFile));
|
2020-12-15 06:59:22 +08:00
|
|
|
inputFiles.insert(newFile);
|
2020-12-03 07:57:30 +08:00
|
|
|
}
|
2020-09-19 02:38:15 +08:00
|
|
|
return newFile;
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
|
2020-12-04 05:40:04 +08:00
|
|
|
static void addLibrary(StringRef name, bool isWeak) {
|
|
|
|
if (Optional<std::string> path = findLibrary(name)) {
|
|
|
|
auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(*path, false));
|
|
|
|
if (isWeak && dylibFile)
|
|
|
|
dylibFile->forceWeakImport = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
error("library not found for -l" + name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void addFramework(StringRef name, bool isWeak) {
|
|
|
|
if (Optional<std::string> path = findFramework(name)) {
|
|
|
|
auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(*path, false));
|
|
|
|
if (isWeak && dylibFile)
|
|
|
|
dylibFile->forceWeakImport = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
error("framework not found for -framework " + name);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parses LC_LINKER_OPTION contents, which can add additional command line flags.
|
|
|
|
void macho::parseLCLinkerOption(InputFile* f, unsigned argc, StringRef data) {
|
|
|
|
SmallVector<const char *, 4> argv;
|
|
|
|
size_t offset = 0;
|
|
|
|
for (unsigned i = 0; i < argc && offset < data.size(); ++i) {
|
|
|
|
argv.push_back(data.data() + offset);
|
|
|
|
offset += strlen(data.data() + offset) + 1;
|
|
|
|
}
|
|
|
|
if (argv.size() != argc || offset > data.size())
|
|
|
|
fatal(toString(f) + ": invalid LC_LINKER_OPTION");
|
|
|
|
|
|
|
|
MachOOptTable table;
|
|
|
|
unsigned missingIndex, missingCount;
|
|
|
|
opt::InputArgList args = table.ParseArgs(argv, missingIndex, missingCount);
|
|
|
|
if (missingCount)
|
|
|
|
fatal(Twine(args.getArgString(missingIndex)) + ": missing argument");
|
|
|
|
for (auto *arg : args.filtered(OPT_UNKNOWN))
|
|
|
|
error("unknown argument: " + arg->getAsString(args));
|
|
|
|
|
|
|
|
for (auto *arg : args) {
|
|
|
|
switch (arg->getOption().getID()) {
|
|
|
|
case OPT_l:
|
|
|
|
addLibrary(arg->getValue(), false);
|
|
|
|
break;
|
|
|
|
case OPT_framework:
|
|
|
|
addFramework(arg->getValue(), false);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error(arg->getSpelling() + " is not allowed in LC_LINKER_OPTION");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-29 00:56:50 +08:00
|
|
|
static void addFileList(StringRef path) {
|
|
|
|
Optional<MemoryBufferRef> buffer = readFile(path);
|
|
|
|
if (!buffer)
|
|
|
|
return;
|
|
|
|
MemoryBufferRef mbref = *buffer;
|
|
|
|
for (StringRef path : args::getLines(mbref))
|
2020-11-20 23:14:57 +08:00
|
|
|
addFile(path, false);
|
2020-07-29 00:56:50 +08:00
|
|
|
}
|
|
|
|
|
2020-05-06 07:37:34 +08:00
|
|
|
// An order file has one entry per line, in the following format:
|
|
|
|
//
|
2020-12-19 01:47:15 +08:00
|
|
|
// <cpu>:<object file>:<symbol name>
|
2020-05-06 07:37:34 +08:00
|
|
|
//
|
2020-12-19 01:47:15 +08:00
|
|
|
// <cpu> and <object file> are optional. If not specified, then that entry
|
|
|
|
// matches any symbol of that name. Parsing this format is not quite
|
|
|
|
// straightforward because the symbol name itself can contain colons, so when
|
|
|
|
// encountering a colon, we consider the preceding characters to decide if it
|
|
|
|
// can be a valid CPU type or file path.
|
2020-05-06 07:37:34 +08:00
|
|
|
//
|
|
|
|
// If a symbol is matched by multiple entries, then it takes the lowest-ordered
|
|
|
|
// entry (the one nearest to the front of the list.)
|
|
|
|
//
|
|
|
|
// The file can also have line comments that start with '#'.
|
2020-07-17 19:49:11 +08:00
|
|
|
static void parseOrderFile(StringRef path) {
|
2020-05-06 07:37:34 +08:00
|
|
|
Optional<MemoryBufferRef> buffer = readFile(path);
|
|
|
|
if (!buffer) {
|
|
|
|
error("Could not read order file at " + path);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MemoryBufferRef mbref = *buffer;
|
|
|
|
size_t priority = std::numeric_limits<size_t>::max();
|
2020-12-19 01:47:15 +08:00
|
|
|
for (StringRef line : args::getLines(mbref)) {
|
|
|
|
StringRef objectFile, symbol;
|
|
|
|
line = line.take_until([](char c) { return c == '#'; }); // ignore comments
|
|
|
|
line = line.ltrim();
|
|
|
|
|
|
|
|
CPUType cpuType = StringSwitch<CPUType>(line)
|
|
|
|
.StartsWith("i386:", CPU_TYPE_I386)
|
|
|
|
.StartsWith("x86_64:", CPU_TYPE_X86_64)
|
|
|
|
.StartsWith("arm:", CPU_TYPE_ARM)
|
|
|
|
.StartsWith("arm64:", CPU_TYPE_ARM64)
|
|
|
|
.StartsWith("ppc:", CPU_TYPE_POWERPC)
|
|
|
|
.StartsWith("ppc64:", CPU_TYPE_POWERPC64)
|
|
|
|
.Default(CPU_TYPE_ANY);
|
|
|
|
// Drop the CPU type as well as the colon
|
|
|
|
if (cpuType != CPU_TYPE_ANY)
|
|
|
|
line = line.drop_until([](char c) { return c == ':'; }).drop_front();
|
|
|
|
// TODO: Update when we extend support for other CPUs
|
2020-09-27 04:00:22 +08:00
|
|
|
if (cpuType != CPU_TYPE_ANY && cpuType != CPU_TYPE_X86_64 &&
|
|
|
|
cpuType != CPU_TYPE_ARM64)
|
2020-12-19 01:47:15 +08:00
|
|
|
continue;
|
2020-05-06 07:37:34 +08:00
|
|
|
|
2020-12-19 01:47:15 +08:00
|
|
|
constexpr std::array<StringRef, 2> fileEnds = {".o:", ".o):"};
|
|
|
|
for (StringRef fileEnd : fileEnds) {
|
|
|
|
size_t pos = line.find(fileEnd);
|
|
|
|
if (pos != StringRef::npos) {
|
|
|
|
// Split the string around the colon
|
|
|
|
objectFile = line.take_front(pos + fileEnd.size() - 1);
|
|
|
|
line = line.drop_front(pos + fileEnd.size());
|
|
|
|
break;
|
2020-05-06 07:37:34 +08:00
|
|
|
}
|
|
|
|
}
|
2020-12-19 01:47:15 +08:00
|
|
|
symbol = line.trim();
|
2020-05-06 07:37:34 +08:00
|
|
|
|
|
|
|
if (!symbol.empty()) {
|
|
|
|
SymbolPriorityEntry &entry = config->priorities[symbol];
|
|
|
|
if (!objectFile.empty())
|
|
|
|
entry.objectFiles.insert(std::make_pair(objectFile, priority));
|
|
|
|
else
|
|
|
|
entry.anyObjectFile = std::max(entry.anyObjectFile, priority);
|
|
|
|
}
|
|
|
|
|
|
|
|
--priority;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-24 11:16:49 +08:00
|
|
|
// We expect sub-library names of the form "libfoo", which will match a dylib
|
2020-08-19 06:46:21 +08:00
|
|
|
// with a path of .*/libfoo.{dylib, tbd}.
|
|
|
|
// XXX ld64 seems to ignore the extension entirely when matching sub-libraries;
|
|
|
|
// I'm not sure what the use case for that is.
|
2020-12-15 11:55:28 +08:00
|
|
|
static bool markReexport(StringRef searchName, ArrayRef<StringRef> extensions) {
|
2020-04-24 11:16:49 +08:00
|
|
|
for (InputFile *file : inputFiles) {
|
|
|
|
if (auto *dylibFile = dyn_cast<DylibFile>(file)) {
|
|
|
|
StringRef filename = path::filename(dylibFile->getName());
|
2020-08-19 06:46:21 +08:00
|
|
|
if (filename.consume_front(searchName) &&
|
2020-12-15 11:55:28 +08:00
|
|
|
(filename.empty() ||
|
|
|
|
find(extensions, filename) != extensions.end())) {
|
2020-04-24 11:16:49 +08:00
|
|
|
dylibFile->reexport = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-10-27 10:18:29 +08:00
|
|
|
// This function is called on startup. We need this for LTO since
|
|
|
|
// LTO calls LLVM functions to compile bitcode files to native code.
|
|
|
|
// Technically this can be delayed until we read bitcode files, but
|
|
|
|
// we don't bother to do lazily because the initialization is fast.
|
|
|
|
static void initLLVM() {
|
|
|
|
InitializeAllTargets();
|
|
|
|
InitializeAllTargetMCs();
|
|
|
|
InitializeAllAsmPrinters();
|
|
|
|
InitializeAllAsmParsers();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void compileBitcodeFiles() {
|
|
|
|
auto lto = make<BitcodeCompiler>();
|
|
|
|
for (InputFile *file : inputFiles)
|
|
|
|
if (auto *bitcodeFile = dyn_cast<BitcodeFile>(file))
|
|
|
|
lto->add(*bitcodeFile);
|
|
|
|
|
|
|
|
for (ObjFile *file : lto->compile())
|
2020-12-15 06:59:22 +08:00
|
|
|
inputFiles.insert(file);
|
2020-10-27 10:18:29 +08:00
|
|
|
}
|
|
|
|
|
2020-09-25 05:44:14 +08:00
|
|
|
// Replaces common symbols with defined symbols residing in __common sections.
|
|
|
|
// This function must be called after all symbol names are resolved (i.e. after
|
|
|
|
// all InputFiles have been loaded.) As a result, later operations won't see
|
|
|
|
// any CommonSymbols.
|
|
|
|
static void replaceCommonSymbols() {
|
|
|
|
for (macho::Symbol *sym : symtab->getSymbols()) {
|
|
|
|
auto *common = dyn_cast<CommonSymbol>(sym);
|
|
|
|
if (common == nullptr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
auto *isec = make<InputSection>();
|
2021-02-04 02:31:40 +08:00
|
|
|
isec->file = common->getFile();
|
2020-09-25 05:44:14 +08:00
|
|
|
isec->name = section_names::common;
|
|
|
|
isec->segname = segment_names::data;
|
|
|
|
isec->align = common->align;
|
|
|
|
// Casting to size_t will truncate large values on 32-bit architectures,
|
|
|
|
// but it's not really worth supporting the linking of 64-bit programs on
|
|
|
|
// 32-bit archs.
|
|
|
|
isec->data = {nullptr, static_cast<size_t>(common->size)};
|
|
|
|
isec->flags = S_ZEROFILL;
|
|
|
|
inputSections.push_back(isec);
|
|
|
|
|
2021-02-04 02:31:40 +08:00
|
|
|
replaceSymbol<Defined>(sym, sym->getName(), isec->file, isec, /*value=*/0,
|
2020-09-25 05:44:14 +08:00
|
|
|
/*isWeakDef=*/false,
|
[lld/mac] Implement support for private extern symbols
Private extern symbols are used for things scoped to the linkage unit.
They cause duplicate symbol errors (so they're in the symbol table,
unlike TU-scoped truly local symbols), but they don't make it into the
export trie. They are created e.g. by compiling with
-fvisibility=hidden.
If two weak symbols have differing privateness, the combined symbol is
non-private external. (Example: inline functions and some TUs that
include the header defining it were built with
-fvisibility-inlines-hidden and some weren't).
A weak private external symbol implicitly has its "weak" dropped and
behaves like a regular strong private external symbol: Weak is an export
trie concept, and private symbols are not in the export trie.
If a weak and a strong symbol have different privateness, the strong
symbol wins.
If two common symbols have differing privateness, the larger symbol
wins. If they have the same size, the privateness of the symbol seen
later during the link wins (!) -- this is a bit lame, but it matches
ld64 and this behavior takes 2 lines less to implement than the less
surprising "result is non-private external), so match ld64.
(Example: `int a` in two .c files, both built with -fcommon,
one built with -fvisibility=hidden and one without.)
This also makes `__dyld_private` a true TU-local symbol, matching ld64.
To make this work, make the `const char*` StringRefZ ctor to correctly
set `size` (without this, writing the string table crashed when calling
getName() on the __dyld_private symbol).
Mention in CommonSymbol's comment that common symbols are now disabled
by default in clang.
Mention in -keep_private_externs's HelpText that the flag only has an
effect with `-r` (which we don't implement yet -- so this patch here
doesn't regress any behavior around -r + -keep_private_externs)). ld64
doesn't explicitly document it, but the commit text of
http://reviews.llvm.org/rL216146 does, and ld64's
OutputFile::buildSymbolTable() checks `_options.outputKind() ==
Options::kObjectFile` before calling `_options.keepPrivateExterns()`
(the only reference to that function).
Fixes PR48536.
Differential Revision: https://reviews.llvm.org/D93609
2020-12-18 02:30:18 +08:00
|
|
|
/*isExternal=*/true, common->privateExtern);
|
2020-09-25 05:44:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-11 09:47:16 +08:00
|
|
|
static inline char toLowerDash(char x) {
|
|
|
|
if (x >= 'A' && x <= 'Z')
|
|
|
|
return x - 'A' + 'a';
|
|
|
|
else if (x == ' ')
|
|
|
|
return '-';
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string lowerDash(StringRef s) {
|
|
|
|
return std::string(map_iterator(s.begin(), toLowerDash),
|
|
|
|
map_iterator(s.end(), toLowerDash));
|
|
|
|
}
|
|
|
|
|
2020-06-16 03:36:32 +08:00
|
|
|
static void handlePlatformVersion(const opt::Arg *arg) {
|
2020-08-11 09:47:16 +08:00
|
|
|
StringRef platformStr = arg->getValue(0);
|
|
|
|
StringRef minVersionStr = arg->getValue(1);
|
|
|
|
StringRef sdkVersionStr = arg->getValue(2);
|
|
|
|
|
|
|
|
// TODO(compnerd) see if we can generate this case list via XMACROS
|
|
|
|
config->platform.kind =
|
2020-12-24 00:24:02 +08:00
|
|
|
StringSwitch<PlatformKind>(lowerDash(platformStr))
|
|
|
|
.Cases("macos", "1", PlatformKind::macOS)
|
|
|
|
.Cases("ios", "2", PlatformKind::iOS)
|
|
|
|
.Cases("tvos", "3", PlatformKind::tvOS)
|
|
|
|
.Cases("watchos", "4", PlatformKind::watchOS)
|
|
|
|
.Cases("bridgeos", "5", PlatformKind::bridgeOS)
|
|
|
|
.Cases("mac-catalyst", "6", PlatformKind::macCatalyst)
|
|
|
|
.Cases("ios-simulator", "7", PlatformKind::iOSSimulator)
|
|
|
|
.Cases("tvos-simulator", "8", PlatformKind::tvOSSimulator)
|
|
|
|
.Cases("watchos-simulator", "9", PlatformKind::watchOSSimulator)
|
|
|
|
.Cases("driverkit", "10", PlatformKind::driverKit)
|
|
|
|
.Default(PlatformKind::unknown);
|
|
|
|
if (config->platform.kind == PlatformKind::unknown)
|
2020-08-11 09:47:16 +08:00
|
|
|
error(Twine("malformed platform: ") + platformStr);
|
|
|
|
// TODO: check validity of version strings, which varies by platform
|
|
|
|
// NOTE: ld64 accepts version strings with 5 components
|
|
|
|
// llvm::VersionTuple accepts no more than 4 components
|
|
|
|
// Has Apple ever published version strings with 5 components?
|
|
|
|
if (config->platform.minimum.tryParse(minVersionStr))
|
|
|
|
error(Twine("malformed minimum version: ") + minVersionStr);
|
|
|
|
if (config->platform.sdk.tryParse(sdkVersionStr))
|
|
|
|
error(Twine("malformed sdk version: ") + sdkVersionStr);
|
2020-06-16 03:36:32 +08:00
|
|
|
}
|
|
|
|
|
2020-12-14 11:31:33 +08:00
|
|
|
static void handleUndefined(const opt::Arg *arg) {
|
|
|
|
StringRef treatmentStr = arg->getValue(0);
|
|
|
|
config->undefinedSymbolTreatment =
|
2021-01-10 00:58:19 +08:00
|
|
|
StringSwitch<UndefinedSymbolTreatment>(treatmentStr)
|
2020-12-14 11:31:33 +08:00
|
|
|
.Case("error", UndefinedSymbolTreatment::error)
|
|
|
|
.Case("warning", UndefinedSymbolTreatment::warning)
|
|
|
|
.Case("suppress", UndefinedSymbolTreatment::suppress)
|
|
|
|
.Case("dynamic_lookup", UndefinedSymbolTreatment::dynamic_lookup)
|
|
|
|
.Default(UndefinedSymbolTreatment::unknown);
|
|
|
|
if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::unknown) {
|
|
|
|
warn(Twine("unknown -undefined TREATMENT '") + treatmentStr +
|
|
|
|
"', defaulting to 'error'");
|
|
|
|
config->undefinedSymbolTreatment = UndefinedSymbolTreatment::error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 03:36:32 +08:00
|
|
|
static void warnIfDeprecatedOption(const opt::Option &opt) {
|
|
|
|
if (!opt.getGroup().isValid())
|
|
|
|
return;
|
|
|
|
if (opt.getGroup().getID() == OPT_grp_deprecated) {
|
|
|
|
warn("Option `" + opt.getPrefixedName() + "' is deprecated in ld64:");
|
|
|
|
warn(opt.getHelpText());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void warnIfUnimplementedOption(const opt::Option &opt) {
|
2020-09-23 23:53:37 +08:00
|
|
|
if (!opt.getGroup().isValid() || !opt.hasFlag(DriverFlag::HelpHidden))
|
2020-06-16 03:36:32 +08:00
|
|
|
return;
|
|
|
|
switch (opt.getGroup().getID()) {
|
|
|
|
case OPT_grp_deprecated:
|
|
|
|
// warn about deprecated options elsewhere
|
|
|
|
break;
|
|
|
|
case OPT_grp_undocumented:
|
|
|
|
warn("Option `" + opt.getPrefixedName() +
|
|
|
|
"' is undocumented. Should lld implement it?");
|
|
|
|
break;
|
|
|
|
case OPT_grp_obsolete:
|
|
|
|
warn("Option `" + opt.getPrefixedName() +
|
|
|
|
"' is obsolete. Please modernize your usage.");
|
|
|
|
break;
|
|
|
|
case OPT_grp_ignored:
|
|
|
|
warn("Option `" + opt.getPrefixedName() + "' is ignored.");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
warn("Option `" + opt.getPrefixedName() +
|
|
|
|
"' is not yet implemented. Stay tuned...");
|
|
|
|
break;
|
2020-05-13 02:02:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-29 11:38:27 +08:00
|
|
|
static const char *getReproduceOption(opt::InputArgList &args) {
|
|
|
|
if (auto *arg = args.getLastArg(OPT_reproduce))
|
|
|
|
return arg->getValue();
|
|
|
|
return getenv("LLD_REPRODUCE");
|
|
|
|
}
|
|
|
|
|
2020-12-01 13:07:16 +08:00
|
|
|
static bool isPie(opt::InputArgList &args) {
|
|
|
|
if (config->outputType != MH_EXECUTE || args.hasArg(OPT_no_pie))
|
|
|
|
return false;
|
2020-09-27 04:00:22 +08:00
|
|
|
if (config->arch == AK_arm64 || config->arch == AK_arm64e)
|
|
|
|
return true;
|
2020-12-01 13:07:16 +08:00
|
|
|
|
|
|
|
// TODO: add logic here as we support more archs. E.g. i386 should default
|
2020-09-27 04:00:22 +08:00
|
|
|
// to PIE from 10.7
|
2020-12-01 13:07:16 +08:00
|
|
|
assert(config->arch == AK_x86_64 || config->arch == AK_x86_64h);
|
|
|
|
|
2020-12-24 00:24:02 +08:00
|
|
|
PlatformKind kind = config->platform.kind;
|
|
|
|
if (kind == PlatformKind::macOS &&
|
2020-12-01 13:07:16 +08:00
|
|
|
config->platform.minimum >= VersionTuple(10, 6))
|
|
|
|
return true;
|
|
|
|
|
2020-12-24 00:24:02 +08:00
|
|
|
if (kind == PlatformKind::iOSSimulator || kind == PlatformKind::driverKit)
|
|
|
|
return true;
|
|
|
|
|
2020-12-01 13:07:16 +08:00
|
|
|
return args.hasArg(OPT_pie);
|
|
|
|
}
|
|
|
|
|
2020-12-08 21:08:56 +08:00
|
|
|
static void parseClangOption(StringRef opt, const Twine &msg) {
|
|
|
|
std::string err;
|
|
|
|
raw_string_ostream os(err);
|
|
|
|
|
|
|
|
const char *argv[] = {"lld", opt.data()};
|
|
|
|
if (cl::ParseCommandLineOptions(2, argv, "", &os))
|
|
|
|
return;
|
|
|
|
os.flush();
|
|
|
|
error(msg + ": " + StringRef(err).trim());
|
|
|
|
}
|
|
|
|
|
2020-12-15 07:24:50 +08:00
|
|
|
static uint32_t parseDylibVersion(const opt::ArgList& args, unsigned id) {
|
|
|
|
const opt::Arg *arg = args.getLastArg(id);
|
|
|
|
if (!arg)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (config->outputType != MH_DYLIB) {
|
|
|
|
error(arg->getAsString(args) + ": only valid with -dylib");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-16 05:37:37 +08:00
|
|
|
PackedVersion version;
|
|
|
|
if (!version.parse32(arg->getValue())) {
|
2020-12-15 07:24:50 +08:00
|
|
|
error(arg->getAsString(args) + ": malformed version");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-16 05:37:37 +08:00
|
|
|
return version.rawValue();
|
2020-12-15 07:24:50 +08:00
|
|
|
}
|
|
|
|
|
2021-01-10 00:58:19 +08:00
|
|
|
bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
|
2020-04-03 02:54:05 +08:00
|
|
|
raw_ostream &stdoutOS, raw_ostream &stderrOS) {
|
|
|
|
lld::stdoutOS = &stdoutOS;
|
|
|
|
lld::stderrOS = &stderrOS;
|
|
|
|
|
2020-04-30 06:42:32 +08:00
|
|
|
stderrOS.enable_colors(stderrOS.has_colors());
|
|
|
|
// TODO: Set up error handler properly, e.g. the errorLimitExceededMsg
|
|
|
|
|
2020-09-25 03:00:43 +08:00
|
|
|
errorHandler().cleanupCallback = []() { freeArena(); };
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
MachOOptTable parser;
|
|
|
|
opt::InputArgList args = parser.parse(argsArr.slice(1));
|
|
|
|
|
2020-06-16 03:36:32 +08:00
|
|
|
if (args.hasArg(OPT_help_hidden)) {
|
|
|
|
parser.printHelp(argsArr[0], /*showHidden=*/true);
|
|
|
|
return true;
|
2020-12-23 04:51:20 +08:00
|
|
|
}
|
|
|
|
if (args.hasArg(OPT_help)) {
|
2020-06-16 03:36:32 +08:00
|
|
|
parser.printHelp(argsArr[0], /*showHidden=*/false);
|
|
|
|
return true;
|
|
|
|
}
|
2020-12-23 04:51:20 +08:00
|
|
|
if (args.hasArg(OPT_version)) {
|
|
|
|
message(getLLDVersion());
|
|
|
|
return true;
|
|
|
|
}
|
2020-06-16 03:36:32 +08:00
|
|
|
|
2020-11-29 11:38:27 +08:00
|
|
|
if (const char *path = getReproduceOption(args)) {
|
|
|
|
// Note that --reproduce is a debug option so you can ignore it
|
|
|
|
// if you are trying to understand the whole picture of the code.
|
|
|
|
Expected<std::unique_ptr<TarWriter>> errOrWriter =
|
|
|
|
TarWriter::create(path, path::stem(path));
|
|
|
|
if (errOrWriter) {
|
|
|
|
tar = std::move(*errOrWriter);
|
|
|
|
tar->append("response.txt", createResponseFile(args));
|
|
|
|
tar->append("version.txt", getLLDVersion() + "\n");
|
|
|
|
} else {
|
|
|
|
error("--reproduce: " + toString(errOrWriter.takeError()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
config = make<Configuration>();
|
|
|
|
symtab = make<SymbolTable>();
|
|
|
|
target = createTargetInfo(args);
|
|
|
|
|
2020-12-16 10:05:06 +08:00
|
|
|
config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main"),
|
2021-02-04 02:31:40 +08:00
|
|
|
/*file=*/nullptr,
|
2020-12-16 10:05:06 +08:00
|
|
|
/*isWeakRef=*/false);
|
2021-02-09 21:18:23 +08:00
|
|
|
for (auto *arg : args.filtered(OPT_u)) {
|
|
|
|
config->explicitUndefineds.push_back(symtab->addUndefined(
|
|
|
|
arg->getValue(), /*file=*/nullptr, /*isWeakRef=*/false));
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
config->outputFile = args.getLastArgValue(OPT_o, "a.out");
|
2020-04-29 07:58:22 +08:00
|
|
|
config->installName =
|
|
|
|
args.getLastArgValue(OPT_install_name, config->outputFile);
|
2020-07-31 05:38:58 +08:00
|
|
|
config->headerPad = args::getHex(args, OPT_headerpad, /*Default=*/32);
|
2020-09-22 02:04:13 +08:00
|
|
|
config->headerPadMaxInstallNames =
|
|
|
|
args.hasArg(OPT_headerpad_max_install_names);
|
2020-12-03 07:57:30 +08:00
|
|
|
config->printEachFile = args.hasArg(OPT_t);
|
2020-12-03 07:59:00 +08:00
|
|
|
config->printWhyLoad = args.hasArg(OPT_why_load);
|
2020-09-01 14:23:37 +08:00
|
|
|
config->outputType = getOutputType(args);
|
2020-12-03 12:34:17 +08:00
|
|
|
config->ltoObjPath = args.getLastArgValue(OPT_object_path_lto);
|
2021-01-13 03:41:56 +08:00
|
|
|
config->ltoNewPassManager =
|
|
|
|
args.hasFlag(OPT_no_lto_legacy_pass_manager, OPT_lto_legacy_pass_manager,
|
|
|
|
LLVM_ENABLE_NEW_PASS_MANAGER);
|
2020-08-13 10:50:28 +08:00
|
|
|
config->runtimePaths = args::getStrings(args, OPT_rpath);
|
2020-08-26 11:00:42 +08:00
|
|
|
config->allLoad = args.hasArg(OPT_all_load);
|
2020-09-19 11:51:38 +08:00
|
|
|
config->forceLoadObjC = args.hasArg(OPT_ObjC);
|
clang+lld: Improve clang+ld.darwinnew.lld interaction, pass -demangle
This patch:
- adds an ld64.lld.darwinnew symlink for lld, to go with f2710d4b576,
so that `clang -fuse-ld=lld.darwinnew` can be used to test new
Mach-O lld while it's in bring-up. (The expectation is that we'll
remove this again once new Mach-O lld is the defauld and only Mach-O
lld.)
- lets the clang driver know if the linker is lld (currently
only triggered if `-fuse-ld=lld` or `-fuse-ld=lld.darwinnew` is
passed). Currently only used for the next point, but could be used
to implement other features that need close coordination between
compiler and linker, e.g. having a diag for calling `clang++` instead
of `clang` when link errors are caused by a missing C++ stdlib.
- lets the clang driver pass `-demangle` to Mach-O lld (both old and
new), in addition to ld64
- implements -demangle for new Mach-O lld
- changes demangleItanium() to accept _Z, __Z, ___Z, ____Z prefixes
(and updates one test added in D68014). Mach-O has an extra
underscore for symbols, and the three (or, on Mach-O, four)
underscores are used for block names.
Differential Revision: https://reviews.llvm.org/D91884
2020-11-21 02:57:44 +08:00
|
|
|
config->demangle = args.hasArg(OPT_demangle);
|
2020-12-10 07:08:05 +08:00
|
|
|
config->implicitDylibs = !args.hasArg(OPT_no_implicit_dylibs);
|
2020-04-22 04:37:57 +08:00
|
|
|
|
2020-09-22 04:21:45 +08:00
|
|
|
if (const opt::Arg *arg = args.getLastArg(OPT_static, OPT_dynamic))
|
|
|
|
config->staticLink = (arg->getOption().getID() == OPT_static);
|
|
|
|
|
2020-09-19 11:51:38 +08:00
|
|
|
config->systemLibraryRoots = getSystemLibraryRoots(args);
|
|
|
|
config->librarySearchPaths =
|
|
|
|
getLibrarySearchPaths(args, config->systemLibraryRoots);
|
|
|
|
config->frameworkSearchPaths =
|
|
|
|
getFrameworkSearchPaths(args, config->systemLibraryRoots);
|
2020-09-20 23:37:20 +08:00
|
|
|
if (const opt::Arg *arg =
|
|
|
|
args.getLastArg(OPT_search_paths_first, OPT_search_dylibs_first))
|
|
|
|
config->searchDylibsFirst =
|
2021-01-10 10:17:59 +08:00
|
|
|
arg->getOption().getID() == OPT_search_dylibs_first;
|
2020-06-20 12:13:03 +08:00
|
|
|
|
2020-12-15 07:24:50 +08:00
|
|
|
config->dylibCompatibilityVersion =
|
|
|
|
parseDylibVersion(args, OPT_compatibility_version);
|
|
|
|
config->dylibCurrentVersion = parseDylibVersion(args, OPT_current_version);
|
|
|
|
|
2020-10-27 10:18:29 +08:00
|
|
|
config->saveTemps = args.hasArg(OPT_save_temps);
|
|
|
|
|
2020-04-22 04:37:57 +08:00
|
|
|
if (args.hasArg(OPT_v)) {
|
|
|
|
message(getLLDVersion());
|
2020-06-18 10:59:27 +08:00
|
|
|
message(StringRef("Library search paths:") +
|
|
|
|
(config->librarySearchPaths.size()
|
2021-01-10 00:58:19 +08:00
|
|
|
? "\n\t" + join(config->librarySearchPaths, "\n\t")
|
2020-06-18 10:59:27 +08:00
|
|
|
: ""));
|
|
|
|
message(StringRef("Framework search paths:") +
|
|
|
|
(config->frameworkSearchPaths.size()
|
2021-01-10 00:58:19 +08:00
|
|
|
? "\n\t" + join(config->frameworkSearchPaths, "\n\t")
|
2020-06-18 10:59:27 +08:00
|
|
|
: ""));
|
2020-04-22 04:37:57 +08:00
|
|
|
freeArena();
|
|
|
|
return !errorCount();
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2020-12-09 13:51:32 +08:00
|
|
|
initLLVM(); // must be run before any call to addFile()
|
|
|
|
|
2020-06-16 03:36:32 +08:00
|
|
|
for (const auto &arg : args) {
|
|
|
|
const auto &opt = arg->getOption();
|
|
|
|
warnIfDeprecatedOption(opt);
|
2020-09-23 23:53:37 +08:00
|
|
|
warnIfUnimplementedOption(opt);
|
|
|
|
// TODO: are any of these better handled via filtered() or getLastArg()?
|
2020-09-19 02:38:15 +08:00
|
|
|
switch (opt.getID()) {
|
2020-04-03 02:54:05 +08:00
|
|
|
case OPT_INPUT:
|
2020-11-20 23:14:57 +08:00
|
|
|
addFile(arg->getValue(), false);
|
2020-04-03 02:54:05 +08:00
|
|
|
break;
|
2021-01-19 23:44:42 +08:00
|
|
|
case OPT_weak_library:
|
|
|
|
if (auto *dylibFile =
|
|
|
|
dyn_cast_or_null<DylibFile>(addFile(arg->getValue(), false)))
|
2020-09-19 02:38:15 +08:00
|
|
|
dylibFile->forceWeakImport = true;
|
|
|
|
break;
|
2020-07-29 00:56:50 +08:00
|
|
|
case OPT_filelist:
|
|
|
|
addFileList(arg->getValue());
|
|
|
|
break;
|
2020-08-13 10:50:27 +08:00
|
|
|
case OPT_force_load:
|
2020-11-20 23:14:57 +08:00
|
|
|
addFile(arg->getValue(), true);
|
2020-08-13 10:50:27 +08:00
|
|
|
break;
|
2020-09-19 02:38:15 +08:00
|
|
|
case OPT_l:
|
2020-12-04 05:40:04 +08:00
|
|
|
case OPT_weak_l:
|
|
|
|
addLibrary(arg->getValue(), opt.getID() == OPT_weak_l);
|
2020-04-22 04:37:57 +08:00
|
|
|
break;
|
2020-09-19 02:38:15 +08:00
|
|
|
case OPT_framework:
|
2020-12-04 05:40:04 +08:00
|
|
|
case OPT_weak_framework:
|
|
|
|
addFramework(arg->getValue(), opt.getID() == OPT_weak_framework);
|
2020-07-27 03:46:46 +08:00
|
|
|
break;
|
2020-06-16 03:36:32 +08:00
|
|
|
case OPT_platform_version:
|
|
|
|
handlePlatformVersion(arg);
|
|
|
|
break;
|
2020-12-14 11:31:33 +08:00
|
|
|
case OPT_undefined:
|
|
|
|
handleUndefined(arg);
|
|
|
|
break;
|
2020-06-16 03:36:32 +08:00
|
|
|
default:
|
2020-05-13 02:02:13 +08:00
|
|
|
break;
|
2020-04-03 02:54:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-06 01:55:33 +08:00
|
|
|
config->isPic = config->outputType == MH_DYLIB ||
|
2020-12-01 13:07:16 +08:00
|
|
|
config->outputType == MH_BUNDLE || isPie(args);
|
2020-09-06 01:55:33 +08:00
|
|
|
|
2020-04-24 11:16:49 +08:00
|
|
|
// Now that all dylibs have been loaded, search for those that should be
|
|
|
|
// re-exported.
|
2020-12-15 11:55:28 +08:00
|
|
|
for (opt::Arg *arg : args.filtered(OPT_sub_library, OPT_sub_umbrella)) {
|
2020-04-24 11:16:49 +08:00
|
|
|
config->hasReexports = true;
|
|
|
|
StringRef searchName = arg->getValue();
|
2020-12-15 11:55:28 +08:00
|
|
|
std::vector<StringRef> extensions;
|
|
|
|
if (arg->getOption().getID() == OPT_sub_library)
|
|
|
|
extensions = {".dylib", ".tbd"};
|
|
|
|
else
|
|
|
|
extensions = {".tbd"};
|
|
|
|
if (!markReexport(searchName, extensions))
|
|
|
|
error(arg->getSpelling() + " " + searchName +
|
|
|
|
" does not match a supplied dylib");
|
2020-04-24 11:16:49 +08:00
|
|
|
}
|
|
|
|
|
2020-12-08 21:08:56 +08:00
|
|
|
// Parse LTO options.
|
|
|
|
if (auto *arg = args.getLastArg(OPT_mcpu))
|
|
|
|
parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())),
|
|
|
|
arg->getSpelling());
|
|
|
|
|
|
|
|
for (auto *arg : args.filtered(OPT_mllvm))
|
|
|
|
parseClangOption(arg->getValue(), arg->getSpelling());
|
|
|
|
|
2020-10-27 10:18:29 +08:00
|
|
|
compileBitcodeFiles();
|
2020-09-25 05:44:14 +08:00
|
|
|
replaceCommonSymbols();
|
|
|
|
|
2020-05-06 07:37:34 +08:00
|
|
|
StringRef orderFile = args.getLastArgValue(OPT_order_file);
|
|
|
|
if (!orderFile.empty())
|
|
|
|
parseOrderFile(orderFile);
|
|
|
|
|
2020-09-18 01:20:16 +08:00
|
|
|
if (config->outputType == MH_EXECUTE && isa<Undefined>(config->entry)) {
|
2020-12-02 08:00:48 +08:00
|
|
|
error("undefined symbol: " + toString(*config->entry));
|
2020-04-03 02:54:05 +08:00
|
|
|
return false;
|
|
|
|
}
|
2021-02-09 21:18:23 +08:00
|
|
|
// FIXME: This prints symbols that are undefined both in input files and
|
|
|
|
// via -u flag twice.
|
|
|
|
for (const auto *undefined : config->explicitUndefineds) {
|
|
|
|
if (isa<Undefined>(undefined)) {
|
|
|
|
error("undefined symbol: " + toString(*undefined) +
|
|
|
|
"\n>>> referenced by flag -u " + toString(*undefined));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
|
2020-04-22 04:37:57 +08:00
|
|
|
createSyntheticSections();
|
2020-07-31 05:28:41 +08:00
|
|
|
symtab->addDSOHandle(in.header);
|
2020-04-22 04:37:57 +08:00
|
|
|
|
2020-08-11 09:47:13 +08:00
|
|
|
for (opt::Arg *arg : args.filtered(OPT_sectcreate)) {
|
|
|
|
StringRef segName = arg->getValue(0);
|
|
|
|
StringRef sectName = arg->getValue(1);
|
|
|
|
StringRef fileName = arg->getValue(2);
|
|
|
|
Optional<MemoryBufferRef> buffer = readFile(fileName);
|
|
|
|
if (buffer)
|
2020-12-15 06:59:22 +08:00
|
|
|
inputFiles.insert(make<OpaqueFile>(*buffer, segName, sectName));
|
2020-08-11 09:47:13 +08:00
|
|
|
}
|
|
|
|
|
2020-04-03 02:54:05 +08:00
|
|
|
// Initialize InputSections.
|
[lld-macho][re-land] Support .subsections_via_symbols
Summary:
This diff restores and builds upon @pcc and @ruiu's initial work on
subsections.
The .subsections_via_symbols directive indicates we can split each
section along symbol boundaries, unless those symbols have been marked
with `.alt_entry`.
We exercise this functionality in our tests by using order files that
rearrange those symbols.
Depends on D79668.
Reviewers: ruiu, pcc, MaskRay, smeenai, alexshap, gkm, Ktwu, christylee
Reviewed By: smeenai
Subscribers: thakis, llvm-commits, pcc, ruiu
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D79926
2020-05-19 23:46:07 +08:00
|
|
|
for (InputFile *file : inputFiles) {
|
|
|
|
for (SubsectionMap &map : file->subsections) {
|
|
|
|
for (auto &p : map) {
|
|
|
|
InputSection *isec = p.second;
|
|
|
|
inputSections.push_back(isec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-03 02:54:05 +08:00
|
|
|
|
|
|
|
// Write to an output file.
|
|
|
|
writeResult();
|
|
|
|
|
|
|
|
if (canExitEarly)
|
|
|
|
exitLld(errorCount() ? 1 : 0);
|
|
|
|
|
|
|
|
return !errorCount();
|
|
|
|
}
|