[llvm-bugs] [Bug 51067] New: [ThinLTO] linkonce_odr function is incorrectly not discarded from global_ctors

via llvm-bugs llvm-bugs at lists.llvm.org
Mon Jul 12 11:00:04 PDT 2021


https://bugs.llvm.org/show_bug.cgi?id=51067

            Bug ID: 51067
           Summary: [ThinLTO] linkonce_odr function is incorrectly not
                    discarded from global_ctors
           Product: lld
           Version: 12.0
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: ELF
          Assignee: unassignedbugs at nondot.org
          Reporter: jbc.engelen at gmail.com
                CC: llvm-bugs at lists.llvm.org, smithp352 at googlemail.com

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.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20210712/f2ccd025/attachment.html>


More information about the llvm-bugs mailing list