powerpc (32-bit) clang 3.8.0 vs. gcc 4.2.1 routine preamble mismatches: contributions to SEGV's differences

Mark Millard markmi at dsl-only.net
Fri Feb 5 09:59:36 UTC 2016


Clang 3.8.0 produced code uses r31 as a frame pointer in contexts where gcc 4.2.1 produced code does not (ever?). This leaves clang's produced code being more dependent on r31 handling, such as when resuming after signal delivery.

The following is one of the routines in "make" where a clang 3.8.0 based "make" sometimes gets a SEGV after resuming after a SIGCHLD delivery, the SEGV being from having r31=0x0 in a Frame Pointer (r31) based address calculation that is at some point dereferenced. (See https://lists.freebsd.org/pipermail/freebsd-ppc/2016-February/008002.html .)

But gcc 4.2.1 does not use r31 as a frame pointer in the Str_Match that it produces and so does not see the problem. gcc 4.2.1's produced code simply uses the stack pointer as needed.


clang 3.8.0 based Str_Match preamble (from make):

0x181a4a8 <Str_Match>:	mflr    r0
0x181a4ac <Str_Match+4>:	stw     r31,-4(r1) # Clang's frame pointer (r31) 
                                                   # saved before stack pointer changed.
0x181a4b0 <Str_Match+8>:	stw     r0,4(r1)   # lr saved before stack pointer changed.
0x181a4b4 <Str_Match+12>:	stwu    r1,-32(r1) # Stack pointer finally saved and
                                                   # changed.
0x181a4b8 <Str_Match+16>:	mr      r31,r1     # r31 is the frame pointer under clang.
0x181a4bc <Str_Match+20>:	stw     r30,24(r31)

gcc 4.2.1 based Str_Match preamble:

0x1819cb8 <Str_Match>:	mflr    r0
0x1819cbc <Str_Match+4>:	stwu    r1,-32(r1) # Stack pointer saved and changed first.
0x1819cc0 <Str_Match+8>:	stw     r31,28(r1) # r31 saved after stack pointer changed.
0x1819cc4 <Str_Match+12>:	mr      r31,r3     # gcc 4.2.1 does not reserve
                                                   # r31 for use as a frame pointer.
0x1819cc8 <Str_Match+16>:	stw     r30,24(r1)
0x1819ccc <Str_Match+20>:	stw     r0,36(r1)  # lr saved after stack pointer changed.


(Str_Match is a self contained routine, although it is recursive.)


Looking at some other gcc 4.2.1 preamble examples. . .

0x1823b58 <VarSYSVMatch>:	cmpwi   cr7,r6,0
0x1823b5c <VarSYSVMatch+4>:	stwu    r1,-64(r1) # Stack pointer saved and changed "first"
0x1823b60 <VarSYSVMatch+8>:	mflr    r0
0x1823b64 <VarSYSVMatch+12>:	lis     r9,396
0x1823b68 <VarSYSVMatch+16>:	stw     r25,36(r1)
0x1823b6c <VarSYSVMatch+20>:	addi    r25,r9,8944
0x1823b70 <VarSYSVMatch+24>:	stw     r26,40(r1)
0x1823b74 <VarSYSVMatch+28>:	mr      r26,r3
0x1823b78 <VarSYSVMatch+32>:	stw     r27,44(r1)
0x1823b7c <VarSYSVMatch+36>:	mr      r27,r4
0x1823b80 <VarSYSVMatch+40>:	stw     r28,48(r1)
0x1823b84 <VarSYSVMatch+44>:	mr      r28,r8
0x1823b88 <VarSYSVMatch+48>:	stw     r29,52(r1)
0x1823b8c <VarSYSVMatch+52>:	mr      r29,r5
0x1823b90 <VarSYSVMatch+56>:	stw     r31,60(r1)
0x1823b94 <VarSYSVMatch+60>:	mr      r31,r7     # Again r31 is not a frame pointer
0x1823b98 <VarSYSVMatch+64>:	stw     r0,68(r1)
0x1823b9c <VarSYSVMatch+68>:	lwz     r0,0(r25)
0x1823ba0 <VarSYSVMatch+72>:	stw     r0,28(r1)
0x1823ba4 <VarSYSVMatch+76>:	li      r0,0
0x1823ba8 <VarSYSVMatch+80>:	stw     r30,56(r1)
0x1823bac <VarSYSVMatch+84>:	beq-    cr7,0x1823bbc <VarSYSVMatch+100>


0x1819f30 <Str_SYSVMatch>:	mflr    r0         # Stack pointer saved and changed first
0x1819f34 <Str_SYSVMatch+4>:	stwu    r1,-32(r1)
0x1819f38 <Str_SYSVMatch+8>:	stw     r28,16(r1)
0x1819f3c <Str_SYSVMatch+12>:	mr      r28,r5
0x1819f40 <Str_SYSVMatch+16>:	stw     r30,24(r1)
0x1819f44 <Str_SYSVMatch+20>:	mr      r30,r3
0x1819f48 <Str_SYSVMatch+24>:	stw     r31,28(r1)
0x1819f4c <Str_SYSVMatch+28>:	mr      r31,r4     # Again r31 is not a frame pointer
0x1819f50 <Str_SYSVMatch+32>:	stw     r29,20(r1)
0x1819f54 <Str_SYSVMatch+36>:	stw     r0,36(r1)
0x1819f58 <Str_SYSVMatch+40>:	lbz     r29,0(r4)


0x181fcac <VarMatch>:	mflr    r0                 # Stack pointer saved and changed first
0x181fcb0 <VarMatch+4>:	stwu    r1,-48(r1)
0x181fcb4 <VarMatch+8>:	lis     r9,396
0x181fcb8 <VarMatch+12>:	stw     r27,28(r1)
0x181fcbc <VarMatch+16>:	mr      r27,r4
0x181fcc0 <VarMatch+20>:	stw     r0,52(r1)
0x181fcc4 <VarMatch+24>:	stw     r28,32(r1)
0x181fcc8 <VarMatch+28>:	mr      r28,r7
0x181fccc <VarMatch+32>:	lwz     r0,-1344(r9)
0x181fcd0 <VarMatch+36>:	stw     r29,36(r1)
0x181fcd4 <VarMatch+40>:	mr      r29,r5
0x181fcd8 <VarMatch+44>:	andi.   r9,r0,512
0x181fcdc <VarMatch+48>:	stw     r30,40(r1)
0x181fce0 <VarMatch+52>:	stw     r31,44(r1)
0x181fce4 <VarMatch+56>:	mr      r30,r8
0x181fce8 <VarMatch+60>:	mr      r31,r6     # Again r31 is not a frame pointer


0x1801d58 <Buf_AddBytes>:	mflr    r0         # Stack pointer saved and changed first
0x1801d5c <Buf_AddBytes+4>:	stwu    r1,-48(r1)
0x1801d60 <Buf_AddBytes+8>:	stw     r28,32(r1)
0x1801d64 <Buf_AddBytes+12>:	stw     r0,52(r1)
0x1801d68 <Buf_AddBytes+16>:	stw     r30,40(r1)
0x1801d6c <Buf_AddBytes+20>:	mr      r30,r4
0x1801d70 <Buf_AddBytes+24>:	lwz     r28,4(r3)
0x1801d74 <Buf_AddBytes+28>:	lwz     r4,0(r3)
0x1801d78 <Buf_AddBytes+32>:	stw     r29,36(r1)
0x1801d7c <Buf_AddBytes+36>:	add     r29,r30,r28
0x1801d80 <Buf_AddBytes+40>:	cmpw    cr7,r29,r4
0x1801d84 <Buf_AddBytes+44>:	stw     r27,28(r1)
0x1801d88 <Buf_AddBytes+48>:	stw     r31,44(r1)
0x1801d8c <Buf_AddBytes+52>:	mr      r27,r5
0x1801d90 <Buf_AddBytes+56>:	mr      r31,r3     # Again r31 is not a frame pointer


And so it goes for every intermittent SEGV related example (clang 3.8.0 buildworld based) that I've examined: the matching gcc 4.2.1 code would not try to use the the r31 values that clang does use. Instead gcc 4.2.1 assigns an independent value to r31 before using it.


In effect gcc 4.2.1 and clang 3.8.0 are not following the exact-same call standard. If clang 3.8.0's code generation is left as is then a conversion to its call standard requirements will be required if clang 3.8.0 is to be used for powerpc (32-bit).

"Works when gcc 4.2.1 is used" is not a great guide to "appropriate for use with clang 3.8.0", at least in this area for powerpc (32-bit).

(These notes presume a context with sys/powerpc/powerpc/sigcode32.S -r295186 in place so that signal delivery maintains the modulo 16 byte stack/frame alignment status instead of changing the alignment. It appears that, while necessary, this is not sufficient for a clang 3.8.0 based buildworld to operate with signals reliably. See https://lists.freebsd.org/pipermail/freebsd-ppc/2016-February/008002.html .)

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



More information about the freebsd-ppc mailing list