Issue |
128644
|
Summary |
powerpc: clang build with -fPIC corrupts link stack
|
Labels |
clang
|
Assignees |
|
Reporter |
chleroy
|
Explanation copied from linux kernel commit c974809a26a1 ("powerpc/vdso: Avoid link stack corruption in __get_datapage()"):
_powerpc has a link register (lr) used for calling functions. We "bl
<func>" to call a function, and "blr" to return back to the call site._
_The lr is only a single register, so if we call another function from
inside this function (ie. nested calls), software must save away the
lr on the software stack before calling the new function. Before
returning (ie. before the "blr"), the lr is restored by software from
the software stack._
_This makes branch prediction quite difficult for the processor as it
will only know the branch target just before the "blr"._
_To help with this, modern powerpc processors keep a (non-architected)
hardware stack of lr called a "link stack". When a "bl <func>" is
run, the lr is pushed onto this stack. When a "blr" is called, the
branch predictor pops the lr value from the top of the link stack, and
uses it to predict the branch target. Hence the processor pipeline
knows a lot earlier the branch target._
_This works great but there are some cases where you call "bl" but
without a matching "blr". Once such case is when trying to determine
the program counter (which can't be read directly). Here you "bl+4;
mflr" to get the program counter. If you do this, the link stack will
get out of sync with reality, causing the branch predictor to
mis-predict subsequent function returns._
_To avoid this, modern micro-architectures have a special case of bl.
Using the form "bcl 20,31,+4", ensures the processor doesn't push to
the link stack._
Lets take the following test function:
```
char val;
char test(void)
{
return val;
}
```
When built with GCC (ppc-linux-gcc -O2 -fPIC -c test.c), we get:
```
00000004 <test>:
4: 94 21 ff f0 stwu r1,-16(r1)
8: 7c 08 02 a6 mflr r0
c: 42 9f 00 05 bcl 20,4*cr7+so,10 <test+0xc> <== bcl 20,31,.+4
10: 93 c1 00 08 stw r30,8(r1)
14: 7f c8 02 a6 mflr r30
18: 90 01 00 14 stw r0,20(r1)
1c: 80 1e ff f0 lwz r0,-16(r30)
20: 7f c0 f2 14 add r30,r0,r30
24: 81 3e 80 00 lwz r9,-32768(r30)
28: 80 01 00 14 lwz r0,20(r1)
2c: 88 69 00 00 lbz r3,0(r9)
30: 83 c1 00 08 lwz r30,8(r1)
34: 7c 08 03 a6 mtlr r0
38: 38 21 00 10 addi r1,r1,16
3c: 4e 80 00 20 blr
```
But when building with clang (clang --target=ppc-linux -O2 -fPIC -c test.c), we get:
```
00000004 <test>:
4: 7c 08 02 a6 mflr r0
8: 94 21 ff f0 stwu r1,-16(r1)
c: 93 c1 00 08 stw r30,8(r1)
10: 90 01 00 14 stw r0,20(r1)
14: 48 00 00 05 bl 18 <test+0x14> <== bl .+4
18: 7f c8 02 a6 mflr r30
1c: 80 7e ff e8 lwz r3,-24(r30)
20: 7f c3 f2 14 add r30,r3,r30
24: 80 7e 80 00 lwz r3,-32768(r30)
28: 88 63 00 00 lbz r3,0(r3)
2c: 80 01 00 14 lwz r0,20(r1)
30: 83 c1 00 08 lwz r30,8(r1)
34: 38 21 00 10 addi r1,r1,16
38: 7c 08 03 a6 mtlr r0
3c: 4e 80 00 20 blr
```
As you can see, gcc uses the expected special form `bcl 20,31,+.4` but clang uses `bl .+4` instead hence corrupting the link stack.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs