Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Indicating unaligned access to Clang for ARM compatibility

Tags:

c

gcc

clang

arm

I'm parsing a file format by mapping a file to memory and accessing it through C struct definitions. The file format uses packed structures, so I cannot guarantee that a field will align to a word boundary.

The parsing works just fine, unfortunately in certain cases the optimizer may wreak havoc. In particular, compiling for armv7 there are certain load instructions that require word alignment and others that do not. Consider this snippet:

#define PACKED __attribute__((packed))

typedef struct PACKED _Box_mvhd {
    union {
        struct {
            int32_t creation_time;
            int32_t modification_time;
            int32_t time_scale;
            int32_t duration;
            ...
        } v0;
    } data;
} Box_mvhd;

Container mvhd = find_single_box(&moov, 'mvhd');
if (mvhd.boxStart) {
    Box_mvhd *mvhdBox = mvhd.mvhd;
    if (0 == mvhdBox.box.version) {
        uint32_t ts = ntohl(mvhdBox->data.v0.time_scale);
        uint32_t dur = ntohl(mvhdBox->data.v0.duration);
        ...
    }
}

In -O0 (debugging) the innermost block is emitted as the following assembly, which works properly:

ldr r1, [r0, #24]
ldr r2, [r0, #20]

In -O2 however the compiler realizes these fields are adjacent and generates this assembly:

ldrdeq  r2, r3, [r0, #20]

Unfortunately LDRD always generates an alignment fault (by spec and in practice). So I need a way to inform the compiler of this issue effectively. Ideally this could be done with an attribute on the struct. It's also possible that this is a bug with the compiler or ARM backend, but I'll give them the benefit of the doubt.

I'm compiling with Xcode 4.2 (clang 3.0) targeting armv7 for iPhone.

like image 360
mjr Avatar asked Sep 05 '25 03:09

mjr


1 Answers

The issue isn't that the fields of the struct don't have the required alignment, it's that you're casting an arbitrary pointer to a pointer to your struct, and the pointer you're casting doesn't have the required alignment of the struct. Strictly speaking this is undefined behavior.

Instead, memcpy your data from the source buffer to your struct. memcpy is fast, and guaranteed to handle whatever alignment you throw at it.

like image 162
Stephen Canon Avatar answered Sep 09 '25 19:09

Stephen Canon