ARM 编译程序通常将全局变量对齐到自然尺寸边界上,以便通过使用 LDR和 STR 指令有效地存取这些变量。这种内存访问方式与多数 CISC (Complex Instruction Set Computing)体系结构不同,在CISC体系结构下,指令直接存取未对齐的数据。因而,当需要将代码从CISC 体系结构向 ARM 处理器移植时,内存访问的地址对齐问题必须予以注意。在RISC体系结构下,存取未对齐数据无论在代码尺寸或是程序执行效率上,都将付出非常大的代价。
本文将从以下几个方面讨论在ARM体系结构下的程序设计问题。
未对齐的数据指针
C和C++编程标准规定,指向某一数据类型的指针,必须和该类型的数据地址对齐方式一致,所以ARM 编译器期望程序中的 C 指针指向存储器中字对齐地址,因为这可使编译器生成更高效的代码。
比如,如果定义一个指向 int 数据类型的指针,用该指针读取一个字,ARM 编译器将使用LDR 指令来完成此操作。如果读取的地址为四的倍数(即在一个字的边界)即能正确读取。但是,如果该地址不是四的倍数,那么,一条 LDR 指令返回一个循环移位结果,而不是执行真正的未对齐字载入。循环移位结果取决于该地址向对于字的边界的偏移量和系统所使用的端序(Endianness)。例如,如果代码要求从指针指向的地址 0x8006 载入数据,即要载入 0x8006、0x8007、0x8008 和 0x8009 四字节的内容。但是,在 ARM 处理器上,这个存取操作载入了0x8004、0x8005、0x8006 和 0x8007 字节的内容。这就是在未对齐的地址上使用指针存取所得到的循环移位结果。
因而,如果想将指针定义到一个指定地址(即该地址为非自然边界对齐),那么在定义该指针时,必须使用 __packed 限定符来定义指针: 例如,
__packed int *pi; // 指针指向一个非字对其内存地址
使用了_packed限定符限定之后,ARM 编译器将产生字节存取命令(LDRB或STRB指令)来存取内存,这样就不必考虑指针对齐问题。所生成的代码是字节存取的一个序列,或者取决于编译选项、跟变量对齐相关的移位和屏蔽。但这会导致系统性能和代码密度的损失。
值得注意的是,不能使用 __packed 限定的指针来存取存储器映射的外围寄存器,因为 ARM 编译程序可使用多个存储器存取来获取数据。因而,可能对实际存取地址附近的位置进行存取,而这些附近的位置可能对应于其它外部寄存器。当使用了位字段(Bitfield)时, ARM 程序将访问整个结构体,而非指定字段。
在ARM中,通常希望字单元的地址是字对齐的(地址的低两位为0b00),半字单元的地址是半字对齐的(地址的最低为0b0).在存储访问操作中,如果存储单元的地址没有遵守上述的对齐规则,则称为非对齐(unaligned)的存储访问操作.
转载自:ARM开发板|嵌入式开发http://armdmc.woku.com/article/5018028.html
———————————————— END ————————————————
自修改代码指的是代码在执行过程种可能修改自身.对于支持指令预取的ARM系统,自修改代码可能带来潜在的问题.当指令被预取后,在该指令被执行前,如果有数据访问指令修改了位于主存种的该指令,这是被预取的指令和主存种对应的指令不同,从而可能使执行的结果发生错误.
上一篇:ARM处理器寄存器和汇编指令系统
下一篇:ARM基础知识教程二:ARM处理器的寄存器
推荐阅读最新更新时间:2024-03-16 14:58