Generate Aligned Access Code

Table of Contents

用途

当使用C中的bit field时,编译器在编译时会生成按byte,字长等来访问的指令,对于普通的内存空间,这个都是可以正常使用的。
但是对于ARM平台中的寄存器,由于总线的限制,访问时必须按照32bit来访问, 当使用ldrb访问时,系统会发生异常.

例子

源代码

#include <stdio.h>
#include <stdint.h>

struct device_status {
    union {
        struct {
            uint32_t length : 12;
            uint32_t is_valid : 4;
            uint32_t idx: 8;
        };
        uint32_t value;
    };
} __attribute__((packed, aligned(4)));

volatile struct device_status g_status = {
    .value = 0x1238,
};

void bitfield_test()
{
    printf("status.value = 0x%08x\n", g_status.value);
    g_status.idx++;
    printf("status.value = 0x%08x\n", g_status.value);
}

int main(int argc, char *argv[])
{
    bitfield_test();
    return 0;
}

先看一下数据结构


Normal Compile

在编译时通过指定 -mno-strict-align -fno-strict-volatile-bitfields 的编译参数,来防止编译器版本的不同而进行自动优化。


从上边的汇编代码可以看到,在生成的代码中,系统调用了 ldur指令,这个指令是不带对齐的.

0x0000000000400610 <+44>:   a0 0a 40 39 ldrb    w0, [x21, #2]
0x0000000000400614 <+48>:   00 1c 00 12 and w0, w0, #0xff
0x0000000000400618 <+52>:   00 04 00 11 add w0, w0, #0x1
0x000000000040061c <+56>:   00 1c 00 12 and w0, w0, #0xff
0x0000000000400620 <+60>:   a0 0a 00 39 strb    w0, [x21, #2]

上面这个片段就是从内存中读取g_status.idx 并对其加1操作,最后存入内存中.
上述代码片段中使用了ldrb的指令,在访问AHB接口寄存器的时候,会出现问题。

Compile with aligned access

下面是通过 -mstrict-align -fstrict-volatile-bitfields 参数进行编译的结果:


同样的操作,g_status.idx++;在这里就变成了使用ldr指令的对齐的访问:

Refs

Contact me via :)
虚怀乃若谷,水深则流缓。