Mischief reported a crash with on arm with
winwatch when closing all windows excluding those
ignored through the -e flag. Cinap_lenrek
narrowed the problem down to a bug in the 5l
linker: it generates incorrect code when using
the conditional operator and dividing.
A minimal test case is the following:

term% cat foo.c
#include <u.h>
#include <libc.h>

void
main(void)
{
        int i, j, k;

        i = 1;
        j = 0;
        k = j <= 0 ? 1 : 2/i;
        print("%d\n", k);
        exits(nil);
}

The output of asm(main) in acid is:

acid: asm(main)
main 0x00001020 MOVW.W  R14,#-0x18(R13)
main+0x4 0x00001024     MOVW    $#0x1,R1
main+0x8 0x00001028     MOVW    $#0x0,R2
main+0xc 0x0000102c     CMP.S   $#0x0,R2
main+0x10 0x00001030    MOVW.LE R1,R3
main+0x14 0x00001034    MOVW.GT $#0x2,R3
main+0x18 0x00001038    SUB.GT  $#0x8,R13,R13
main+0x1c 0x0000103c    MOVW    R1,#0x4(R13)
main+0x20 0x00001040    MOVW    R3,R11
main+0x24 0x00001044    BL      _div
main+0x28 0x00001048    MOVW    R11,R3
main+0x2c 0x0000104c    ADD     $#0x8,R13,R13
main+0x30 0x00001050    MOVW    $#0x7080,R0
main+0x34 0x00001054    MOVW    R3,#0x8(R13)
main+0x38 0x00001058    BL      print
main+0x3c 0x0000105c    MOVW    $#0x0,R0
main+0x40 0x00001060    BL      exits
main+0x44 0x00001064    RET.P   #0x18(R13)

The problem is that the division at main+0x24
happens regardless of the comparison. The output
from the compiler is correct, however:

term% 5c -S foo.c
        TEXT    main+0(SB),0,$20
        MOVW    $1,R1
        MOVW    $0,R2
        CMP     $0,R2,
        MOVW.LE R1,R3
        MOVW.GT $2,R3
        DIV.GT  R1,R3,R3
        MOVW    $.string<>+0(SB),R0
        MOVW    R3,8(R13)
        BL      ,print+0(SB)
        MOVW    $0,R0
        BL      ,exits+0(SB)
        RET     ,
        DATA    .string<>+0(SB)/8,$"%d\n\z\z\z\z\z"
        GLOBL   .string<>+0(SB),$8
        END     ,

A (temporary) workaround for this is using an
if-else statement, for which the linker generates
correct code.

--
pap


Reply via email to