[llvm] 9559bd1 - [LTO][Legacy] Add new API to check presence of ctor/dtor functions.

Wael Yehia via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 28 05:43:09 PDT 2021


Author: Wael Yehia
Date: 2021-07-28T12:41:56Z
New Revision: 9559bd19908bf6421f2abed1578219dacdc49169

URL: https://github.com/llvm/llvm-project/commit/9559bd19908bf6421f2abed1578219dacdc49169
DIFF: https://github.com/llvm/llvm-project/commit/9559bd19908bf6421f2abed1578219dacdc49169.diff

LOG: [LTO][Legacy] Add new API to check presence of ctor/dtor functions.

On AIX, the linker needs to check whether a given lto_module_t contains
any constructor/destructor functions, in order to implement the behavior
of the -bcdtors:all flag. See
https://www.ibm.com/docs/en/aix/7.2?topic=l-ld-command for the flag's
documentation.
In llvm IR, constructor (destructor) functions are added to a special
global array @llvm.global_ctors (@llvm.global_dtors).
However, because these two symbols are artificial, they are not visited
during the symbol traversal (using the
lto_module_get_[num_symbols|symbol_name|symbol_attribute] API).

This patch adds a new function to the libLTO interface that checks the
presence of one or both of these two symbols.

Reviewed By: steven_wu

Differential Revision: https://reviews.llvm.org/D106887

Added: 
    llvm/test/tools/llvm-lto/ltomodule.ll

Modified: 
    llvm/include/llvm-c/lto.h
    llvm/include/llvm/LTO/legacy/LTOModule.h
    llvm/lib/LTO/LTOModule.cpp
    llvm/tools/llvm-lto/llvm-lto.cpp
    llvm/tools/lto/lto.cpp
    llvm/tools/lto/lto.exports

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm-c/lto.h b/llvm/include/llvm-c/lto.h
index f6fc8588f5f71..5ceb02224d2bb 100644
--- a/llvm/include/llvm-c/lto.h
+++ b/llvm/include/llvm-c/lto.h
@@ -46,7 +46,7 @@ typedef bool lto_bool_t;
  * @{
  */
 
-#define LTO_API_VERSION 28
+#define LTO_API_VERSION 29
 
 /**
  * \since prior to LTO_API_VERSION=3
@@ -312,6 +312,16 @@ extern lto_bool_t lto_module_get_macho_cputype(lto_module_t mod,
                                                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.
  *

diff  --git a/llvm/include/llvm/LTO/legacy/LTOModule.h b/llvm/include/llvm/LTO/legacy/LTOModule.h
index 2a25dab58ada3..01e63db4bab3d 100644
--- a/llvm/include/llvm/LTO/legacy/LTOModule.h
+++ b/llvm/include/llvm/LTO/legacy/LTOModule.h
@@ -167,6 +167,10 @@ struct LTOModule {
 
   Expected<uint32_t> 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

diff  --git a/llvm/lib/LTO/LTOModule.cpp b/llvm/lib/LTO/LTOModule.cpp
index 155790041a757..5fbeef501a4fc 100644
--- a/llvm/lib/LTO/LTOModule.cpp
+++ b/llvm/lib/LTO/LTOModule.cpp
@@ -688,3 +688,16 @@ Expected<uint32_t> LTOModule::getMachOCPUType() const {
 Expected<uint32_t> LTOModule::getMachOCPUSubType() const {
   return MachO::getCPUSubType(Triple(Mod->getTargetTriple()));
 }
+
+bool LTOModule::hasCtorDtor() const {
+  for (auto Sym : SymTab.symbols()) {
+    if (auto *GV = Sym.dyn_cast<GlobalValue *>()) {
+      StringRef Name = GV->getName();
+      if (Name.consume_front("llvm.global_")) {
+        if (Name.equals("ctors") || Name.equals("dtors"))
+          return true;
+      }
+    }
+  }
+  return false;
+}

diff  --git a/llvm/test/tools/llvm-lto/ltomodule.ll b/llvm/test/tools/llvm-lto/ltomodule.ll
new file mode 100644
index 0000000000000..fa64ec2d0ce7a
--- /dev/null
+++ b/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
+ at llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @constructor, i8* null }]
+declare void @constructor()
+
+;--- hasDtor.ll
+ at llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @destructor, i8* null }]
+declare void @destructor()
+
+;--- hasBoth.ll
+ at llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @constructor, i8* null }]
+ at 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()
+
+

diff  --git a/llvm/tools/llvm-lto/llvm-lto.cpp b/llvm/tools/llvm-lto/llvm-lto.cpp
index 45bfa84fb826d..183798634a8be 100644
--- a/llvm/tools/llvm-lto/llvm-lto.cpp
+++ b/llvm/tools/llvm-lto/llvm-lto.cpp
@@ -227,6 +227,10 @@ static cl::opt<bool> ListDependentLibrariesOnly(
         "Instead of running LTO, list the dependent libraries in each IR file"),
     cl::cat(LTOCategory));
 
+static cl::opt<bool> QueryHasCtorDtor(
+    "query-hasCtorDtor", cl::init(false),
+    cl::desc("Queries LTOModule::hasCtorDtor() on each IR file"));
+
 static cl::opt<bool>
     SetMergedModule("set-merged-module", cl::init(false),
                     cl::desc("Use the first input module as the merged module"),
@@ -394,22 +398,27 @@ static void printIndexStats() {
   }
 }
 
-/// 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<MemoryBuffer> Buffer;
     std::unique_ptr<LTOModule> 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 @@ int main(int argc, char **argv) {
   // set up the TargetOptions for the machine
   TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());
 
-  if (ListSymbolsOnly) {
-    listSymbols(Options);
+  if (ListSymbolsOnly || QueryHasCtorDtor) {
+    testLTOModule(Options);
     return 0;
   }
 

diff  --git a/llvm/tools/lto/lto.cpp b/llvm/tools/lto/lto.cpp
index 2a560a0d5e83e..dffab5f0facca 100644
--- a/llvm/tools/lto/lto.cpp
+++ b/llvm/tools/lto/lto.cpp
@@ -511,6 +511,10 @@ void lto_codegen_set_should_embed_uselists(lto_code_gen_t cg,
   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) {

diff  --git a/llvm/tools/lto/lto.exports b/llvm/tools/lto/lto.exports
index 1948bba29b67e..3abae5f0fcbaf 100644
--- a/llvm/tools/lto/lto.exports
+++ b/llvm/tools/lto/lto.exports
@@ -8,6 +8,7 @@ lto_module_create_from_memory
 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


        


More information about the llvm-commits mailing list