diff options
author | Nico Weber <thakis@chromium.org> | 2020-12-03 16:40:04 -0500 |
---|---|---|
committer | Nico Weber <thakis@chromium.org> | 2020-12-04 08:46:53 -0500 |
commit | 16b1f6e3858b7082ae9f8eea65aff8a04c692099 (patch) | |
tree | a42c450c8fa061a2b4bb7bf078621399b788ed06 /lld/MachO | |
parent | 0519e1ddb3885d070f054ca30a7487f915f6f795 (diff) | |
download | llvm-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.cpp | 77 | ||||
-rw-r--r-- | lld/MachO/Driver.h | 2 | ||||
-rw-r--r-- | lld/MachO/InputFiles.cpp | 7 |
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>{ |