diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1055,6 +1055,12 @@ }); } +static const char *libcallRoutineNames[] = { +#define HANDLE_LIBCALL(code, name) name, +#include "llvm/IR/RuntimeLibcalls.def" +#undef HANDLE_LIBCALL +}; + void LinkerDriver::link(ArrayRef argsArr) { // Needed for LTO. InitializeAllTargetInfos(); @@ -1762,6 +1768,12 @@ addUndefined(mangle("_load_config_used")); } while (run()); + if (!BitcodeFile::instances.empty()) { + for (const char *s : libcallRoutineNames) + symtab->addLibcall(mangle(s)); + run(); + } + if (args.hasArg(OPT_include_optional)) { // Handle /includeoptional for (auto *arg : args.filtered(OPT_include_optional)) diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h --- a/lld/COFF/SymbolTable.h +++ b/lld/COFF/SymbolTable.h @@ -100,6 +100,7 @@ Symbol *addImportData(StringRef n, ImportFile *f); Symbol *addImportThunk(StringRef name, DefinedImportData *s, uint16_t machine); + void addLibcall(StringRef name); void reportDuplicate(Symbol *existing, InputFile *newFile); diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -584,6 +584,17 @@ return nullptr; } +void SymbolTable::addLibcall(StringRef name) { + Symbol *sym = find(name); + if (!sym) + sym = findUnderscore(name); + if (!sym) + return; + + if (Lazy *l = dyn_cast(sym)) + addUndefined(sym->getName()); +} + std::vector SymbolTable::getChunks() { std::vector res; for (ObjFile *file : ObjFile::instances) { diff --git a/lld/test/COFF/Inputs/libcall-archive.ll b/lld/test/COFF/Inputs/libcall-archive.ll new file mode 100644 --- /dev/null +++ b/lld/test/COFF/Inputs/libcall-archive.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-unknown-windows" + +define void @memcpy() { + ret void +} diff --git a/lld/test/COFF/Inputs/libcall-archive.s b/lld/test/COFF/Inputs/libcall-archive.s new file mode 100644 --- /dev/null +++ b/lld/test/COFF/Inputs/libcall-archive.s @@ -0,0 +1,2 @@ +.globl __sync_val_compare_and_swap_8 +__sync_val_compare_and_swap_8: diff --git a/lld/test/COFF/libcall-archive.ll b/lld/test/COFF/libcall-archive.ll new file mode 100644 --- /dev/null +++ b/lld/test/COFF/libcall-archive.ll @@ -0,0 +1,23 @@ +; REQUIRES: x86 +; RUN: rm -f %t.a +; RUN: llvm-as -o %t.obj %s +; RUN: llvm-as -o %t2.obj %S/Inputs/libcall-archive.ll +; RUN: llvm-mc -filetype=obj -triple=i686-unknown-windows -o %t3.obj %S/Inputs/libcall-archive.s +; RUN: llvm-ar rcs %t.a %t2.obj %t3.obj +; RUN: lld-link -out:%t.exe -subsystem:console -entry:start -lldsavetemps -safeseh:no %t.obj %t.a +; RUN: llvm-nm %t.exe.lto.obj | FileCheck %s + +; CHECK-NOT: T __sync_val_compare_and_swap_8 +; CHECK: T _memcpy +; CHECK: T _start + +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-unknown-windows" + +define void @start(i8* %a, i8* %b) { +entry: + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %b, i64 1024, i1 false) + ret void +} + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1)