Hello,

after some discussion in #debian-arm, I have to revise this.

On 04/26/2017 10:30 AM, Uwe Kleine-König wrote:
> On Mon, Apr 17, 2017 at 05:02:32PM +0100, Paul Brook wrote:
>> Package: libsbc1
>> Version: 1.3-1+b2
>> Followup-For: Bug #856487
>>
>> Not a stack corruption.
>>
>> This is miscompilation of sbc_analyze_4b_8s_armv6.  gcc appears to look
>> into the asm function and decides that it does not clobber r3 (which the
>> normal ARM ABI says is call clobbered).  The last out += out_stride ends
>> up incrementing the pointer by an arbitrary amount.
>>
>> The attached patch works around the bug.
>>
>> I'm not entirely sure whether this is a gcc bug or not, but at best it's
>> surprising behavior from gcc.  I've attached a reduced testcase for the 
>> toolchain
>> folks to argue over (compile with gcc -O2, tested with gcc 6.3.0-2 from
>> sid).
> 
> AFAICT this is not a gcc bug. gcc is not supposed (and I'm sure this is
> even impossible in general) to determine the set of clobbered registers.
> 
>> diff -ur clean/sbc/sbc_primitives_armv6.c sbc-1.3/sbc/sbc_primitives_armv6.c
>> --- clean/sbc/sbc_primitives_armv6.c 2013-04-30 17:19:23.000000000 +0100
>> +++ sbc-1.3/sbc/sbc_primitives_armv6.c       2017-04-17 16:43:49.918809345 
>> +0100
>> @@ -102,6 +102,7 @@
>>              "pop    {r8-r11}\n"
>>              "stmia  r1, {r4, r5, r6, r7}\n"
>>              "pop    {r1, r4-r7, pc}\n"
>> +        :::"r0", "r2", "r3", "ip"
> 
> While this might fix the problem at hand, this is not a complete fix.

naked functions must only use basic assembler according to

        https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html

.

> So there is no guarantee that r0 still has the value passed to the
> function when it returns.
> 
> So r0, r1 and r2 must be declared inputs, r0 also an output.

So this is wrong.

> Also I'd
> recommend to fix the prototype of the functions to match reality.

This however stays correct.

> Other than that the code is hard to review and I wonder if it's worth to
> have this as hand coded assembly.

ditto.

>> /* Compile with -O2 on arm */
>> #include <stdint.h>
>> #include <stdlib.h>
>>
>> static void __attribute__((naked)) frob(int16_t *a, int32_t *b, const 
>> int16_t *c)
>> {
>>      /* The explicit clobber of r3 should not be necessary because that it 
>> is implied by the function call?
> 
> No it's not.

ok, AAPCS[1] says:

        A subroutine must preserve the contents of the registers r4-
        r8, r10, r11 and SP (and r9 in PCS variants that
        designate r9 as v6).

So r3 can be clobbered and gcc must assume that this is the case.

BTW, the relevant assembly output (generated on abel.d.o) is:

000006cc <frob>:
 6cc:   e3a03102        mov     r3, #-2147483648        ; 0x80000000
 6d0:   e5813000        str     r3, [r1]
 6d4:   e12fff1e        bx      lr

000006d8 <test>:
 6d8:   e92d41f0        push    {r4, r5, r6, r7, r8, lr}
 6dc:   e1a04001        mov     r4, r1
 6e0:   e1a01002        mov     r1, r2
 6e4:   e59f2054        ldr     r2, [pc, #84]   ; 740 <test+0x68>
 6e8:   e59f0054        ldr     r0, [pc, #84]   ; 744 <test+0x6c>
 6ec:   e08f2002        add     r2, pc, r2
 6f0:   e7925000        ldr     r5, [r2, r0]
 6f4:   e1a03103        lsl     r3, r3, #2
 6f8:   e1a02005        mov     r2, r5
 6fc:   e2840030        add     r0, r4, #48     ; 0x30
 700:   e0817003        add     r7, r1, r3
 704:   ebfffff0        bl      6cc <frob>
 708:   e1a01007        mov     r1, r7
 70c:   e0876003        add     r6, r7, r3
 710:   e1a02005        mov     r2, r5
 714:   e2840020        add     r0, r4, #32
 718:   ebffffeb        bl      6cc <frob>
 71c:   e1a01006        mov     r1, r6
 720:   e1a02005        mov     r2, r5
 724:   e2840010        add     r0, r4, #16
 728:   ebffffe7        bl      6cc <frob>
 72c:   e1a02005        mov     r2, r5
 730:   e0861003        add     r1, r6, r3
 734:   e1a00004        mov     r0, r4
 738:   e8bd41f0        pop     {r4, r5, r6, r7, r8, lr}
 73c:   eaffffe2        b       6cc <frob>
 740:   0001090c        .word   0x0001090c
 744:   00000034        .word   0x00000034

And at address 70c r3 is assumed to still hold the initial value but
frob already clobbered it when being called at address 704.

When I change frob to:

        void frob(int16_t *a, int32_t *b, const int16_t *c);

(and compile with -c) the code is correct. So it would indeed be
interesting to get some input from the gcc people.

Best regards
Uwe

[1]
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to