aboutsummaryrefslogtreecommitdiff
path: root/lld/MachO
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2020-12-03 16:40:04 -0500
committerNico Weber <thakis@chromium.org>2020-12-04 08:46:53 -0500
commit16b1f6e3858b7082ae9f8eea65aff8a04c692099 (patch)
treea42c450c8fa061a2b4bb7bf078621399b788ed06 /lld/MachO
parent0519e1ddb3885d070f054ca30a7487f915f6f795 (diff)
downloadllvm-project-16b1f6e3858b7082ae9f8eea65aff8a04c692099.tar.gz
[mac/lld] Add support for the LC_LINKER_OPTION load command in o files
clang puts `-framework CoreFoundation` in this load command for files that use @available / __builtin_available. Without support for this, binaries that don't explicitly link to CoreFoundation fail to link. Differential Revision: https://reviews.llvm.org/D92624
Diffstat (limited to 'lld/MachO')
-rw-r--r--lld/MachO/Driver.cpp77
-rw-r--r--lld/MachO/Driver.h2
-rw-r--r--lld/MachO/InputFiles.cpp7
3 files changed, 66 insertions, 20 deletions
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index ffd274b33a88..72ef1b28ed58 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -332,6 +332,59 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive) {
return newFile;
}
+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");
+ }
+ }
+}
+
static void addFileList(StringRef path) {
Optional<MemoryBufferRef> buffer = readFile(path);
if (!buffer)
@@ -707,29 +760,13 @@ bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
addFile(arg->getValue(), true);
break;
case OPT_l:
- case OPT_weak_l: {
- StringRef name = arg->getValue();
- if (Optional<std::string> path = findLibrary(name)) {
- auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(*path, false));
- if (opt.getID() == OPT_weak_l && dylibFile)
- dylibFile->forceWeakImport = true;
- break;
- }
- error("library not found for -l" + name);
+ case OPT_weak_l:
+ addLibrary(arg->getValue(), opt.getID() == OPT_weak_l);
break;
- }
case OPT_framework:
- case OPT_weak_framework: {
- StringRef name = arg->getValue();
- if (Optional<std::string> path = findFramework(name)) {
- auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(*path, false));
- if (opt.getID() == OPT_weak_framework && dylibFile)
- dylibFile->forceWeakImport = true;
- break;
- }
- error("framework not found for -framework " + name);
+ case OPT_weak_framework:
+ addFramework(arg->getValue(), opt.getID() == OPT_weak_framework);
break;
- }
case OPT_platform_version:
handlePlatformVersion(arg);
break;
diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h
index d371ee531433..9a6a05af0e0d 100644
--- a/lld/MachO/Driver.h
+++ b/lld/MachO/Driver.h
@@ -36,6 +36,8 @@ enum {
#undef OPTION
};
+void parseLCLinkerOption(InputFile*, unsigned argc, StringRef data);
+
std::string createResponseFile(const llvm::opt::InputArgList &args);
// Check for both libfoo.dylib and libfoo.tbd (in that order).
diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index 0c577bfd0785..1339152901ce 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -383,6 +383,13 @@ ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName)
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
auto *hdr = reinterpret_cast<const mach_header_64 *>(mb.getBufferStart());
+ if (const load_command *cmd = findCommand(hdr, LC_LINKER_OPTION)) {
+ auto *c = reinterpret_cast<const linker_option_command *>(cmd);
+ StringRef data{reinterpret_cast<const char *>(c + 1),
+ c->cmdsize - sizeof(linker_option_command)};
+ parseLCLinkerOption(this, c->count, data);
+ }
+
if (const load_command *cmd = findCommand(hdr, LC_SEGMENT_64)) {
auto *c = reinterpret_cast<const segment_command_64 *>(cmd);
sectionHeaders = ArrayRef<section_64>{