forked from OSchip/llvm-project
[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
This commit is contained in:
parent
0519e1ddb3
commit
16b1f6e385
|
@ -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;
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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>{
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue