https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125803

            Bug ID: 125803
           Summary: [powerpc64 FreeBSD ELFv2] frob_update_context in
                    freebsd-unwind.h uses the ELFv1 TOC save-slot offset
                    (40), so r2 is not restored when unwinding and C++
                    exceptions crash
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: pkubaj at anongoth dot pl
  Target Milestone: ---

Created attachment 64744
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=64744&action=edit
patch

Also present on 14/15/16.
On FreeBSD/powerpc64* targets (so both powerpc64 and powerpc64le), there's a
ELFv1-ism in libgcc/config/rs6000/freebsd-unwind.h.
It causes crashes during throwing and catching C++ exceptions through gcc's
libgcc_s.

Minimal reproducer (build with the system clang, or g++ -shared-libgcc;
run so that gcc's libgcc_s provides the unwinder):
#include <cstdio>
int main() {
try { throw 42; }
catch (int e) { printf("caught %d\n", e); }
}
$ c++ -o t t.cpp # base libgcc_s -> OK
caught 42
$ LD_PRELOAD=/usr/local/lib/gcc14/libgcc_s.so.1 ./t   # gcc libgcc_s
Segmentation fault (core dumped)

It works with a fully static link (g++ -static) and with FreeBSD's base
libgcc_s, and only fails with gcc's *shared* libgcc_s -- i.e. only when
libgcc_s and the throwing/catching code have different TOCs.

The problem is that the code assumes ELFv1 and sets TOC save slot offset of 40
bytes:
std r2,40(r1)   == 0xF8410028
ld  r2,40(r1)   == 0xE8410028
context->cfa + 40 ,  sp + 40

But ELFv2 saves the TOC at offset 24 (std r2,24(r1) / ld r2,24(r1)), so
none of the checks ever match, r2 is never restored, and the handler
runs with the wrong TOC.

rs6000/linux-unwind.h already does this correctly, selecting the offset
with a TOC_SAVE_SLOT macro keyed on _CALL_ELF (24 for ELFv2, 40
otherwise). freebsd-unwind.h was never updated for ELFv2.

Fix attached.

Reply via email to