为什么arm汇编语言教程程序前要加PRESERVE8

【图文】四、ARM汇编语言伪指令_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
四、ARM汇编语言伪指令
上传于|0|0|文档简介
&&四、ARM汇编语言伪指令
大小:293.00KB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢403 Forbidden
403 Forbidden1509人阅读
ARM汇编(6)
简单的实现将一个字符串复制到另外一个字符数组中。拷贝功能在ARM中实现。C语言调用汇编实现。
C语言代码:主要注意要将汇编中的函数导入进来。其余很简单!我这样赋值方便以后调试的时侯方便。
#include &stdio.h&
extern void strcopy(char *d, const char *s);
int main()
const char *srcstr=&abcdefghi&;
char dststr[]=&ighfedcba&;
strcopy(dststr,srcstr);
ARM汇编代码:在此汇编代码中,主要是注意将拷贝函数导出,将C语言main函数导入,注意在调试的时候你会发现,R0,R1寄存器存储的是两个传入参数的存储地址,所以后期通过LDR和STR即可实现,主要是要不断的调试你就会熟悉这个参数是怎么传入的,还有就是注意通过寻址观察目标字符数组的变化,是否复制成功。
STACK_TOP EQU 0x
AREA SCopy, CODE, READONLY
EXPORT START
EXPORT strcopy
import main
LDR R13,=STACK_TOP
LDRB r2, [r1],#1
STRB r2, [r0],#1
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:7962次
排名:千里之外1262人阅读
C/C++(96)
REQUIRE8 and PRESERVE8
The&REQUIRE8&and&PRESERVE8&directives
specify that the current file requires or preserves eight-byte alignment of the stack.
The&REQUIRE8&directive sets the REQ8 build attribute to inform the linker.
The&PRESERVE8&directive sets the PRES8 build attribute to inform the linker.
The linker checks that any code that requires eight-byte alignment of the stack is only called, directly or indirectly, by code that preserves eight-byte alignment of the stack.
一、什么是栈对齐?
栈的字节对齐,实际是指栈顶指针须是某字节的整数倍。因此下边对系统栈与MSP,任务栈与PSP,栈对齐与SP对齐 这三对概念不做区分。另外下文提到编译器的时候,实际上是对编译器汇编器连接器的统称。
之前对栈的8字节对齐理解的不透,就在网上查了好多有关栈字节对齐、还有一些ARM对齐伪指令的资料信息,又做了一些实验,把这些零碎的信息拼接在一起,总觉得理解透这个问题的话得长篇大论了。结果昨天看了AAPCS手册、然后查到了没有使用PRESERVE8伪指令出现错误的实例,突然觉得长篇大论不存在了,半篇小论这问题就能理顺了。
二、AAPCS栈使用规约
在ARM上编程,但凡涉及到调用,就需要遵循一套规约AAPCS:《Procedure Call Standard for the ARM Architecture》。这套规约里面对栈使用的约定如下:
Universal stack constraints&
At all times the following basic constraints must hold:&
Stack-limit & SP &= stack-base. The stack pointer must lie within the extent of the stack.&
SP mod 4 = 0. The stack must at all times be aligned to a word boundary.&
A process may only access (for reading or writing) the closed interval of the entire stack delimited by [SP, stack-base – 1] (where SP is the value of register r13).&
This implies that instructions of the following form can fail to satisfy the stack discipline constraints, even when reg points within the extent of the stack.&
ldmxx reg, {..., sp, ...} // reg != sp&
If execution of the instruction is interrupted after sp has been loaded, the stack extent will not be restored, so restarting the instruction might violate the third constraint.&
Stack constraints at a public interface&
The stack must also conform to the following constraint at a public interface:&
SP mod 8 = 0. The stack must be double-word aligned.
可以看到,规约规定,栈任何时候都得4字节对齐,在调用入口得8字节对齐。
在这个约定里,栈的4字节对齐确实得任何时候都遵守,而且你想不遵守都难,因为SP的最后两位是硬件上保持0的。而对于8字节对齐,这就需要码农和编译器配合着来。需要说明的一点是,8字节对齐即使不遵守,一些情况下也没问题,只要主调和被调用例程两边把堆栈使用,传参,返回等处理好就行,也就是说两边有自己的一套约定就行。但是有时候,主调这边在调用严格遵守AAPCS的函数时,没有将栈保持在8字节对齐上,那就会出问题。
三、如何编程?
在cortex m3上编程时,对于AAPCS栈使用约定的遵守,总的来说就两条:
1. 汇编文件中需要我们亲自动手来保证遵守AAPCS栈使用约定。
(特别注意每次从汇编进入C的世界时,要保证汇编部分的编码在调用c接口时栈是8字节对齐的,不要疏忽了,因为c编译器可不负责调整。c编译器说你得送给我的SP就是8字节对齐的,我才能保证接下来的C部分没有结束之前,遵守AAPCS栈使用约定)
2. 在C文件中,由编译器来处理。
四、补充:
1. 由于程序的入口点为复位中断响应函数,一般我们都写在启动代码里,通常是一个汇编文件,然后经由汇编进入到C程序的main入口处,在调用main的时刻,为遵循AAPCS,就得在此时保持8字节对齐。
2. 对于MSP,Keil MDK为我们提供了一个用来初始化C运行库环境的函数_main,这个函数会调用_user_setup_stackheap函数,该函数将MSP的低三位清零,然后在进入main之前不对其进行更改,这样在进入main的时刻,MSP保证为8字节对齐的。
3. 对于PSP,一般在上多任务OS时会用它,对于PSP我们要比MSP更为操心点,因为MSP起码还可以通过调用_main来跳进main的方式保证进入C世界的时候是遵守约定的。而PSP全靠自己来保证每次进入C世界时是8字节对齐。
4. 另外只要是汇编文件,可配合使用汇编命令armasm --diag_warning 1546,这样汇编器就会对一些SP没有8字节对齐的地方给出警告,但是我发现汇编器并不能保证检测到所有对SP造成8字节不对齐的操作,例如直接给SP载入一个立即数这种,汇编器就发现不了。我并没有对所有会影响SP的指令进行测试(原因是不熟悉。。。),不知道1546这个警告能覆盖多少指令,所以总的来讲,对汇编文件就是睁大自己的钛合金眼,争取大部分工作都放到C中去。
五. CORTEX-M3 中断控制器的栈对齐调整功能(该功能在r2p0版本以后的内核中均默认开启,STKALIGN位默认为1)
Cortex M3 NVIC CCR寄存器(控制与配置寄存器)的STKALIGN位置1,那么在发生中断时,进入中断响应函数前,内核会首先检查当前正在使用的栈指针是否8字节对齐,如果是,则正常将xPSR,PC,LR,SP,R0-R3入栈,如果不是,则先把SP-4,调整为8字节对齐,然后将xPSR第九位置1,接着把xPSR,PC,LR,SP,R0-R3入栈,再然后才进入中断响应函数。这样可以保证程序在运行过程中,如果在栈没有发生4字节对齐的地方发生中断了,进入到中断响应函数的时候也是遵守AAPCS栈使用约定的。如果中断服务程序是做任务切换的,那么前面的情况就是将任务栈调整为对齐,然后进入异常服务程序后使用系统栈,那如果系统栈本来就是不对齐的呢?通过中断来做任务切换的情况下,中断控制器并不会对系统栈进行调整,怎么办?其实这也不用担心,以μC/OS-II为例,在cortex-m3上通常使用PendSV异常来做任务切换,即将OSCtxSw以及OSIntCtxSw都设为仅完成PendSV异常触发功能,然后在PendSV异常服务程序中进行任务切换。由于上电时刻系统处于特权级模式,只要我们保证从上电开始到第一次系统调用,使用的栈都是系统栈MSP就可以了,这样即使第一次要进入任务切换时MSP不对齐,中断向量控制器也会给调整为8字节对齐状态,虽然这个第一次任务切换后除了中断再也不会使用MSP,但只要我们同时保证所有汇编部分都不会破坏8字节对齐规约,那么从此以后MSP都会是8字节对齐的。
六、关于ALIGN属性 与 PRESERVE8伪指令
在CORTEX M3芯片的启动代码中,这两个伪指令并非必不可少,可以不要这两个伪指令。但是有了这两个伪指令,可以在确保遵守AAPCS的道路上加一道保险,使得AAPCS栈使用约定的遵守在实际编程时变得稍微容易点。
当在段定义头(即AREA伪指令的相关代码)当中使用ALIGN=?时,ALIGN属性的作用为设定该代码段或数据段的首址的对齐位置,例如ALIGN=3就表示,该段首址将被安排在2^3=8字节对齐处。需要注意的是,除了AREA的ALIGN属性,还有一个同名的ALIGN指令,ALIGN指令使用在段内部的,用来调整ALIGN指令下一条命令或数据的对齐位置。
而PRESERVE8伪指令并不会对栈进行任何修改。PRESERVE8伪指令的使用有四种方法,分别如下,其中1、2的用法是等价的:
1.&&&&&&& PRESERVE8
2.&&&&&&& PRESERVE8 {TRUE}
3.&&&&&&& PRESERVE8 {FALSE}&&&
如果不写,那么由编译器来决定在编译过程中将汇编文件标识为PRES8属性还是~PRES8属性(也即加还是不加该伪指令),但经过实验,发现编译器在加不加这条伪指令上表现的并不完全可靠。。。所以最好明确的加上是 PRESERVE8 {TRUE}还是PRESERVE8 {FALSE}。那么这条伪指令起什么作用呢?
如果你想要告诉汇编器说:“在我这个汇编文件中保证栈的8字节对齐,我这个文件对栈的任何时刻的任何操作都是8字节对齐的”,那么你就把PRESERVE8伪指令用在汇编文件中,用以向汇编器通知前面你的保证内容。汇编器就知道你这个汇编文件是8字节对齐靠谱选手,将该文件标识为PRES8属性,然后如果在你这个汇编中调用了标示了需要8字节对齐属性的文件中的函数,连接的时候就不会报错。但是假如你把这个汇编文件标示为PRESERVE8
{FALSE},然后你又在这个文件中调用了标示了需要8字节对齐属性的文件中的函数,连接时就会给出错误信息。
那么什么是标示了需要8字节对齐属性的文件呢?如果你的某个汇编文件,某些操作一定要栈8字节对齐才行,那么你就需要使用REQUIRE8伪指令来通知汇编器将该文件标识为REQ8属性,然后这个文件就是所谓的“标示了需要8字节对齐属性的文件”。
在文件较多,文件之间调用由繁多的情况下,通过PRESERVE8和REQUIRE8的配合,就能够在连接期间由编译器检查出我们写代码时不小心造成的破坏8字节对齐模块对需要8字节对齐模块的调用(经过实验发现,汇编之间是给出警告,汇编调用C则是给出错误,由于C文件中并不能直接用REQUIRE8,所以我猜编译器将C文件都通通标识为REQ8属性了,所以才会出错)。
REQUIRE8的用法同PRESERVE8。
/reload/archive//3159053.html
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:148894次
积分:2827
积分:2827
排名:第11089名
原创:106篇
转载:223篇
(2)(23)(11)(3)(12)(10)(3)(7)(8)(10)(4)(15)(6)(8)(15)(10)(11)(10)(36)(14)(16)(29)(7)(13)(9)(2)(1)(1)(1)(3)(7)(7)(9)(15)

我要回帖

更多关于 arm汇编 的文章

 

随机推荐