Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 27 Feb 2016 17:55:02 -0800
From:      Mark Millard <markmi@dsl-only.net>
To:        freebsd-arm <freebsd-arm@freebsd.org>, FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>, FreeBSD Toolchain <freebsd-toolchain@freebsd.org>, Roman Divacky <rdivacky@freebsd.org>, Dimitry Andric <dim@FreeBSD.org>
Subject:   clang 3.8.0 can mess up __builtin_dwarf_cfa (), at least for TARGET_ARCH=armv6, powerpc, powerpc64: a bug 207325 update
Message-ID:  <366B67F9-6A14-4906-8545-1B57A3FF53B8@dsl-only.net>
In-Reply-To: <F23112FF-C417-4757-96FF-4E93C259DC9D@dsl-only.net>
References:  <83B8741C-B4C9-4EFB-A3B4-473F8F165984@dsl-only.net> <80EA4460-E842-46F5-B006-2A83FBBEE845@dsl-only.net> <F23112FF-C417-4757-96FF-4E93C259DC9D@dsl-only.net>

next in thread | previous in thread | raw e-mail | index | archive | help
I discovered on powerpc that __builtin_dwarf_cfa() for clang 3.8.0 and =
g++ do not agree. For powerpc this breaks C++ exception handling (via =
the use in libgcc_s's unwind handling), resulting in uncaught exceptions =
and SEGV's. objdump -d for the two line source file below shows the low =
level differences.

> extern void g(void*);
> void f() { g(__builtin_dwarf_cfa()); }

I've also shown the same issue for powerpc64.

The issue is where g's argument value points relative to f's frame and =
f's caller's frame (since __builtin_dwarf_cfa() is called by f, not g).

And now for armv6 . . .

> # clang++ -c -g -std=3Dc++11 -Wall -pedantic builtin_dwarf_cfa.cpp
> # /usr/local/bin/objdump -d --prefix-addresses builtin_dwarf_cfa.o
>=20
> builtin_dwarf_cfa.o:     file format elf32-littlearm
>=20
>=20
> Disassembly of section .text:
> 00000000 <_Z1fv> push	{fp, lr}
> 00000004 <_Z1fv+0x4> mov	fp, sp
> 00000008 <_Z1fv+0x8> mov	r0, fp
> 0000000c <_Z1fv+0xc> bl	00000000 <_Z1gPv>
> 00000010 <_Z1fv+0x10> pop	{fp, pc}

vs.

> # g++5 -c -g -std=3Dc++11 -Wall -pedantic builtin_dwarf_cfa.cpp
> # /usr/local/bin/objdump -d --prefix-addresses builtin_dwarf_cfa.o
>=20
> builtin_dwarf_cfa.o:     file format elf32-littlearm
>=20
>=20
> Disassembly of section .text:
> 00000000 <_Z1fv> push	{fp, lr}
> 00000004 <_Z1fv+0x4> add	fp, sp, #4, 0
> 00000008 <_Z1fv+0x8> add	r3, fp, #4, 0
> 0000000c <_Z1fv+0xc> mov	r0, r3
> 00000010 <_Z1fv+0x10> bl	00000000 <_Z1gPv>
> 00000014 <_Z1fv+0x14> nop			; (mov r0, r0)
> 00000018 <_Z1fv+0x18> pop	{fp, pc}


They do not agree.

So any infrastructure based on __builtin_dwarf_cfa() use will be =
compiler sensitive for armv6 as well.

[It is my understanding that what g++ does is what the normal sort of =
.eh_frame infrastructure is designed for: pointing between the caller's =
and called's frames.]


For reference: powerpc64 and powerpc results. . .

> # clang++ -c -g -std=3Dc++11 -Wall -pedantic builtin_dwarf_cfa.cpp
> # /usr/local/bin/objdump -d --prefix-addresses builtin_dwarf_cfa.o
>=20
> builtin_dwarf_cfa.o:     file format elf64-powerpc-freebsd
>=20
>=20
> Disassembly of section .text:
> 0000000000000000 <._Z1fv> mflr    r0
> 0000000000000004 <._Z1fv+0x4> std     r31,-8(r1)
> 0000000000000008 <._Z1fv+0x8> std     r0,16(r1)
> 000000000000000c <._Z1fv+0xc> stdu    r1,-128(r1)
> 0000000000000010 <._Z1fv+0x10> mr      r31,r1
> 0000000000000014 <._Z1fv+0x14> mr      r3,r31
> 0000000000000018 <._Z1fv+0x18> bl      0000000000000018 <._Z1fv+0x18>
> 000000000000001c <._Z1fv+0x1c> nop
> 0000000000000020 <._Z1fv+0x20> addi    r1,r1,128
> 0000000000000024 <._Z1fv+0x24> ld      r0,16(r1)
> 0000000000000028 <._Z1fv+0x28> ld      r31,-8(r1)
> 000000000000002c <._Z1fv+0x2c> mtlr    r0
> 0000000000000030 <._Z1fv+0x30> blr
>         ...

r3 does not point to a boundary with f's caller's stack frame.

By contrast for g++49:

> # g++49 -c -g -std=3Dc++11 -Wall -pedantic builtin_dwarf_cfa.cpp
> # /usr/local/bin/objdump -d --prefix-addresses builtin_dwarf_cfa.o | =
more
>=20
> builtin_dwarf_cfa.o:     file format elf64-powerpc-freebsd
>=20
>=20
> Disassembly of section .text:
> 0000000000000000 <._Z1fv> mflr    r0
> 0000000000000004 <._Z1fv+0x4> std     r0,16(r1)
> 0000000000000008 <._Z1fv+0x8> std     r31,-8(r1)
> 000000000000000c <._Z1fv+0xc> stdu    r1,-128(r1)
> 0000000000000010 <._Z1fv+0x10> mr      r31,r1
> 0000000000000014 <._Z1fv+0x14> addi    r9,r31,128
> 0000000000000018 <._Z1fv+0x18> mr      r3,r9
> 000000000000001c <._Z1fv+0x1c> bl      000000000000001c <._Z1fv+0x1c>
> 0000000000000020 <._Z1fv+0x20> nop
> 0000000000000024 <._Z1fv+0x24> addi    r1,r31,128
> 0000000000000028 <._Z1fv+0x28> ld      r0,16(r1)
> 000000000000002c <._Z1fv+0x2c> mtlr    r0
> 0000000000000030 <._Z1fv+0x30> ld      r31,-8(r1)
> 0000000000000034 <._Z1fv+0x34> blr
> 0000000000000038 <._Z1fv+0x38> .long 0x0
> 000000000000003c <._Z1fv+0x3c> .long 0x90001
> 0000000000000040 <._Z1fv+0x40> lwz     r0,1(r1)

r3 does point to a boundary with f's caller's stack frame.

For TARGET_ARCH=3Dpowerpc, clang 3.8.0 first:

> # clang++ -c -g -std=3Dc++11 -Wall -pedantic builtin_dwarf_cfa.cpp
> # /usr/local/bin/objdump -d --prefix-addresses builtin_dwarf_cfa.o
>=20
> builtin_dwarf_cfa.o:     file format elf32-powerpc-freebsd
>=20
>=20
> Disassembly of section .text:
> 00000000 <_Z1fv> mflr    r0
> 00000004 <_Z1fv+0x4> stw     r31,-4(r1)
> 00000008 <_Z1fv+0x8> stw     r0,4(r1)
> 0000000c <_Z1fv+0xc> stwu    r1,-16(r1)
> 00000010 <_Z1fv+0x10> mr      r31,r1
> 00000014 <_Z1fv+0x14> mr      r3,r31
> 00000018 <_Z1fv+0x18> bl      00000018 <_Z1fv+0x18>
> 0000001c <_Z1fv+0x1c> addi    r1,r1,16
> 00000020 <_Z1fv+0x20> lwz     r0,4(r1)
> 00000024 <_Z1fv+0x24> lwz     r31,-4(r1)
> 00000028 <_Z1fv+0x28> mtlr    r0
> 0000002c <_Z1fv+0x2c> blr

Then g++5 (5.3):

> # g++5 -c -g -std=3Dc++11 -Wall -pedantic builtin_dwarf_cfa.cpp
> # /usr/local/bin/objdump -d --prefix-addresses builtin_dwarf_cfa.o
>=20
> builtin_dwarf_cfa.o:     file format elf32-powerpc-freebsd
>=20
>=20
> Disassembly of section .text:
> 00000000 <_Z1fv> stwu    r1,-16(r1)
> 00000004 <_Z1fv+0x4> mflr    r0
> 00000008 <_Z1fv+0x8> stw     r0,20(r1)
> 0000000c <_Z1fv+0xc> stw     r31,12(r1)
> 00000010 <_Z1fv+0x10> mr      r31,r1
> 00000014 <_Z1fv+0x14> addi    r9,r31,16
> 00000018 <_Z1fv+0x18> mr      r3,r9
> 0000001c <_Z1fv+0x1c> bl      0000001c <_Z1fv+0x1c>
> 00000020 <_Z1fv+0x20> nop
> 00000024 <_Z1fv+0x24> addi    r11,r31,16
> 00000028 <_Z1fv+0x28> lwz     r0,4(r11)
> 0000002c <_Z1fv+0x2c> mtlr    r0
> 00000030 <_Z1fv+0x30> lwz     r31,-4(r11)
> 00000034 <_Z1fv+0x34> mr      r1,r11
> 00000038 <_Z1fv+0x38> blr


The historical note below is from before I'd discovered powerpc64 or =
armv6 have the same sort of issue. But it gives an example use that is =
broken for powerpc and powerpc64. (I do not know if armv6 uses the same =
infrastructure.)

=3D=3D=3D
Mark Millard
markmi at dsl-only.net

On 2016-Feb-27, at 3:31 PM, Mark Millard <markmi at dsl-only.net> wrote:
>=20
> [Top post for dinging the low level problem that directly breaks c++ =
exception handling for TARGET_ARCH=3Dpowerpc for clang 3.8.0 generated =
code.]
>=20
> I've tracked down the c++ exception problem for TARGET_ARCH=3Dpowerpc =
via clang 3.8.0: misbehavior of clang 3.8.0 code generation for =
__builtin_dwarf_cfa () as used in:
>=20
> #define uw_init_context(CONTEXT)                                       =
    \
>  do                                                                    =
   \
>    {                                                                   =
   \
>      /* Do any necessary initialization to access arbitrary stack =
frames. \
>         On the SPARC, this means flushing the register windows.  */    =
   \
>      __builtin_unwind_init ();                                         =
   \
>      uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (),               =
   \
>                         __builtin_return_address (0));                 =
   \
>    }                                                                   =
   \
>  while (0)
> . . .
> 85	_Unwind_Reason_Code
> 86	_Unwind_RaiseException(struct _Unwind_Exception *exc)
> 87	{
> 88	  struct _Unwind_Context this_context, cur_context;
> 89	  _Unwind_Reason_Code code;
> 90=09
> 91	  /* Set up this_context to describe the current stack frame.  =
*/
> 92	  uw_init_context (&this_context);
>=20
> In the below r4 ends up with the __builtin_dwarf_cfa () value supplied =
to uw_init_context_1:
>=20
> Dump of assembler code for function _Unwind_RaiseException:
>   0x419a8fd8 <+0>:	mflr    r0
>   0x419a8fdc <+4>:	stw     r31,-148(r1)
>   0x419a8fe0 <+8>:	stw     r30,-152(r1)
>   0x419a8fe4 <+12>:	stw     r0,4(r1)
>   0x419a8fe8 <+16>:	stwu    r1,-2992(r1)
>   0x419a8fec <+20>:	mr      r31,r1
> . . .
>   0x419a9094 <+188>:	mr      r4,r31
>   0x419a9098 <+192>:	mflr    r30
>   0x419a909c <+196>:	lwz     r5,2996(r31)
>   0x419a90a0 <+200>:	mr      r3,r28
>   0x419a90a4 <+204>:	bl      0x419a929c <uw_init_context_1>
>=20
> That r4 ends up holding the stack pointer value for after it has been =
decremented. r4 is not pointing at the boundary with the caller's frame.
>=20
> The .eh_frame information and unwind code is set up for pointing at =
the boundary with the caller's frame. So the cfa relative addressing is =
messed up for what it actually extracts.
>=20
> Contrast this with gcc/g++ 5.3's TARGET_ARCH=3Dpowerpc64 code where r4 =
is  made to be at the boundary with the caller's frame:
>=20
> Dump of assembler code for function _Unwind_RaiseException:
>   0x00000000501cb810 <+0>:	mflr    r0
>   0x00000000501cb814 <+4>:	stdu    r1,-5648(r1)
> . . .
>   0x00000000501cb8d0 <+192>:	addi    r4,r1,5648
>   0x00000000501cb8d4 <+196>:	stw     r12,5656(r1)
>   0x00000000501cb8d8 <+200>:	mr      r28,r3
>   0x00000000501cb8dc <+204>:	addi    r31,r1,2544
>   0x00000000501cb8e0 <+208>:	mr      r3,r27
>   0x00000000501cb8e4 <+212>:	addi    r29,r1,112
>   0x00000000501cb8e8 <+216>:	bl      0x501cae60 <uw_init_context_1>
>=20
>=20
> NOTE: The powerpc (32-bit) issue may in some way be associated with =
the clang 3.8.0 powerpc ABI violation in how it handles the stack =
pointer for FreeBSD: TARGET_ARCH=3Dpowerpc is currently using a "red =
zone", decrementing the stack pointer late, and incrementing the stack =
pointer early compared to the FreeBSD ABI rules. (This is similar to the =
official FreeBSD ABI for TARGET_ARCH=3Dpowerpc64.)
>=20
>=20
>=20
>=20
> =3D=3D=3D
> Mark Millard
> markmi at dsl-only.net




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?366B67F9-6A14-4906-8545-1B57A3FF53B8>