Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 19 Mar 2019 20:16:36 -0700
From:      Mark Millard <marklmi@yahoo.com>
To:        FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>, FreeBSD Toolchain <freebsd-toolchain@freebsd.org>
Subject:   powerpc64: clang/libunwind vs devel/powerpc64-gcc based code for C++ exception handling: incompatible [ignoring r2 handling issue]
Message-ID:  <1B1A8473-1A53-407B-B96D-D25D91EE9A6B@yahoo.com>

next in thread | raw e-mail | index | archive | help
[This note ignores libunwind's r2 (TOC) mishandling
issue that has been noted elsewhere.]

It appears to me that clang powerpc64 targeted code
and devel/powerpc64-gcc generated code are incompatible
for C++ exception handling. I show code examples
later.

clang does in-line setup of register save/restore in
a.out but powerpc64-gcc leaves it to the unwind
library. libunwind does not do that, expecting the
compiler to have dealt with managing the save/restore
activity. Thus when code produced by powerpc64-gcc
is in use, the save/restore activity would not happen.

[This also leads to matching differences in what
dwarfdump -v -v -v -F shows in various relevant
places, but I'll not show that in this message.]

(Is there a detailed powerpc64 ABI definition that, if
followed by both compilers, would make use of the two
compilers compatible for C++ exceptions?)

A question is: is it required to allow the likes of
devel/powerpc64-xtoolchain-gcc based buildworld's that
target powerpc64 if/when libunwind becomes official?

[It appears to me that clang used under a historical
libgcc_s.so that built with powerpc-gcc has redundant
save/restore activity that, while non-optimal, would
work. So: not as strong of a mis-match and I'll ignore
that combination below.]


Evidence for the problem being reported . . .

For code like (causing lots of save/restore
context for C++ exceptions to be involved):

# more exception_test_regs.cpp=20
#include <exception>
#include <stdlib.h>

int main(void)
{
    volatile int  a[]=3D {0,1,2,3};
    int incr=3D rand()%4;

#define unit(v,init) \
    int  v=3D init; \
    try { \
        if (a[v] < 4) throw std::exception(); \
        v=3D (v+incr) % 4; \
    } \
    catch (std::exception& e) {}

    unit(b,incr);
    unit(c,b);
    unit(d,c);
    unit(e,d);
    unit(f,e);
    unit(g,f);
    unit(h,g);
    unit(i,h);
    unit(j,i);
    unit(k,j);
    unit(l,k);
    unit(m,l);
    unit(n,m);
    unit(o,n);
    unit(p,o);
    unit(q,p);
    unit(r,q);
    unit(s,r);
    unit(t,s);
    unit(u,t);
    unit(v,u);
    unit(w,v);
    unit(x,w);
    unit(y,x);
    unit(z,y);

    a[(b+c+d+e+f+g+h+i+j+k+m+n+o+p+q+r+s+t+u+v+w+x+y+z)%4]=3D i;

    return 0;
}

clang produces code that is, in part, like:

000000001000110c <.main+0x370> add     r3,r24,r29
0000000010001110 <.main+0x374> srawi   r4,r3,2
0000000010001114 <.main+0x378> addze   r4,r4
0000000010001118 <.main+0x37c> rlwinm  r4,r4,2,0,29
000000001000111c <.main+0x380> subf    r26,r4,r3
0000000010001120 <.main+0x384> extsw   r25,r26
0000000010001124 <.main+0x388> rldicr  r3,r25,2,61
0000000010001128 <.main+0x38c> lwzx    r3,r30,r3
000000001000112c <.main+0x390> cmpwi   r3,3
0000000010001130 <.main+0x394> ble-    00000000100018fc <.main+0xb60>
0000000010001134 <.main+0x398> add     r3,r26,r29
. . .
00000000100018fc <.main+0xb60> li      r3,8
0000000010001900 <.main+0xb64> stw     r0,156(r31)
0000000010001904 <.main+0xb68> mr      r14,r8
0000000010001908 <.main+0xb6c> mr      r15,r7
000000001000190c <.main+0xb70> mr      r16,r6
0000000010001910 <.main+0xb74> stw     r12,152(r31)
0000000010001914 <.main+0xb78> mr      r28,r5
0000000010001918 <.main+0xb7c> stw     r11,148(r31)
000000001000191c <.main+0xb80> stw     r10,144(r31)
0000000010001920 <.main+0xb84> stw     r9,140(r31)
0000000010001924 <.main+0xb88> bl      0000000010000860 =
<00000018.plt_call.__cxa_allocate_exception@@CXXABI_1.3>
0000000010001928 <.main+0xb8c> ld      r2,40(r1)
000000001000192c <.main+0xb90> nop
0000000010001930 <.main+0xb94> ld      r4,-32728(r2)
0000000010001934 <.main+0xb98> addi    r4,r4,16
0000000010001938 <.main+0xb9c> std     r4,0(r3)
000000001000193c <.main+0xba0> nop
0000000010001940 <.main+0xba4> nop
0000000010001944 <.main+0xba8> ld      r4,-32720(r2)
0000000010001948 <.main+0xbac> ld      r5,-32712(r2)
000000001000194c <.main+0xbb0> bl      00000000100008e0 =
<00000018.plt_call.__cxa_throw@@CXXABI_1.3>
0000000010001950 <.main+0xbb4> ld      r2,40(r1)
0000000010001954 <.main+0xbb8> b       0000000010001b20 <.main+0xd84>
. . .
0000000010001b20 <.main+0xd84> cmplwi  r4,1
0000000010001b24 <.main+0xd88> bne-    0000000010002104 <.main+0x1368>
0000000010001b28 <.main+0xd8c> bl      0000000010000880 =
<00000018.plt_call.__cxa_begin_catch@@CXXABI_1.3>
0000000010001b2c <.main+0xd90> ld      r2,40(r1)
0000000010001b30 <.main+0xd94> bl      00000000100008a0 =
<00000018.plt_call.__cxa_end_catch@@CXXABI_1.3>
0000000010001b34 <.main+0xd98> ld      r2,40(r1)
0000000010001b38 <.main+0xd9c> lwz     r7,132(r31)
0000000010001b3c <.main+0xda0> mr      r3,r14
0000000010001b40 <.main+0xda4> mr      r5,r29
0000000010001b44 <.main+0xda8> mr      r6,r25
0000000010001b48 <.main+0xdac> lwz     r8,136(r31)
0000000010001b4c <.main+0xdb0> lwz     r9,140(r31)
0000000010001b50 <.main+0xdb4> lwz     r10,144(r31)
0000000010001b54 <.main+0xdb8> lwz     r11,148(r31)
0000000010001b58 <.main+0xdbc> lwz     r12,152(r31)
0000000010001b5c <.main+0xdc0> lwz     r0,156(r31)
0000000010001b60 <.main+0xdc4> b       0000000010001210 <.main+0x474>

Note the explicit stw's before the bl for
00000018.plt_call.__cxa_allocate_exception@@CXXABI_1.3
and the matching lwz's after the bl for
00000018.plt_call.__cxa_end_catch@@CXXABI_1.3,
and also the save/restore use of some registers from
R14-R31 that are part of the call standard.
(I just picked one of the examples so show code
for. The detailed save/restore code varies from
one to the next.)

powerpc64-gcc does not generate such code before
00000018.plt_call.__cxa_allocate_exception@@CXXABI_1.3
or after 00000018.plt_call.__cxa_end_catch@@CXXABI_1.3 .
The code looks like (again just picking an example):

0000000010000ad4 <.main+0x1b4> add     r9,r21,r30
0000000010000ad8 <.main+0x1b8> srawi   r26,r9,2
0000000010000adc <.main+0x1bc> addze   r26,r26
0000000010000ae0 <.main+0x1c0> rlwinm  r26,r26,2,0,29
0000000010000ae4 <.main+0x1c4> subf    r26,r26,r9
0000000010000ae8 <.main+0x1c8> extsw   r26,r26
0000000010000aec <.main+0x1cc> rldicr  r9,r26,2,61
0000000010000af0 <.main+0x1d0> lwzx    r9,r29,r9
0000000010000af4 <.main+0x1d4> cmpwi   cr7,r9,3
0000000010000af8 <.main+0x1d8> ble     cr7,0000000010001428 =
<.main+0xb08>
. . .
0000000010001428 <.main+0xb08> li      r3,8
000000001000142c <.main+0xb0c> bl      0000000010000860 =
<0000004b.plt_call.__cxa_allocate_exception@@CXXABI_1.3>
0000000010001430 <.main+0xb10> ld      r2,40(r1)
0000000010001434 <.main+0xb14> nop
0000000010001438 <.main+0xb18> ld      r9,-32728(r2)
000000001000143c <.main+0xb1c> nop
0000000010001440 <.main+0xb20> ld      r5,-32720(r2)
0000000010001444 <.main+0xb24> nop
0000000010001448 <.main+0xb28> std     r9,0(r3)
000000001000144c <.main+0xb2c> ld      r4,-32712(r2)
0000000010001450 <.main+0xb30> bl      0000000010000900 =
<0000004b.plt_call.__cxa_throw@@CXXABI_1.3>
0000000010001454 <.main+0xb34> ld      r2,40(r1)
0000000010001458 <.main+0xb38> cmpdi   cr7,r4,1
000000001000145c <.main+0xb3c> bne     cr7,0000000010000f5c =
<.main+0x63c>
0000000010001460 <.main+0xb40> bl      00000000100008c0 =
<0000004b.plt_call.__cxa_begin_catch@@CXXABI_1.3>
0000000010001464 <.main+0xb44> ld      r2,40(r1)
0000000010001468 <.main+0xb48> mr      r20,r26
000000001000146c <.main+0xb4c> bl      00000000100008e0 =
<0000004b.plt_call.__cxa_end_catch@@CXXABI_1.3>
0000000010001470 <.main+0xb50> ld      r2,40(r1)
0000000010001474 <.main+0xb54> b       0000000010000b14 <.main+0x1f4>

(None of the allocate_exception..end_catch related code
has code anything like doing what clang did for
save/restore.)

The result is that, used against libunwind built with
either clang or powerpc-gcc, the relevant registers for a
powerpc64-gcc based a.out are not saved/restored that
need to be for correct operation.

[libunwind does not use __builtin_eh_return to have
(part of) what a historical libgcc_s.so had for
for its save/restore.]

[Note: In my context the "historical" libgcc_s.so has
the interpretation of DW_CFA_remember_state and
DW_CFA_restore_state shown in dwarfdmp -v -v -v -F
output fixed for how to interpret it (instead of being
incomplete).]

=3D=3D=3D
Mark Millard
marklmi at yahoo.com
( dsl-only.net went
away in early 2018-Mar)




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1B1A8473-1A53-407B-B96D-D25D91EE9A6B>