llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.42k stars 11.74k forks source link

Potential bad code generation with TLS and PowerPC #23482

Closed llvmbot closed 8 years ago

llvmbot commented 9 years ago
Bugzilla Link 23108
Resolution FIXED
Resolved on Oct 15, 2015 09:27
Version 3.5
OS Linux
Reporter LLVM Bugzilla Contributor
CC @hfinkel

Extended Description

Hello,

I have discovered a potential inconsistency with LLVM and TLS code generation for PowerPC, specifically Power8.

This test program exists as two object files, test.o which references an external TLS variable "y", which belongs to test_a.o. These two .o files are linked together to create my test application. I am not compiling this example with -relocation-model=pic

The variable in question, "y", is located in the initialized data section of the resulting executable. Now, on to my issue:

I have an external TLS integer variable, "y" which is declared as the following from my test.c source file. @​y = external thread_local global i32 ,section ".comm" , align 4

When my code first tries to access this external variable, my compiler emits the following code sequence in llvm to access and then add the value of another int to 'y': Build: llc ./test.ll -mcpu=native -o ./test.s Result: %41 = load i32* @​y, align 4, !dbg !​20 ... %57 = add i32 %41, %56, !dbg !​20

This generates the following asm: Build: /usr/bin/as ./test.s -mpower8 -o test.o Result: ld 0, y@got@tprel@l(6) addis 7, 2, x@got@tprel@ha lwz 30, -120(1)
lwz 29, -116(1) add 28, 0, y@tls
lwz 0, -96(1) lwz 28, 0(28) ld 27, x@got@tprel@l(7) lwz 26, -76(1) lwz 25, -80(1)
lwz 24, -84(1) lwz 23, -88(1) add 26, 26, 25

Since GNU-ld can manipulate TLS instructions (for optimization purposes) the following is the resulting object code after linking: <+360>: addis r7,r13,0 <+364>: lwz r8,-112(r1) <+368>: lwz r11,-124(r1) <+372>: addi r7,r7,-28664 <+376>: lwz r12,0(r7) <+380>: addis r0,r13,0 <+384>: nop <+388>: lwz r30,-120(r1) <+392>: lwz r29,-116(r1) <+396>: li r28,-28668 <+400>: lwz r0,-96(r1) <+404>: lwz r28,0(r28)

What concerns me, and is causing a segfault is offset +396 to +400.
The linker transforms the asm to object code: add 28, 0, y@tls transformed--> li r28,-28668

The following lwz at +404 in the object code will try to load r28 (which is a negative value/not-an-address). This segfaults my application.

Looking at the Power8 ABI for TLS and the specific "add 28, 0, y@tls" instruction. 1) This appears to be the following relocation: R_PPC64_TLS (y + 0) 2) The Power8 ABI specifies that the "add" and "r9" registers are to be used. It is not clear to me if the explicit register values as noted in the ABI have to be used, but it would seem that way.

I have noticed there appears to be a clobber of a register if I specify PIC compilation.

So is there a code generation fault on behalf of LLVM, or is there something I have missed?

llvmbot commented 8 years ago

Closing as a duplicate of a resolved issue, but I couldn't find a bugzilla number for the TLS problem.

llvmbot commented 9 years ago

No, it's not the same problem. The previous issue was with the linker. What Hal fixed was a problem in LLVM itself.

Bill

llvmbot commented 9 years ago

Yes, the linker was assuming the original load of the TLS address was into G#3 , even when it wasn't, which led to some surprising situations when it performed the optimization. With LLVM 3.6 we avoid generating code that will cause trouble with an unpatched linker. The linker has been fixed upstream, but it takes time for fixes to propagate to distributions...

Hi Bill,

Hal put in this fix much more recently to 3.7.x: https://github.com/llvm-mirror/llvm/commit/0977a23c2a0cbc9ca661f7d694ade420edbd7dde

Does this happen to also address the same problem with no-tls-optimize? I ask this mainly because I am curious, because it seems that Hal's fix also removes the use of a hard-coded G#3 .

llvmbot commented 9 years ago

Yes, the linker was assuming the original load of the TLS address was into G#3 , even when it wasn't, which led to some surprising situations when it performed the optimization. With LLVM 3.6 we avoid generating code that will cause trouble with an unpatched linker. The linker has been fixed upstream, but it takes time for fixes to propagate to distributions...

Thanks for this information!

llvmbot commented 9 years ago

Yes, the linker was assuming the original load of the TLS address was into G#3 , even when it wasn't, which led to some surprising situations when it performed the optimization. With LLVM 3.6 we avoid generating code that will cause trouble with an unpatched linker. The linker has been fixed upstream, but it takes time for fixes to propagate to distributions...

llvmbot commented 9 years ago

Thanks a ton Hal, that trick does work.

hfinkel commented 9 years ago

There was a TLS linker bug that LLVM now works around (but not version 3.5, that's too old). Bill knows the details, I'll let him comment.

Try passing -Wl,--no-tls-optimize and see if that fixes things.