1. 数据位宽与对齐 嵌入式开发中,对于移植性来说,数据类型的长度和对齐,是一个很容易出错的问题。 1.1. 对齐 关于什么是对齐,有很多资料,不明白的,可以google,这里不占用篇幅。 先谈谈对齐的问题,不同的系统,有不同的对齐方式,处理不好的话,会给移植带来很大的问题。遗憾的是,许多有经验的程序员都会犯对齐的错误,而且,许多情况下,对齐错误是一个隐含的错误,再详细的测试都测不出来。 下面以arm为例谈谈这个问题,arm要求栈8字节对齐,是因为LDRD/STRD指令要求8字节对齐的操作地址。加入没有遵守8字节对齐,如果编译时没有使用这两条指令,那么程序执行就是正确的。修改一下编译选项(一般是优化选项),编译器可能就选择了使用这两条指令,程序执行就错了。所幸的是,这两条指令被使用的机会,大约只有万分之一~万分之五,因此一般不容易表现出来;不幸的是,这种测试时不容易暴露的问题,是很容易到达用户手中的。如果数据结构中有64位的成员,比如u64,该结构的起始地址,也要求8字节对齐的。 这种错误,即使是国际知名大公司出的例程,都免不了,略举两例: TI公司为他的TMS320C470编写的固件库的启动代码,只做了4字节对齐。我在为帮助用户把djyos移植到OMAPL138的过程中发现了这个问题,并反馈给了TI,得到了TI官方的确认的。你现在看到的、新下载的example,估计就没这个问题了。 在ST官方固件库中,开发工具商RAISONANCE公司为RIDE7提供的工具链,也没有做8字节对齐。大家打开ST官方提供的固件库中,ride目录下的stm32f10x_flash_extsram.ld文件,一看就知。 Djyos为了避免用户写应用程序时犯对齐的错误,做了如下措施: 1、 无论是从堆中分配内存,还是从内存池中分配内存,都做了8字节对齐。只要是使用djyos的内存管理函数分配的内存,可以放心地做各种操作。否则,把动态分配的内存指针强制转换成结构变量访问时,就可能出问题。略举一例: struct abc{ u32 a; u63 b; } u8 buf[1000]; struct abc *ppp; struct mem_cell_pool *my_pool; my_pool = mb_create_pool(…); ppp = (struct abc *)mb_malloc(my_pool); 这段代码,如果内存管理不做对齐,ppp就是一个定时炸弹,运行时会出现不可预知的问题,取决于cpu是否支持不对齐操作,以及编译器给buf分配什么地址。即使cpu支持非对齐操作,运行效率也是大打折扣的。 遗憾的是,像ucosii这样著名的操作系统,都没有注意到这个问题,它要求用户自己提供的内存块首址是对齐的,(参见ucosii的OSMemCreate函数)。如果用户提供了非对齐的地址,你可以认为是用户的错,但是,OS作为“主管部门”,就没有监管责任吗?这样,岂不成了“相关部门”了。而djyos着重于预防应用程序出错的理念,在此展现无遗。 2、 定义了一个按最严格对齐的数据类型: typedef u64 align_type; //arm中,u64能满足所有对齐要求 3、 定义了一些跟对齐相关的常数: #define mem_align 1 //如果目标系统没有对齐要求,改为0 #define align_size 8 //arm(含cm3)要求8字节对齐 4、 定义了一些跟对齐相关的宏操作: #define align_down_sys(x) align_down(8,x) //arm要求8字节对齐 #define align_up_sys(x) align_up(8,x) //arm要求8字节对齐 #define define_align_buf(name,size) align_type name[align_up_sys(size)/sizeof(align_size)] 宏define_align_buf用于定义一个首址符合系统对齐要求的缓冲区。 示例: u8 buf[1000]; struct abc *ppp; ppp = (struct abc *)buf; 这段代码能否正确运行,同样取决于cpu是否支持不对齐操作,以及编译器给buf分配什么地址。但如果把“u8 buf[1000]”改为“define_align_buf(buf,1000)”则没有任何问题。 align_down_sys用于把一个地址向下调整到系统要求的对齐值,align_up_sys则把一个地址向上调整到系统要求的对齐值,define_align_buf用于定义一个数组,其起始地址满足系统对齐要求。 严格使用上述定义设计的应用程序,在不同对齐要求的系统中移植时,只需要修改上述定义即可,源代码完全不用修改。
[ 本帖最后由 djyos 于 2012-8-10 11:47 编辑 ]
|