alignment faults in 3.6

Mans Rullgard mans.rullgard at linaro.org
Fri Oct 5 18:37:40 EDT 2012


On 5 October 2012 17:01, Rob Herring <robherring2 at gmail.com> wrote:
> Here's a testcase. Compiled on ubuntu precise with
> "arm-linux-gnueabihf-gcc -O2 -marm -march=armv7-a test.c".
>
> typedef unsigned short u16;
> typedef unsigned short __sum16;
> typedef unsigned int __u32;
> typedef unsigned char __u8;
> typedef __u32 __be32;
> typedef u16 __be16;
>
> struct iphdr {
>         __u8    ihl:4,
>                 version:4;
>         __u8    tos;
>         __be16  tot_len;
>         __be16  id;
>         __be16  frag_off;
>         __u8    ttl;
>         __u8    protocol;
>         __sum16 check;
>         __be32  saddr;
>         __be32  daddr;
>         /*The options start here. */
> };
>
> #define ntohl(x) __swab32((__u32)(__be32)(x))
> #define IP_DF           0x4000          /* Flag: "Don't Fragment"       */
>
> static inline __attribute__((const)) __u32 __swab32(__u32 x)
> {
>         __asm__ ("rev %0, %1" : "=r" (x) : "r" (x));
>         return x;
> }
>
> int main(void * buffer, unsigned int *p_id)
> {
>         unsigned int id;
>         int flush = 1;
>         const struct iphdr *iph = buffer;
>         __u32 len = *p_id;
>
>         id = ntohl(*(__be32 *)&iph->id);
>         flush = (u16)((ntohl(*(__be32 *)iph) ^ len) | (id ^ IP_DF));
>         id >>= 16;
>
>         *p_id = id;
>         return flush;
> }

The problem is the (__be32 *) casts.  This is a normal pointer to a 32-bit,
which is assumed to be aligned, and the cast overrides the packed attribute
from the struct.  Dereferencing these cast expressions must be done with the
macros from asm/unaligned.h

-- 
Mans Rullgard / mru



More information about the linux-arm-kernel mailing list