diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -779,7 +779,41 @@ } } +static macho::Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &objSym, + BitcodeFile &file) { + StringRef name = saver.save(objSym.getName()); + + // TODO: support weak references + if (objSym.isUndefined()) + return symtab->addUndefined(name, &file, /*isWeakRef=*/false); + + assert(!objSym.isCommon() && "TODO: support common symbols in LTO"); + + // TODO: Write a test demonstrating why computing isPrivateExtern before + // LTO compilation is important. + bool isPrivateExtern = false; + switch (objSym.getVisibility()) { + case GlobalValue::HiddenVisibility: + isPrivateExtern = true; + break; + case GlobalValue::ProtectedVisibility: + error(name + " has protected visibility, which is not supported by Mach-O"); + break; + case GlobalValue::DefaultVisibility: + break; + } + + return symtab->addDefined(name, &file, /*isec=*/nullptr, /*value=*/0, + objSym.isWeak(), isPrivateExtern); +} + BitcodeFile::BitcodeFile(MemoryBufferRef mbref) : InputFile(BitcodeKind, mbref) { obj = check(lto::InputFile::create(mbref)); + + // Convert LTO Symbols to LLD Symbols in order to perform resolution. The + // "winning" symbol will then be marked as Prevailing at LTO compilation + // time. + for (const lto::InputFile::Symbol &objSym : obj->symbols()) + symbols.push_back(createBitcodeSymbol(objSym, *this)); } diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp --- a/lld/MachO/LTO.cpp +++ b/lld/MachO/LTO.cpp @@ -10,6 +10,7 @@ #include "Config.h" #include "Driver.h" #include "InputFiles.h" +#include "Symbols.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Strings.h" @@ -50,16 +51,24 @@ resols.reserve(objSyms.size()); // Provide a resolution to the LTO API for each symbol. + auto symIt = f.symbols.begin(); for (const lto::InputFile::Symbol &objSym : objSyms) { resols.emplace_back(); lto::SymbolResolution &r = resols.back(); + Symbol *sym = *symIt++; // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile // reports two symbols for module ASM defined. Without this check, lld // flags an undefined in IR with a definition in ASM as prevailing. // Once IRObjectFile is fixed to report only one symbol this hack can // be removed. - r.Prevailing = !objSym.isUndefined(); + r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f; + + // Un-define the symbol so that we don't get duplicate symbol errors when we + // load the ObjFile emitted by LTO compilation. + if (r.Prevailing) + replaceSymbol(sym, sym->getName(), sym->getFile(), + RefState::Strong); // TODO: set the other resolution configs properly r.VisibleToRegularObj = true; diff --git a/lld/test/MachO/invalid/duplicate-symbol.ll b/lld/test/MachO/invalid/duplicate-symbol.ll new file mode 100644 --- /dev/null +++ b/lld/test/MachO/invalid/duplicate-symbol.ll @@ -0,0 +1,15 @@ +; REQUIRES: x86 +; RUN: rm -rf %t; mkdir -p %t +; RUN: opt -module-summary %s -o %t/first.o +; RUN: opt -module-summary %s -o %t/second.o +; RUN: not %lld -dylib -lSystem %t/first.o %t/second.o -o /dev/null 2>&1 | FileCheck %s +; CHECK: error: duplicate symbol: _foo +; CHECK-NEXT: >>> defined in {{.*}}/first.o +; CHECK-NEXT: >>> defined in {{.*}}/second.o + +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 +} diff --git a/lld/test/MachO/invalid/protected.ll b/lld/test/MachO/invalid/protected.ll new file mode 100644 --- /dev/null +++ b/lld/test/MachO/invalid/protected.ll @@ -0,0 +1,11 @@ +; REQUIRES: x86 +; RUN: opt -module-summary %s -o %t.o +; RUN: not %lld -dylib -lSystem %t.o -o /dev/null 2>&1 | FileCheck %s +; CHECK: error: _foo has protected visibility, which is not supported by Mach-O + +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 protected void @foo() { + ret void +} diff --git a/lld/test/MachO/linkonce.ll b/lld/test/MachO/linkonce.ll new file mode 100644 --- /dev/null +++ b/lld/test/MachO/linkonce.ll @@ -0,0 +1,29 @@ +; REQUIRES: x86 +; RUN: rm -rf %t; split-file %s %t +; RUN: opt -module-summary %t/first.ll -o %t/first.o +; RUN: opt -module-summary %t/second.ll -o %t/second.o +; RUN: %lld -dylib -lSystem %t/first.o %t/second.o -o %t/12 +; RUN: llvm-objdump --syms %t/12 | FileCheck %s --check-prefix=FIRST +; RUN: %lld -dylib -lSystem %t/second.o %t/first.o -o %t/21 +; RUN: llvm-objdump --syms %t/21 | FileCheck %s --check-prefix=SECOND + +; FIRST: w O __TEXT,first _foo +; SECOND: w O __TEXT,second _foo + +#--- first.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 linkonce void @foo() section "__TEXT,first" { + ret void +} + +#--- second.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 linkonce void @foo() section "__TEXT,second" { + ret void +}