[llvm-branch-commits] [lld] 16b1f6e - [mac/lld] Add support for the LC_LINKER_OPTION load command in o files
Nico Weber via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Dec 4 05:54:34 PST 2020
Author: Nico Weber
Date: 2020-12-04T08:46:53-05:00
New Revision: 16b1f6e3858b7082ae9f8eea65aff8a04c692099
URL: https://github.com/llvm/llvm-project/commit/16b1f6e3858b7082ae9f8eea65aff8a04c692099
DIFF: https://github.com/llvm/llvm-project/commit/16b1f6e3858b7082ae9f8eea65aff8a04c692099.diff
LOG: [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
Added:
lld/test/MachO/lc-linker-option.ll
Modified:
lld/MachO/Driver.cpp
lld/MachO/Driver.h
lld/MachO/InputFiles.cpp
Removed:
################################################################################
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>{
diff --git a/lld/test/MachO/lc-linker-option.ll b/lld/test/MachO/lc-linker-option.ll
new file mode 100644
index 000000000000..f3ad60d946f2
--- /dev/null
+++ b/lld/test/MachO/lc-linker-option.ll
@@ -0,0 +1,55 @@
+# REQUIRES: x86
+# RUN: rm -rf %t
+# RUN: split-file %s %t
+
+# RUN: llvm-as %t/framework.ll -o %t/framework.o
+# RUN: %lld %t/framework.o -o %t/frame
+# RUN: llvm-objdump --macho --all-headers %t/frame | FileCheck --check-prefix=FRAME %s
+# FRAME: cmd LC_LOAD_DYLIB
+# FRAME-NEXT: cmdsize
+# FRAME-NEXT: name /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
+
+# RUN: llvm-as %t/l.ll -o %t/l.o
+# RUN: %lld %t/l.o -o %t/l
+# RUN: llvm-objdump --macho --all-headers %t/l | FileCheck --check-prefix=LIB %s
+# LIB: cmd LC_LOAD_DYLIB
+# LIB-NEXT: cmdsize
+# LIB-NEXT: name /usr/lib/libSystem.B.dylib
+
+# RUN: llvm-as %t/invalid.ll -o %t/invalid.o
+# RUN: not %lld %t/invalid.o -o /dev/null 2>&1 | FileCheck --check-prefix=INVALID %s
+# INVALID: error: -why_load is not allowed in LC_LINKER_OPTION
+
+#--- framework.ll
+target triple = "x86_64-apple-macosx10.15.0"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+!0 = !{!"-framework", !"CoreFoundation"}
+!llvm.linker.options = !{!0}
+
+define void @main() {
+ ret void
+}
+
+#--- l.ll
+target triple = "x86_64-apple-macosx10.15.0"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+!0 = !{!"-lSystem"}
+!llvm.linker.options = !{!0}
+
+define void @main() {
+ ret void
+}
+
+#--- invalid.ll
+
+target triple = "x86_64-apple-macosx10.15.0"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+!0 = !{!"-why_load"}
+!llvm.linker.options = !{!0}
+
+define void @main() {
+ ret void
+}
More information about the llvm-branch-commits
mailing list