gcc miscompiles csum_tcpudp_magic() on ARMv5

Maxime Bizon mbizon at freebox.fr
Thu Dec 12 09:10:10 EST 2013


On Thu, 2013-12-12 at 13:48 +0000, Måns Rullgård wrote:

> In the code above, the outer (uint16_t) cast should clear the top half,
> as should passing the value to a function (inline doesn't alter the
> semantics) as a 16-bit type, so there's something fishy here.

using __attribute__((noinline)), or putting the function in another file
makes the bug disappear

But I'm not convinced inline doesn't change the semantic, since gcc is
merging the function inside another one the rules of calling convention
should not matter anymore.

I attached a second test case without a separate function that has the
same bug.

> Which gcc versions did you try?

4.3.2, 4.6.0, 4.7.2, 4.8-2013 (linaro)

Here is a simple userspace test case.


#include <stdint.h>
#include <stdio.h>

static inline uint32_t asm_add(uint16_t len, uint32_t sum)
{
        __asm__(
        "add    %0, %1, %2 \n"
        : "=&r"(sum)
        : "r" (sum), "r" (len)
        );
        return sum;
}

#define local_swab16(x) ((uint16_t)(                                    \
        (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) |                  \
        (((uint16_t)(x) & (uint16_t)0xff00U) >> 8)))

int main(int argc, char *argv[])
{
        uint16_t foo;

        foo = strtoul(argv[1], NULL, 0);
        printf("%08x\n", asm_add(local_swab16(foo), 0));
        return 0;
}

without optimization, or with noinline:

# ./a.out 0x3412
00001234


with optimization:

# ./a.out 0x3412
00341234


And the second test case without the inline function.

int main(int argc, char *argv[])
{
        uint32_t sum = 0;
        uint16_t foo;

        foo = strtoul(argv[1], NULL, 0);

        __asm__ (
        "add    %0, %1, %2 \n"
        : "=&r"(sum)
        : "r" (sum), "r" (local_swab16(foo))
        );

        printf("%08x\n", sum);
        return 0;
}


-- 
Maxime





More information about the linux-arm-kernel mailing list