目录
经典例子:求阶乘
一:数组求和
二:数据压栈退栈
三:函数嵌套调用
经典例子:求阶乘
知识点:
BGT
用于判断r2 > r0
,确保循环执行 恰好r0
次。BNE
用于判断r2 ≠ r0
,会导致循环多执行一次,得到错误结果。
这就是阶乘代码中必须使用 BGT
而非 BNE
的原因。
AREA Factorial, CODE, READONLYENTRYstartLDR sp, =0x40001000 ; 初始化栈指针MOV r0, #10 ; 设置输入值为10MOV r1, #1 ; 结果初始化为1MOV r2, #1 ; 循环计数器初始化为1loopCMP r2, r0 ; 比较计数器与输入值BGT end_loop ; 如果计数器 > 输入值,结束循环MUL r1, r1, r2 ; 累乘:result *= counterADD r2, r2, #1 ; 计数器加1B loop ; 继续循环end_loopMOV r0, r1 ; 将结果存入r0
stopB stop ; 程序终止END
一:数组求和
例:编写一个ARM汇编程序累加一个“数组”的所有元素,碰上0时停止。结果放入 r4。
area test, code, readonly ; 定义代码段test,属性为代码段、只读entry ; 程序入口标记
startldr r0,=array ; 将array的绝对地址加载到r0(正确写法应为ldr r0, =array)
loopldr r1,[r0],#4 ; 从r0地址读取数据到r1,然后r0自增4字节(4字节=字长,适用于32位数据)cmp r1,#0 ; 比较r1是否为0addne r4,r4,r1 ; 若r1≠0,将r1累加到r4(注意:r4未初始化,默认值不确定)bne loop ; 若r1≠0,跳转回loop继续遍历
stopb stop ; 无限循环,程序在此处结束#DCD伪操作数据缓冲池技术#dcd机器码
arraydcd 0x11 ; 定义数组元素,0x11(十进制17)dcd 0x22 ; 0x22(十进制34)dcd 0 ; 0(数组结束标记)
二:数据压栈退栈
例:先将栈地址设置为将要压栈的数据存入寄存器r1-r5中,然后压栈
AREA first, CODE, READONLYCODE32ENTRYstartLDR sp, =0x40001000 ; 初始化栈指针,指向0x40001000地址; 数据准备:设置寄存器初始值MOV r1, #0x11 ; r1 = 0x11MOV r2, #0x22 ; r2 = 0x22MOV r3, #0x33 ; r3 = 0x33MOV r5, #0x55 ; r5 = 0x55 (修正中文逗号为英文逗号); 压栈操作:保存寄存器值到栈STMFD sp!, {r1-r3, r5} ; 保存r1-r3和r5到栈,SP自动递减; 数据清零:验证后续恢复操作MOV r1, #0 ; 清零r1MOV r2, #0 ; 清零r2MOV r3, #0 ; 清零r3MOV r5, #0 ; 清零r5; 出栈操作:从栈恢复寄存器值LDMFD sp!, {r1-r3, r5} ; 从栈恢复r1-r3和r5,SP自动递增stopB stop ; 无限循环结束程序END
三:函数嵌套调用
当有多级函数嵌套,函数返回值我们不可能都存储在通用寄存器中,必须利用ldm将程序跳转前的寄存器值以及函数的返回地址压栈。
AREA test, CODE, READONLYENTRYstartLDR sp, =0x40002000 ; 初始化栈指针MOV r1, #0x11 ; 设置r1 = 0x11MOV r2, #0x22 ; 设置r2 = 0x22MOV r3, #0x33 ; 修正中文逗号为英文逗号MOV r5, #0x55 ; 修正中文逗号为英文逗号BL child_func ; 调用子函数ADD r0, r1, r2 ; 计算r0 = r1 + r2
stopB stop ; 无限循环结束程序; 非叶子函数(调用其他函数的函数)
child_funcSTMFD sp!, {r1-r3, r5, lr} ; 保存寄存器和返回地址到栈MOV r1, #10 ; 修改r1的值BL child_funcl ; 调用子子函数LDMFD sp!, {r1-r3, r5, lr} ; 恢复寄存器和返回地址MOV pc, lr ; 返回主函数; 叶子函数(不调用其他函数的函数)
child_funclSTMFD sp!, {r1-r3, r5} ; 保存寄存器到栈MOV r1, #11 ; 修改r1的值LDMFD sp!, {r1-r3, r5} ; 恢复寄存器MOV pc, lr ; 返回父函数END