diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1135,6 +1135,52 @@ symtab->addUndefined("dyld_stub_binder", /*file=*/nullptr, /*isWeak=*/false); } +static void createAliases() { + for (const auto &pair : config->aliasedSymbols) { + if (const auto &sym = symtab->find(pair.first)) { + if (const auto &defined = dyn_cast(sym)) { + symtab->aliasDefined(defined, pair.second); + continue; + } + } + + warn("undefined base symbol '" + pair.first + "' for alias '" + + pair.second + "'\n"); + } +} + +static void handleExplicitExports() { + if (config->hasExplicitExports) { + parallelForEach(symtab->getSymbols(), [](Symbol *sym) { + if (auto *defined = dyn_cast(sym)) { + StringRef symbolName = defined->getName(); + if (config->exportedSymbols.match(symbolName)) { + if (defined->privateExtern) { + if (defined->weakDefCanBeHidden) { + // weak_def_can_be_hidden symbols behave similarly to + // private_extern symbols in most cases, except for when + // it is explicitly exported. + // The former can be exported but the latter cannot. + defined->privateExtern = false; + } else { + warn("cannot export hidden symbol " + toString(*defined) + + "\n>>> defined in " + toString(defined->getFile())); + } + } + } else { + defined->privateExtern = true; + } + } + }); + } else if (!config->unexportedSymbols.empty()) { + parallelForEach(symtab->getSymbols(), [](Symbol *sym) { + if (auto *defined = dyn_cast(sym)) + if (config->unexportedSymbols.match(defined->getName())) + defined->privateExtern = true; + }); + } +} + bool macho::link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) { @@ -1583,6 +1629,12 @@ for (const Arg *arg : args.filtered(OPT_mllvm)) parseClangOption(arg->getValue(), arg->getSpelling()); + createSyntheticSections(); + createSyntheticSymbols(); + + createAliases(); + handleExplicitExports(); + compileBitcodeFiles(); replaceCommonSymbols(); @@ -1595,51 +1647,6 @@ // FIXME: should terminate the link early based on errors encountered so // far? - createSyntheticSections(); - createSyntheticSymbols(); - - for (const auto &pair : config->aliasedSymbols) { - if (const auto &sym = symtab->find(pair.first)) { - if (const auto &defined = dyn_cast(sym)) { - symtab->aliasDefined(defined, pair.second); - continue; - } - } - - warn("undefined base symbol '" + pair.first + "' for alias '" + - pair.second + "'\n"); - } - - if (config->hasExplicitExports) { - parallelForEach(symtab->getSymbols(), [](Symbol *sym) { - if (auto *defined = dyn_cast(sym)) { - StringRef symbolName = defined->getName(); - if (config->exportedSymbols.match(symbolName)) { - if (defined->privateExtern) { - if (defined->weakDefCanBeHidden) { - // weak_def_can_be_hidden symbols behave similarly to - // private_extern symbols in most cases, except for when - // it is explicitly exported. - // The former can be exported but the latter cannot. - defined->privateExtern = false; - } else { - warn("cannot export hidden symbol " + toString(*defined) + - "\n>>> defined in " + toString(defined->getFile())); - } - } - } else { - defined->privateExtern = true; - } - } - }); - } else if (!config->unexportedSymbols.empty()) { - parallelForEach(symtab->getSymbols(), [](Symbol *sym) { - if (auto *defined = dyn_cast(sym)) - if (config->unexportedSymbols.match(defined->getName())) - defined->privateExtern = true; - }); - } - for (const Arg *arg : args.filtered(OPT_sectcreate)) { StringRef segName = arg->getValue(0); StringRef sectName = arg->getValue(1); diff --git a/lld/test/MachO/lto-exported-symbol.ll b/lld/test/MachO/lto-exported-symbol.ll new file mode 100644 --- /dev/null +++ b/lld/test/MachO/lto-exported-symbol.ll @@ -0,0 +1,25 @@ +; REQUIRES: x86 +; RUN: rm -rf %t; split-file %s %t +; RUN: llvm-as %t/test.ll -o %t/test.o +; RUN: %lld -lSystem -dylib %t/test.o -o %t/test -exported_symbol _foo -save-temps +; RUN: llvm-dis %t/test.0.2.internalize.bc -o - | FileCheck %s + +;; Check that `-exported_symbol` causes all non-exported symbols to be marked +;; as hidden before LTO. We don't want to downgrade them to private extern only +;; after LTO runs as that likely results in LTO has missing optimization +;; opportunities. +; CHECK: define dso_local void @foo() +; CHECK: define internal void @bar() + +;--- test.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" + +define void @foo() { + ret void +} + +define void @bar() { + ret void +}