powerpc64: clang/libunwind vs devel/powerpc64-gcc based code for C++ exception handling: incompatible [ignoring r2 handling issue]

Mark Millard via freebsd-toolchain <[email protected]>
Newsgroups gmane.os.freebsd.devel.toolchain,gmane.os.freebsd.devel.ppc
Message-ID <[email protected]>
[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 
#include <exception>
#include <stdlib.h>

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

#define unit(v,init) \
    int  v= init; \
    try { \
        if (a[v] < 4) throw std::exception(); \
        v= (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]= 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).]

===
Mark Millard
marklmi at yahoo.com
( dsl-only.net went
away in early 2018-Mar)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.