views:

127

answers:

3

Hi,

consider the following Objective-C++ iPhone Application (TestMemAppDelegate.mm). It crashes with an EXC_BAD_ACCESS on the iPhone (3GS with iOS 4.0). It works fine in the Simulator. It is clearly a memory alignment thing, because it works fine on the iPhone if the "DataA" struct starts on a 8 Byte border.

Can anyone explain the cause? Is it something with the ARM architecture? ARM compiler?

@implementation TestMemAppDelegate


typedef struct DataA
{
 float    x;
 unsigned char  y;
};


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

 char* mem1 = (char*)malloc(4096);

 DataA* ptrA = (DataA*)(mem1 + 1); // Here we shift the alignment
 ptrA->x = 10.0f;
 printf("A: %.2f\n", ptrA->x); // Here it crashes



    // Add the view controller's view to the window and display.
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];

    return YES;
}


@end
A: 

Float generally has to be 4-byte aligned at least.

EJP
+4  A: 

Yes it's an alignment issue. A float needs to be 4-byte aligned. An Intel x86 CPU allows mis-aligned access (but at a performance penalty). On ARM it is not allowed and generates the error you see.

irlennard
Thanks. Based on your answer I found it in the documentation: http://www.keil.com/support/man/docs/ca/ca_ap_byte_alignment.htm
Lars Schneider
A: 

I think you'll find that it's a violation of the C (and presumably C99) standard. malloc() guarantees to return suitably-aligned memory, so you can do something like

struct DataA * foo = (struct DataA *)malloc(sizeof(struct DataA));
foo->x = 10;

There are alignment requirements, though, so it's not guaranteed that you can arbitrarily modify the pointer and have it still work.

That said, the OS can allow misaligned memory access by catching the exception and performing the memory access manually. On PowerPC, the CPU handles misaligned integer accesses, but expects the OS to handle misaligned floating point accesses.

Finally, you might manage to get it to work using the GCC extension __attribute__((packed)):

struct foo {
  ...
} __attribute__((packed));

This has two effects:

  • Variables in the struct have alignment 1 (this may change the memory layout of your struct)
  • The struct has alignment 1 (i.e. the compiler no longer will align it when you stick it in another struct, for example)

This might mean that GCC generates the code necessary to perform the misaligned load. But why would you want to do this?

tc.