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

Reply via email to