Index: llvm/include/llvm-c/lto.h =================================================================== --- llvm/include/llvm-c/lto.h +++ llvm/include/llvm-c/lto.h @@ -46,7 +46,7 @@ * @{ */ -#define LTO_API_VERSION 28 +#define LTO_API_VERSION 29 /** * \since prior to LTO_API_VERSION=3 @@ -312,6 +312,16 @@ unsigned int *out_cputype, unsigned int *out_cpusubtype); +/** + * This function can be used by the linker to check if a given module has + * any constructor or destructor functions. + * + * Returns true if the module has either the @llvm.global_ctors or the + * @llvm.global_dtors symbol. Otherwise returns false. + * + * \since LTO_API_VERSION=29 + */ +extern lto_bool_t lto_module_has_ctor_dtor(lto_module_t mod); /** * Diagnostic severity. * Index: llvm/include/llvm/LTO/legacy/LTOModule.h =================================================================== --- llvm/include/llvm/LTO/legacy/LTOModule.h +++ llvm/include/llvm/LTO/legacy/LTOModule.h @@ -167,6 +167,10 @@ Expected getMachOCPUSubType() const; + /// Returns true if the module has either the @llvm.global_ctors or the + /// @llvm.global_dtors symbol. Otherwise returns false. + bool hasCtorDtor() const; + private: /// Parse metadata from the module // FIXME: it only parses "llvm.linker.options" metadata at the moment Index: llvm/lib/LTO/LTOModule.cpp =================================================================== --- llvm/lib/LTO/LTOModule.cpp +++ llvm/lib/LTO/LTOModule.cpp @@ -688,3 +688,16 @@ Expected LTOModule::getMachOCPUSubType() const { return MachO::getCPUSubType(Triple(Mod->getTargetTriple())); } + +bool LTOModule::hasCtorDtor() const { + for (auto Sym : SymTab.symbols()) { + if (auto *GV = Sym.dyn_cast()) { + StringRef Name = GV->getName(); + if (Name.consume_front("llvm.global_")) { + if (Name.equals("ctors") || Name.equals("dtors")) + return true; + } + } + } + return false; +} Index: llvm/test/tools/llvm-lto/ltomodule.ll =================================================================== --- /dev/null +++ llvm/test/tools/llvm-lto/ltomodule.ll @@ -0,0 +1,35 @@ +# RUN: rm -rf %t && split-file %s %t + +; RUN: llvm-as < %t/hasCtor.ll > %t.bc +; RUN: llvm-lto %t.bc -query-hasCtorDtor | FileCheck %s --check-prefixes=POSITIVE + +; RUN: llvm-as < %t/hasDtor.ll > %t.bc +; RUN: llvm-lto %t.bc -query-hasCtorDtor | FileCheck %s --check-prefixes=POSITIVE + +; RUN: llvm-as < %t/hasBoth.ll > %t.bc +; RUN: llvm-lto %t.bc -query-hasCtorDtor | FileCheck %s --check-prefixes=POSITIVE + +; RUN: llvm-as < %t/hasNone.ll > %t.bc +; RUN: llvm-lto %t.bc -query-hasCtorDtor | FileCheck %s --check-prefixes=NEGATIVE + +; POSITIVE: .bc: hasCtorDtor = true +; NEGATIVE: .bc: hasCtorDtor = false + +;--- hasCtor.ll +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @constructor, i8* null }] +declare void @constructor() + +;--- hasDtor.ll +@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @destructor, i8* null }] +declare void @destructor() + +;--- hasBoth.ll +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @constructor, i8* null }] +@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @destructor, i8* null }] +declare void @constructor() +declare void @destructor() + +;--- hasNone.ll +declare void @foo() + + Index: llvm/tools/llvm-lto/llvm-lto.cpp =================================================================== --- llvm/tools/llvm-lto/llvm-lto.cpp +++ llvm/tools/llvm-lto/llvm-lto.cpp @@ -227,6 +227,10 @@ "Instead of running LTO, list the dependent libraries in each IR file"), cl::cat(LTOCategory)); +static cl::opt QueryHasCtorDtor( + "query-hasCtorDtor", cl::init(false), + cl::desc("Queries LTOModule::hasCtorDtor() on each IR file")); + static cl::opt SetMergedModule("set-merged-module", cl::init(false), cl::desc("Use the first input module as the merged module"), @@ -394,22 +398,27 @@ } } -/// List symbols in each IR file. +/// Load each IR file and dump certain information based on active flags. /// /// The main point here is to provide lit-testable coverage for the LTOModule -/// functionality that's exposed by the C API to list symbols. Moreover, this -/// provides testing coverage for modules that have been created in their own -/// contexts. -static void listSymbols(const TargetOptions &Options) { +/// functionality that's exposed by the C API. Moreover, this provides testing +/// coverage for modules that have been created in their own contexts. +static void testLTOModule(const TargetOptions &Options) { for (auto &Filename : InputFilenames) { std::unique_ptr Buffer; std::unique_ptr Module = getLocalLTOModule(Filename, Buffer, Options); - // List the symbols. - outs() << Filename << ":\n"; - for (int I = 0, E = Module->getSymbolCount(); I != E; ++I) - outs() << Module->getSymbolName(I) << "\n"; + if (ListSymbolsOnly) { + // List the symbols. + outs() << Filename << ":\n"; + for (int I = 0, E = Module->getSymbolCount(); I != E; ++I) + outs() << Module->getSymbolName(I) << "\n"; + } + if (QueryHasCtorDtor) + outs() << Filename + << ": hasCtorDtor = " << (Module->hasCtorDtor() ? "true" : "false") + << "\n"; } } @@ -939,8 +948,8 @@ // set up the TargetOptions for the machine TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple()); - if (ListSymbolsOnly) { - listSymbols(Options); + if (ListSymbolsOnly || QueryHasCtorDtor) { + testLTOModule(Options); return 0; } Index: llvm/tools/lto/lto.cpp =================================================================== --- llvm/tools/lto/lto.cpp +++ llvm/tools/lto/lto.cpp @@ -511,6 +511,10 @@ unwrap(cg)->setShouldEmbedUselists(ShouldEmbedUselists); } +lto_bool_t lto_module_has_ctor_dtor(lto_module_t mod) { + return unwrap(mod)->hasCtorDtor(); +} + // ThinLTO API below thinlto_code_gen_t thinlto_create_codegen(void) { Index: llvm/tools/lto/lto.exports =================================================================== --- llvm/tools/lto/lto.exports +++ llvm/tools/lto/lto.exports @@ -8,6 +8,7 @@ lto_module_create_from_memory_with_path lto_module_create_in_local_context lto_module_create_in_codegen_context +lto_module_has_ctor_dtor lto_module_get_linkeropts lto_module_get_macho_cputype lto_module_get_num_symbols