<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - [ThinLTO] linkonce_odr function is incorrectly not discarded from global_ctors"
   href="https://bugs.llvm.org/show_bug.cgi?id=51067">51067</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>[ThinLTO] linkonce_odr function is incorrectly not discarded from global_ctors
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>lld
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>12.0
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>ELF
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>jbc.engelen@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org, smithp352@googlemail.com
          </td>
        </tr></table>
      <p>
        <div>
        <pre>With LDC, we want to emit a global ctor function that is only called once for
each DSO. We do this by emitting it as "linkonce_odr" in every IR module,
adding it to global_ctors, are relying on LangRef "If the third field is
non-null, and points to a global variable or function, the initializer function
will only run if the associated data from the current module is not discarded."
to discard it from global_ctors when it is merged with the identical function
in other IR modules.
This works across several linkers, also works with LLD, but does not work with
LLD+ThinLTO.


Reproducing test case:

Our main file that defines a ctor, linkonce_odr, and adds it to the
global_ctors list, referencing itself as "data". This means that when the ctor
is discarded, the global_ctors entry should also be discarded.
```
; File: main.ll
target datalayout =
"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@str.ctor = private unnamed_addr constant [6 x i8] c"ctor\0A\00"
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void
()*, i8* } { i32 65535, void ()* @module_ctor, i8* bitcast (void ()*
@module_ctor to i8*) }]

declare i32 @printf(i8*, ...)

define linkonce_odr hidden void @module_ctor() {
  %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x
i8]* @str.ctor, i64 0, i64 0))
  ret void
}

define i32 @main(i32 %argc_arg, i8** %argv_arg) {
  ret i32 0
}
```

A second file that defines the _same_ ctor function, linkonce_odr. We compile
this file directly to object code, not to bitcode (i.e. no LTO capability on
this file). This file also adds the ctor to global_ctors list, again
referencing itself as "data". LangRef: "If the third field is non-null, and
points to a global variable or function, the initializer function will only run
if the associated data from the current module is not discarded.".
```
; File: second_object.ll
target datalayout =
"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@str.ctor = private unnamed_addr constant [6 x i8] c"ctor\0A\00"
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void
()*, i8* } { i32 65535, void ()* @module_ctor, i8* bitcast (void ()*
@module_ctor to i8*) }]

declare i32 @printf(i8*, ...)

define linkonce_odr hidden void @module_ctor() {
  %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x
i8]* @str.ctor, i64 0, i64 0))
  ret void
}
```

Script file to build and reproduce:
```
# File: script.sh
LLC=/home/johan/llvm/install12/bin/llc
OPT=/home/johan/llvm/install12/bin/opt
LLVMgold=/home/johan/llvm/install12/lib/LLVMgold.so

$LLC second_object.ll -O3 --relocation-model=pic -filetype=obj -o
second_object.o
$LLC main.ll -O3 --relocation-model=pic -filetype=obj -o main.o
cc main.o second_object.o -fuse-ld=gold -o bug_gold
cc main.o second_object.o -fuse-ld=lld -o bug_lld

$OPT main.ll -O3 -o main_thinlto.o
cc main_thinlto.o second_object.o -o bug_thinlto_gold -fuse-ld=gold
-Wl,-plugin,$LLVMgold -Wl,-plugin-opt=thinlto
-Wl,-plugin-opt=-function-sections -Wl,-plugin-opt=-data-sections

$OPT main.ll -O3 -o main_thinlto.o
cc main_thinlto.o second_object.o -o bug_thinlto_lld -fuse-ld=lld
#-Wl,-plugin,$LLVMgold -Wl,-plugin-opt=thinlto
-Wl,-plugin-opt=-function-sections -Wl,-plugin-opt=-data-sections

echo "bug_gold:"
./bug_gold
echo "bug_lld:"
./bug_lld
echo "bug_thinlto_gold:"
./bug_thinlto_gold
echo "bug_thinlto_lld:"
./bug_thinlto_lld
```

Output:
```
❯ ./script.sh
bug_gold:
ctor
bug_lld:
ctor
bug_thinlto_gold:
ctor
bug_thinlto_lld:
ctor
ctor
```

The double "ctor" at the end for bug_thinlto_lld is the bug.
Tested with LLVM 12.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>