Unaligned Accesses

About unaligned accesses

Every now and then one'll see on the console a message like:

php4(16829): unaligned access to 0x200000000068989c, ip=0x40000000001b059

This is caused by the program's accessing an n bit quantity that isn't on an n-bit boundary. The processor has to do extra work to access such variables., so it's best to fix the code to avoid them.

For example, the program below will cause an unaligned access when it tries to read across an 8 byte (64 bit) boundary.

#include <stdio.h>
                                                                                                                       
typedef struct a_struct_t {
        unsigned char a[2];
} a_struct;
                                                                                                                       
void print(const a_struct st) {
        printf("%p -> %c | %p -> %c\n", &st.a[0], st.a[0], &st.a[1], st.a[1]);
}
                                                                                                                       
int main(void)
{
        unsigned char *array = "1234567812345678";
                                                                                                                       
        int i;
                                                                                                                       
        for ( i = 1 ; i < 10 ; i+=2 ) {
                printf("array[%d] %p\n", i, &array[i]);
                print( *((a_struct*)&array[i]) );
        }
        return 0;
}

The compiler will see a_struct should be 2 byte aligned and try to use 2 byte load instructions. The Itanium can handle the unaligned access within an already aligned 8 byte value, but once it tries to read across the values (when i is 7 in the above example) you will get an unaligned access fault.

Handling unaligned accesses

The standard way to get around unaligned accesses is to be careful about alignment (so you don't get into such a situation in the first place), or if that isn't possible (say you're parsing data from the user or from over a network) use memcpy to copy the data to somewhere that is aligned.

The most useful tool for helping with userspace unaligned accesses is the prctl tool.

You can do:

prctl --unaligned=signal gdb program

prctl asks the kernel to generate a SIGBUS when an unaligned access occurs. gdb will catch the signal, and you can get a backtrace to see what's going on.

Alternatively, you can just shut the kenel up (for example, if you don't have source)

prctl --unaligned=silent program

Or you can make that the default for all programs:

prctl --unaligned=silent

Interpreting the Addresses

If the IP address starts with 0xa, the unaligned access is in the kernel or in a module. The networking stack is particularly bad, althugh it is being cleaned up gradually.

To find out what is causing the problem, look in the appropriate System.map file for your kernel (many distributions stash this in /boot/System.map-kernel-version) and look for the symbol whose address is before the faulting address. (Or, if your kernel is compiled with debugging symbols, use addr2line or gdb to find the exact line of code).


Thanks to Khalid Aziz on the Debian-IA64 mailing list for this information.

IA64wiki: UnalignedAccesses (last edited 2009-12-10 03:13:51 by localhost)

Gelato@UNSW is sponsored by
the University of New South Wales National ICT Australia The Gelato Federation Hewlett-Packard Company Australian Research Council
Please contact us with any questions or comments.