alignment faults in 3.6

Mans Rullgard mans.rullgard at linaro.org
Tue Oct 9 10:18:58 EDT 2012


On 9 October 2012 15:05, Scott Bambrough <scott.bambrough at linaro.org> wrote:
> On 12-10-05 12:01 PM, Rob Herring 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. */
>> };
>
>
> I was reading this thread with some interest.  AFAIK, with the default
> alignment rules the above struct is packed; there will be no holes in it.

Correct.  The problem here is that something is passing around a pointer to
such a struct which is not 4-byte aligned as required by the ABI rules.

>> #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);
>
>
> The above statement is the problem.  I think it is poorly written networking
> code.  It takes the address of a 16 bit quantity (aligned on a halfword
> address),

The 'id' member starts 4 bytes into the struct, so if the struct is properly
aligned, there will be no fault here.  The problem is that networking code does
not always align these structs correctly.

> attempts to do a type conversion using pointers, then dereference
> it.  I would have thought:
>
> id = ntohs(iph->id);
>
> would have been enough.

I'm assuming the is intentionally merging two 16-bit fields into one 32-bit
value.  What you suggest would do something rather different.

-- 
Mans Rullgard / mru



More information about the linux-arm-kernel mailing list