通过LDMFD/STMFD指令实现R和R6寄存器数据的交换

361 篇文章 ¥29.90 ¥99.00
本文介绍了如何在ARM汇编语言中利用LDMFD和STMFD指令实现R寄存器与R6寄存器之间的数据交换,详细解释了这两个指令的工作原理,并提供了相应的汇编代码示例。

在ARM汇编语言中,LDMFD(Load Multiple Registers and Increment After)和STMFD(Store Multiple Registers and Decrement Before)指令可以用于在寄存器之间传输数据。这些指令可以通过适当的操作实现R寄存器和R6寄存器之间数据的交换。本文将详细介绍如何使用这些指令来实现交换,并提供相应的源代码。

首先,让我们来了解一下LDMFD和STMFD指令的用法和工作原理。

LDMFD指令用于从内存中加载多个寄存器的值,并在加载后递增堆栈指针。它的基本语法如下:

LDMFD Rn!, {Rlist}

其中,Rn是一个基地址寄存器,用于指定要加载的数据的内存地址;Rlist是一个寄存器列表,用于指定要加载的寄存器。

STMFD指令用于将多个寄存器的值存储到内存中,并在存储前递减堆栈指针。它的基本语法如下:

STMFD Rn!, {Rlist}

其中,Rn是一个基地址寄存器,用于指定要存储的数据的内存地址;Rlist是一个寄存器列表,用于指定要存储的寄存器。

现在我们将使用LDMFD和STMFD指令来实现R寄存器和R6寄存器之间的数据交换。假设我们有以下的汇编代码:

        LDMFD R0!, {R1-R5}    ; 将R0-R4的值加载到寄存器R1-R5
        STMFD R6!, {R1-R5}    ; 将R1-R5的值存储到R6-R10的内存位置
        LDMFD R6!, {R1-R5}    ; 将R6-R10的值加载到寄
AREA ExampleProgram, CODE, READONLY ENTRY MAIN MOV R1, #0x10 MOV R2, #0x20 MOV R3, #0x30 LDR SP, =StackUser+29*4 ; 设置好堆栈指针 BL SUB1 ; 调用子程序SUB1,把返回地址(B . 这条指令的地址) ; 存放到LR中 B . SUB1 STMFD SP!, {R0-R7,LR} ;满递减堆栈 ;保存寄存器的顺序:LR,R7,...,R0 MOV R3, R1 ; 0x10,0x10 MOV R1, R2 ; 0x20,0x20 MOV R2, R3 ; 0x10,0x10 ;R1R2的内容交换,R3是中间暂存 BL DELAY ; 调用子程序DELAY,把返回地址 ; (LDMFD SP!, {R0-R7,PC} 的地址)保存在LR中 LDMFD SP!, {R0-R7,PC} ; 恢复寄存器的顺序是R0,...,R7,LR=>PC ; LR=>PC引起处理器跳转到B .指令处执行 ;SUB1子程序结束 DELAY MOV R3, #100 ;控制循环次数的循环变量 DELAY_L1 SUBS R3, R3, #1 ;S的作用是设置CPSR的Z位 ; 减的结果为0,则设置CPSR[Z]=1 BNE DELAY_L1 ;循环体执行100次 ;减的结果不等于0则循环继续,否则退出循环 MOV PC, LR ;跳转到BL DELAY的下一条指令 AREA MyStacks, DATA, READWRITE StackUser SPACE 30*4 ; SPACE伪指令,分配120个字节的存储单元,初始化为0,首地址为StackUser END 1. 在程序执行BL SUB1之前,R1、R2、R3中寄存的值分别是什么(填写十六进制数据)? 2. 在程序执行完BL SUB1之后,R1、R2、R3中寄存的值分别是什么(填写十六进制数据)? 3. 在执行子程序SUB1时,在执行BL DELAY指令之前,执行MOV R2, R3指令之后,R1、R2、R3中寄存的值是什么(填写十六进制数据)? 4. 写出本程序中的循环结构的代码,该循环结构的循环体执行了多少次? 5. 如果把标号DELAY_L1处的指令SUBS R3, R3, #1改成SUB R3, R3, #1,程序的功能会发生怎样的变化?发生这种变化的原因是什么? S 设置CPSR 的条件码标志位 NZCV,Z=0时,条件NE成立 6. BL指令B指令有何异同?
最新发布
06-08
<think>我们正在分析一个ARM汇编程序。首先,我们逐步执行代码并记录寄存器的变化。程序入口是MAIN。1.MAIN部分:-MOVR1,#0x10→R1=0x10-MOVR2,#0x20→R2=0x20-MOVR3,#0x30→R3=0x30-LDRSP,=StackUser+29*4;设置堆栈指针,指向StackUser区域偏移29*4(即116字节)的位置。因为SPACE30*4分配了120字节,所以StackUser+116是堆栈的顶部(满递减堆栈)。-BLSUB1;调用子程序SUB1:将下一条指令(即B.)的地址保存到LR,然后跳转到SUB1。2.SUB1子程序:-STMFDSP!,{R0-R7,LR};将R0到R7以及LR(返回地址)压入堆栈(满递减堆栈,所以先减小SP,然后存储)。注意:压栈顺序是R0到R7LR,但因为是满递减,存储顺序是LR(最高地址)然后R7到R0(最低地址)。但是,由于我们只关心R1,R2,R3,注意它们被保存了,但是后面又被修改了。-然后执行:MOVR3,R1;R3=R1=0x10MOVR1,R2;R1=R2=0x20MOVR2,R3;R2=R3=0x10因此,交换了R1R2的值。此时:R1=0x20R2=0x10R3=0x10(注意:R3最初是0x30,但被覆盖为0x10)-然后调用BLDELAY:将返回地址(即LDMFD指令的地址)存入LR,然后跳转到DELAY。3.DELAY子程序:-MOVR3,#100;R3=100-DELAY_L1:SUBSR3,R3,#1;R3减1,并设置标志位(如果结果为0,则Z标志置1)BNEDELAY_L1;如果结果不为0(Z=0)则循环循环100次后,R3变为0,然后退出循环。-MOVPC,LR;返回到SUB1中的BLDELAY的下一条指令(即LDMFD指令)。4.返回SUB1:-执行LDMFDSP!,{R0-R7,PC};从堆栈中弹出R0-R7以及LR(但这里弹出到PC,所以同时返回)。注意:在STMFD时,我们压入了R0-R7LR。而LDMFD会按顺序弹出到R0-R7PC(因为PC对应的是之前压入的LR,即返回地址)。这样,程序就返回到MAIN中BLSUB1的下一条指令,即“B.”(无限循环)。但是,注意在SUB1中我们修改了R0-R7,包括R1,R2,R3,然后通过堆栈恢复了它们(因为压入了R0-R7并在返回时弹出)。所以在返回到MAIN后,R0-R7的值应该调用SUB1之前一样(除了被修改的R0-R7在SUB1中被修改,但恢复后变回原值?不,这里在SUB1中压栈时,R0-R7被保存,然后我们在SUB1中修改了它们,但是最后通过弹栈又恢复了。所以调用SUB1不会改变MAIN中的R0-R7,包括R1,R2,R3。但是,注意在SUB1中,我们只修改了R1,R2,R3(还有R3被用于暂存),而R0,R4-R7没有被修改(但是也保存了,所以恢复的时候还是原来的值)。然而,在DELAY中,我们修改了R3(赋值为100,然后减到0),但是DELAY结束后没有恢复(因为DELAY是叶子程序,没有保存寄存器)。所以,在SUB1中,在调用DELAY后,R3的值变为0(因为DELAY中R3被修改了)。但是在SUB1的最后,我们通过LDMFD恢复了之前保存的寄存器(包括R3)。所以,在SUB1中,执行DELAY后,R3的值是0,但是当我们弹出堆栈时,R3被恢复为进入SUB1之前的值(即0x30,因为MAIN中初始化的是0x30,而进入SUB1后,STMFD保存了包括R3在内的所有寄存器)。因此,在SUB1中,执行完DELAY后,R3的值是0,但是接着LDMFD会恢复R3(以及R0-R7)为进入SUB1时的值(也就是MAIN中的值:R1=0x10,R2=0x20,R3=0x30)。所以在返回到MAIN后,R1,R2,R3的值还是0x10,0x20,0x30。但是,这里有一个细节:在SUB1中,我们做了交换,但是交换的只是R1R2,并且使用了R3作为临时寄存器。在交换后,R3被修改为0x10,然后我们调用DELAY,在DELAY中R3被修改为0。然后在SUB1的LDMFD指令中,我们从堆栈中弹出原来的R3(0x30)到R3,所以R3恢复为0x30。因此,在SUB1中,执行BLDELAY之前,执行MOVR2,R3之后,R1,R2,R3的值分别是:R1=0x20,R2=0x10,R3=0x10但是,在DELAY执行后,R3变为0。而在SUB1返回前(LDMFD之前),R1,R2,R3的值是:R1=0x20,R2=0x10,R3=0(因为DELAY修改了R3)。然后,LDMFD恢复R0-R7(包括R3恢复为0x30)PC。所以,在MAIN中,执行完BLSUB1后,R1,R2,R3的值没有变化,还是0x10,0x20,0x30。现在,我们回答问题:1.在程序执行BLSUB1之前,R1、R2、R3的值分别是?R1=0x10R2=0x20R3=0x302.在程序执行完BLSUB1之后,R1、R2、R3的值分别是?由于在SUB1中修改了R1,R2,R3,但最后通过堆栈恢复了,所以还是0x10,0x20,0x30。3.在执行子程序SUB1时,在执行BLDELAY指令之前,执行MOVR2,R3指令之后,R1、R2、R3中寄存的值是什么?此时已经完成了交换:R1=0x20R2=0x10(因为R3的值是0x10,所以MOVR2,R3后,R2=0x10)R3=0x10(在MOVR2,R3之前,R3已经由MOVR3,R1设置为0x10)4.循环结构的代码是DELAY中的循环:DELAY_L1:SUBSR3,R3,#1BNEDELAY_L1该循环的循环体执行了100次(因为一开始设置R3=100,每次减1,直到0,循环100次)。5.如果把SUBS改为SUB(不带S后缀),那么循环条件判断会出错。因为SUB指令不会设置标志位,所以后面的BNE指令会使用之前操作的标志位,这可能导致循环次数不正确(甚至无限循环)。因为BNE判断的是Z标志,而Z标志由上一条影响标志位的指令设置(SUBS会设置,而SUB不会)。因此,改为SUB后,BNE使用的可能是之前操作的标志,导致循环次数错误。6.BLB指令的异同:-相同点:两者都是跳转指令,用于改变程序执行流程。-不同点:BL指令在跳转之前会将返回地址(下一条指令的地址)保存到LR寄存器中,用于子程序返回;而B指令只是单纯的跳转,不保存返回地址。因此,BL用于函数调用,B用于无条件跳转。现在,我们按问题顺序回答:问题1答案:R1=0x10,R2=0x20,R3=0x30问题2答案:R1=0x10,R2=0x20,R3=0x30问题3答案:R1=0x20,R2=0x10,R3=0x10问题4答案:循环代码是SUBSBNE两条指令,循环体执行100次。问题5答案:如果改为SUB,循环体可能不会执行100次(因为不设置标志位,BNE使用的是之前的标志位),可能导致死循环或者提前退出。原因就是SUB不设置条件标志位,BNE使用的标志位是旧的,可能不是基于当前减法结果。问题6答案:BL指令在跳转前将返回地址存入LR,用于子程序返回;B指令仅跳转,不保存返回地址。注意:在回答中,我们假设堆栈操作正确,且没有其他影响。在ARM中,STMFDLDMFD是满递减堆栈操作。§§相关问题§§:1.ARM汇编中,STMFDLDMFD指令是如何工作的?请解释压栈出栈的具体过程。2.在ARM的汇编子程序中,通常需要保存哪些寄存器?为什么?3.条件执行(如SUBS中的S后缀)在ARM指令集中有什么作用?请举例说明。4.在子程序调用时,如何传递参数返回值?请用ARM汇编代码举例说明。</think> ### ARM汇编程序执行分析 #### 问题解答: 1. **执行`BL SUB1`之前,寄存器值**: - R1 = `0x10` - R2 = `0x20` - R3 = `0x30` > **解释**:在`MAIN`标签下执行了三条`MOV`指令,分别将立即数加载到寄存器。 2. **执行完`BL SUB1`之后,寄存器值**: - R1 = `0x10`(恢复原值) - R2 = `0x20`(恢复原值) - R3 = `0x30`(恢复原值) > **解释**:`SUB1`子程序通过`STMFD`保存寄存器原值,结束时通过`LDMFD`恢复所有寄存器(包括R1-R3)。 3. **执行`MOV R2, R3`后(`BL DELAY`前),寄存器值**: - R1 = `0x20`(交换后) - R2 = `0x10`(交换后) - R3 = `0x10`(临时值) > **解释**:在`SUB1`中执行了交换操作: > ```armasm > MOV R3, R1 ; R3 = 0x10 > MOV R1, R2 ; R1 = 0x20 > MOV R2, R3 ; R2 = 0x10 > ``` 4. **循环结构代码及执行次数**: ```armasm DELAY_L1 SUBS R3, R3, #1 ; 循环计数器减1 BNE DELAY_L1 ; 结果非零则继续循环 ``` > **循环体执行次数**:100次(R3初值=100) 5. **指令`SUBS`改为`SUB`的影响**: - **功能变化**:循环将无限执行(死循环) - **原因**:`SUB`指令不更新条件标志位(CPSR),导致`BNE`始终判断旧标志位而无法退出循环 6. **`BL`与`B`指令的区别**: - **相同点**:均用于程序跳转 - **不同点**: | 指令 | 返回地址保存 | 用途 | |------|--------------|------------------| | `BL` | 自动存到LR | 子程序调用 | | `B` | 不保存 | 无条件跳转 | --- ### 关键执行流程解析 ```armasm MAIN MOV R1, #0x10 ; R1 = 0x10 MOV R2, #0x20 ; R2 = 0x20 MOV R3, #0x30 ; R3 = 0x30 LDR SP, =StackUser+29*4 ; 设置堆栈指针 BL SUB1 ; 调用子程序(LR = 下条指令地址) B . ; 无限循环(程序终点) SUB1 STMFD SP!, {R0-R7, LR} ; 保存寄存器到堆栈 MOV R3, R1 ; R3 = 0x10 MOV R1, R2 ; R1 = 0x20 MOV R2, R3 ; R2 = 0x10 (完成R1/R2交换) BL DELAY ; 调用延时子程序 LDMFD SP!, {R0-R7, PC} ; 恢复寄存器并返回 DELAY MOV R3, #100 ; 循环计数器初始化 DELAY_L1 SUBS R3, R3, #1 ; 计数器减1(更新标志位) BNE DELAY_L1 ; Z=0时继续循环 MOV PC, LR ; 返回调用点 ``` > **堆栈操作解析**: > - `STMFD SP!, {regs}`:满递减堆栈,按**高编号寄存器先入栈**顺序 > - 入栈顺序:LR → R7 → R6 → ... → R0 > - 出栈顺序:R0 → R1 → ... → R7 → PC(自动跳转) ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值