Bug 207736 - clang 3.8.0/powerpc/powerpc64's _Unwind_RaiseException code generation has messed up r31 (frame pointer) save/restore code (SEGV's can result)
Summary: clang 3.8.0/powerpc/powerpc64's _Unwind_RaiseException code generation has me...
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: CURRENT
Hardware: powerpc Any
: --- Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-03-06 11:43 UTC by Mark Millard
Modified: 2020-03-10 23:43 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Millard 2016-03-06 11:43:29 UTC
[This has been reported on llvm bugzilla: 26856.]

The below causes gdb difficulties for its stack handling: more than just exception handling is at issue. I just happened to notice it via exception handling.

Function _Unwind_RaiseException below is from a FreeBSD "buildworld" using clang 3.8.0.

Dump of assembler code for function _Unwind_RaiseException:
   0x41b2ab80 <+0>:	mflr    r0
   0x41b2ab84 <+4>:	stw     r31,-148(r1)
   0x41b2ab88 <+8>:	stw     r30,-152(r1)
   0x41b2ab8c <+12>:	stw     r0,4(r1)
   0x41b2ab90 <+16>:	stwu    r1,-2992(r1)
   0x41b2ab94 <+20>:	mr      r31,r1
. . .
   0x41b2abe0 <+96>:	stw     r31,2844(r31)
(which replaces the earlier save of the old Frame pointer R31
value with a copy of r1's current  value. Note the offset
relationships with the r1 adjustment: -2992+2844=-148)
. . .
   0x41b2add0 <+592>:	lwz     r31,2844(r31)
(This restores the r1 value that resulted from the "stwu r1,-2992(r1)" into R31.)
. . .
   0x41b2ae30 <+688>:	lwz     r31,-148(r1)
(This restores the r1 value that resulted from the "stwu r1,-2992(r1)" into R31.)
. . .

The wrong r31 value is present when _Unwind_RaiseException returns.

But before that while _Unwind_RaiseException is active the C++ exception handling infrastructure has been given bad r31 information for around _Unwind_RaiseException's frame.
Comment 1 Mark Millard 2016-03-06 13:58:17 UTC
I compiled a .o for TARGET_ARCH=powerpc64 via letting "buildworld" get as far as it could and the resultant .o produced has the same sort of r31/frame-pointer problem as powerpc for _Unwind_RaiseException: The problem DOES occur for powerpc64.

A) r31 is stored twice to the same location, with the 2nd store destroying the frame-pointer value that is supposed to be saved and restored for the caller.

B) r31 is restored twice from the same location.

The FreeBSD TARGET_ARCH=powerpc64 does officially use a stack red-zone on the low-address side with officially "late" decrement and "early" increment (AIX like). Relative to this:

A) each r31 store is on a different side of the "late" r1 decrement

and

B) each r31 restore is on a different side of the "early" r1 increment

TARGET_ARCH=powerpc gets that same relationships but the late r1 decrement and early r1 increment are SVR4 ABI violations: SVR4'sABI does not require a "red-zone" on the low-address side of the stack.

(To get as far as I have for powerpc "buildworld" I had to add signal red-zone handling to my personal FreeBSD builds.)
Comment 2 Mark Millard 2017-02-27 03:14:52 UTC
As of clang 3.9.1 TARGET_ARCH=powerpc still has some
R31 restoration problems when floating point code is
also involved:

R31 is restored but later floating-point cleanup
code is based on R31 not having been restored yet.
In other words: R31 is restored too early.

This is not specific to _Unwind_RaiseException .
Comment 3 Justin Hibbits freebsd_committer freebsd_triage 2017-03-29 16:08:23 UTC
Can you (or did you) file this upstream with llvm?
Comment 4 Mark Millard 2017-03-29 22:03:24 UTC
(In reply to Justin Hibbits from comment #3)

I started at the time with (quoting the description's
first line):

[This has been reported on llvm bugzilla: 26856.]



While 26856 was worked on some the fix was partial
compared to the full submittal and it is still not
resolved in llvm's bugzilla. See 26856's Comment 11,
which references llvm's r280188 for what was done.


In Comment 2 [of FreeBSD's 207736] I messed up R31
vs. R30 references: it should have been R30 for powerpc
vs. floating point code (llvm's 26519 submittal covers
this). So likely I never should have submitted comment
2 here at all. (But I can not edit or delete such to
avoid future confusions more directly.)
Comment 5 Mark Millard 2019-07-09 02:12:37 UTC
It looks like when powerpc64 in head switches to ELFv2
this will have been Overcome By Events that became
official.

(The clang code generation for this was fixed up a
fair time ago but clang is not officially supported
yet and there were other issues blocking its general
use.)
Comment 6 Mark Millard 2020-03-10 23:43:51 UTC
Head no longer has the old libunwind code and my
understanding is that there is no plan to complete
the implementation of DW_CFA_remember_state and
DW_CFA_restore_state in 11 or 12 (which still have
the old libunwind code as I understand).

clang also has progressed so that in head, and
eventually 13.0, clang will be officially the
means of building powerpc families (64-bit and
32-bit), using llvm's libunwind.

The 64-bit ABI has also been changed as part of
the activity.