gcc结构体对齐的误用

    最近对一段声卡裸板程序进行调试时发现了一个结构体对齐误用的错误。在接有wm8976的s3c2440开发板上调试裸板程序,用来解析并播放NandFlash上的wav二进制数据,使用dma传输数据到iis接口,并在传输完毕后触发中断再次传输。然而结果是既没有声音,dma中断也没有被触发,以为是dma的设置出错,经过反复试验后,将问题定位到了iis的部分代码:
struct i2s_regs
{
    unsigned long iiscon; //0x55000000
    unsigned long iismod;
    unsigned long iispsr;
    unsigned long iisfcon;
    unsigned long iisfifo;
}__attribute__((packed));

static volatile struct i2s_regs* i2sregs;
void i2s_init(unsigned int bits_per_channel,unsigned int samp_per_second)
{
    int i;
    int min = 0xffff;
    unsigned int tmp_fs;
    unsigned int pre = 0;

    i2sregs = (struct i2s_regs*)0x55000000;

    GPECON &= ~0x3ff;
    GPECON |=  0x2aa;

    if(bits_per_channel == 16)
    {
        i2sregs->iismod  =  (2<<6) | (1<<3) | (1<<2) | (1);
    }else{
        i2sregs->iismod  =  (2<<6) | (0<<3) | (1<<2) | (1);
    }

     for(i = 0;i < 32;i++)
     {
        tmp_fs = PCLK/384/(i+1);
        if(ABS(tmp_fs,samp_per_second) < min)
        {
            min = ABS(tmp_fs,samp_per_second);
            pre = i;
        }
     }

    i2sregs->iispsr  = (pre<<5) | pre ;
    i2sregs->iisfcon = (1<<15) | (1<<13) ;
    i2sregs->iiscon  =  (1<<5) | (1<<1);
}
   将结构体指针指向iis寄存器的首地址,通过该结构体指针来访问设置iis寄存器,去掉attribute__ ((packed)) 的属性描述符后成功运行了程序,那么为什么会出现这种问题呢?
因为attribute__ ((packed)) 的属性描述符的作用是不进行结构体成员的对齐,在内存中按成员的大小依次排列各成员,按理说 这五个成员都是unsigned long 类型,本身就是4字节对齐的,无论加不加上attribute__ ((packed)) 的属性描述符编译出来的结果都应该是一样的,也就是说结构体的所占大小应该都是20,加上打印语句后也是20。那么会不会是指针赋值的时候出了问题呢?i2sregs = (struct i2s_regs*)0x55000000;寄存器的首地址本身也是4字节对齐的,也不会出错,对每个结构体成员进行取址,得到的结果也都和芯片手册上写的一致,那么说明结构体指针映射没有问题,只可能是对它们进行赋值的时候出了问题了,这种情况下也只有查看反汇编的代码来看看究竟了。使用arm-linux-objdump对elf进行反汇编,分别得到加上属性描述符与不加的代码,来进行分析。

    这是不加上attribute__ ((packed) 属性描述符的代码,忽略掉值的计算等指令,只寻找最后赋值的指令可以大致发现,对每个结构体成员(寄存器)进行最后的写入时,使用的都是str指令。
33f80860 <i2s_init>:
33f80860:   e92d41f0    push    {
  r4, r5, r6, r7, r8, lr}
33f80864:   e3a03455    mov r3, #1426063360 ; 0x55000000
33f80868:   e59f80d0    ldr r8, [pc, #208]  ; 33f80940 <i2s_init+0xe0>
33f8086c:   e1a04000    mov r4, r0
33f80870:   e1a06001    mov r6, r1
33f80874:   e59f00c8    ldr r0, [pc, #200]  ; 33f80944 <i2s_init+0xe4>
33f80878:   e1a01003    mov r1, r3
33f8087c:   e5883000    str r3, [r8]
33f80880:   eb000279    bl  33f8126c <printf>
33f80884:   e3a01456    mov r1, #1442840576 ; 0x56000000
33f80888:   e5913040    ldr r3, [r1, #64]
33f8088c:   e3c33fff    bic r3, r3, #1020   ; 0x3fc
33f80890:   e3c33003    bic r3, r3, #3  ; 0x3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值