当前位置: 首页 > news >正文

ARM汇编与栈操作指南

1.ROM与RAM的分类

2.立即数

判断条件:

  1. 如果某个数的数值范围是0~0xFF之间,那么这个数一定是立即数;
  2. 把某个数展开成2进制,这个数的最高位1至最低位1之间的二进制数序列的位数不能超过8位;
  3. 这个数的二进制序列凑够8位之后的的右边必须为偶数个连续的 0

3.栈的分类

1. 栈的生长方向:“减” vs “增”

        减栈 (Descending Stack):栈在内存中从高地址向低地址方向生长(即“由高到低”)。每次压栈(Push)操作,栈指针的值会减小

        增栈 (Ascending Stack):栈在内存中从低地址向高地址方向生长(即“由低到高”)。每次压栈(Push)操作,栈指针的值会增大

2. 栈指针的位置:“满” vs “空”

        满栈 (Full Stack):栈指针 SP 总是指向最后一个入栈的数据(也就是栈顶元素)。在压栈操作之前,需要先移动SP指向下一个空闲位置,然后再存入数据。

        空栈 (Empty Stack):栈指针 SP 总是指向下一个空闲的位置。在压栈操作时,可以直接存入数据,然后再移动SP指向下一个空闲位置。

3. 满减栈 (Full Descending - FD)

这是 最常见 的方式,ARM和许多其他处理器默认采用这种方式。

  • 满 (Full):书记员(SP)的便签上记录的,永远是最后一个摆放了货物的那个格子

  • 减 (Descending):货架是从编号大的格子向编号小的格子依次摆放货物(栈向低地址增长)。

操作步骤(压栈/PUSH):

  1. 先移动书记员:书记员先向下(向编号小的方向)移动一格,并在便签上记下这个新位置。

  2. 再摆放货物:然后把新货物放进这个新格子。
    (所以他的便签始终指向最后一个有货物的格子)

口诀:先减后存


4. 空减栈 (Empty Descending - ED)

  • 空 (Empty):书记员(SP)的便签上记录的,永远是下一个将要摆放货物的空格子

  • 减 (Descending):货架是从编号大的格子向编号小的格子依次摆放货物(栈向低地址增长)。

操作步骤(压栈/PUSH):

  1. 先摆放货物:直接把新货物放进书记员便签当前指着的那个空格子

  2. 再移动书记员:然后书记员向下(向编号小的方向)移动一格,在便签上记下下一个空位置。
    (所以他的便签始终指向下一个空位置)

口诀:先存后减


5. 满增栈 (Full Ascending - FA)

  • 满 (Full):书记员(SP)的便签上记录的,永远是最后一个摆放了货物的那个格子

  • 增 (Ascending):货架是从编号小的格子向编号大的格子依次摆放货物(栈向高地址增长)。

操作步骤(压栈/PUSH):

  1. 先移动书记员:书记员先向上(向编号大的方向)移动一格,并在便签上记下这个新位置。

  2. 再摆放货物:然后把新货物放进这个新格子。
    (他的便签始终指向最后一个有货物的格子)

口诀:先增后存


6. 空增栈 (Empty Ascending - EA)

  • 空 (Empty):书记员(SP)的便签上记录的,永远是下一个将要摆放货物的空格子

  • 增 (Ascending):货架是从编号小的格子向编号大的格子依次摆放货物(栈向高地址增长)。

操作步骤(压栈/PUSH):

  1. 先摆放货物:直接把新货物放进书记员便签当前指着的那个空格子

  2. 再移动书记员:然后书记员向上(向编号大的方向)移动一格,在便签上记下下一个空位置。
    (他的便签始终指向下一个空位置)

口诀:先存后增

补充:ARM内核中使用的是满减栈

           入栈:stmfd sp!, {r0-r12, lr}
出栈:ldmfd sp!, {r0-r12, lr} 

4.ARM汇编语言

1.简单的指令

MOV Rd, #(立即数b); 将立即数b写入到Rd中

LDR Rd, =(任意数c);将任意数c写入Rd中

ADD Rd, Rm, Rn; 将Rm与Rn求和,写入到Rd中

SUB Rd, Rm, Rn;将Rm与Rn作差,写入到Rd中

BIC Rd, Rd, #(立即数); 将Rd指定为清零,写入到Rd中

ORR Rd, Rd, #(立即数); 将Rd指定为置1,写入到Rd中

CMP Rm ,Rn; 比较Rm与Rn的大小

2.STR指令

ARM汇编语言C语言
        STR Rd, [Rm]*Rd = Rm;
STR Rd, [Rm,  #4]*(Rd + 1) = Rm;
STR Rd, [Rm], #4*Rd++ = Rm;
STR Rd, [Rm, #4]!*++Rd = Rm;
LDR Rd, [Rm]Rd = *Rm;

3.b, bl, bx指令的区别

b:

        b指令类似c语言的goto语句,能够实现无条件跳转。跳转时需要一个lable,表示要跳转到什么地方去,跳转时不修改LR(链接寄存器);

bl:

        bl指令跳转时会修改LR,会将跳转指令的下一条指令的地址保存于LR中

bx:

        bx指令会将某个通用寄存器当前的值(例如LR中的地址)保存于PC中,因此与bl配合使用可以实现从被调函数中返回到主调函数;

5.函数调用

(1)ARM汇编语言中调用C语言     

  1. 参数传递

    • 前4个参数(或前4个32位参数)通过寄存器 R0, R1, R2, R3 传递

    • 第5个及之后的参数通过传递(按从右向左的顺序压栈)

    • 64位参数(如doublelong long)可能占用两个寄存器

  2. 返回值

    • 32位及以下的返回值通过 R0 寄存器返回

    • 64位返回值通过 R0 和 R1 寄存器返回

  3. 栈对齐

    • 栈指针(SP)必须是 8字节对齐 的

  4. 寄存器保护

    • 函数调用会破坏 R0-R3, R12 (IP) 和 R14 (LR)

    • 如果汇编代码需要使用 R4-R11,必须在调用前保存它们

     5.函数声明

                import  函数名

; 假设要调用C函数: int add(int a, int b, int c, int d, int e);
; 前4个参数通过寄存器传递,第5个通过栈传递.text
.global main
main:; 保护需要保存的寄存器PUSH {R4, LR}      ; 保存R4和返回地址; 设置前4个参数MOV R0, #1         ; a = 1MOV R1, #2         ; b = 2MOV R2, #3         ; c = 3MOV R3, #4         ; d = 4; 第5个参数通过栈传递MOV R4, #5         ; e = 5PUSH {R4}          ; 将第5个参数压栈; 调用C函数BL add; 清理栈空间 (移除第5个参数)ADD SP, SP, #4; 恢复寄存器并返回POP {R4, PC}对应的C函数
int add(int a, int b, int c, int d, int e) {return a + b + c + d + e;
}

(2)C语言中调用ARM汇编语言      

  1. 函数声明

    • 在C代码中使用extern声明汇编函数

    • 汇编代码中使用.global.globl导出函数名

  2. 参数获取

    • 前4个参数通过 R0, R1, R2, R3 获取

    • 额外参数通过获取(使用SP访问)

  3. 返回值

    • 通过 R0 返回32位及以下数据

    • 通过 R0 和 R1 返回64位数据

  4. 寄存器保护

    • 汇编函数必须保护 R4-R11, R13 (SP) 和 R14 (LR)

    • 如果使用这些寄存器,必须在使用前保存,返回前恢复

  5. 栈对齐

    • 必须保持栈指针(SP)的8字节对齐

      C代码:
      // 声明外部汇编函数
      extern int multiply(int a, int b);int main() {int result = multiply(5, 7);return result;
      }汇编代码:
      .text
      .global multiply
      multiply:; 函数入口,保护需要使用的寄存器PUSH {R4, R5}      ; 保护R4和R5; 获取参数 (R0 = a, R1 = b)MOV R4, R0         ; 将a保存到R4MOV R5, R1         ; 将b保存到R5; 执行乘法操作MUL R0, R4, R5     ; R0 = R4 * R5; 恢复寄存器并返回POP {R4, R5}BX LR              ; 返回到调用者

5.代码练习

//汇编代码area reset, readonly, codepreserve8code32entry;ldr r0, =0x40000000;ldr r1, =0x3456781A;str r1, [r0, #4] ;*(r0 + 1) = r1	 ;str r1, [r0], #4   ;*r0++ = r1;str r1, [r0, #4]! ;*++r0 = r1;ldr r0, =0x40000000;ldr r3, [r0];ldr r0, = 0x40000004;ldr r4, [r0];add r5, r3, r4;ldr r0, =0x40000008;str r5, [r0];mov r0, #0;orr r0, r0, #(1 << 7)	  ;0000 0000 0000 0000 0000 0000 1000 0000;ldr r0, =0x7FFFFFFF	;adds r0, r0, #1;mov r0, #3;mov r1, #5;mov r2, #4;cmp r0, r1;movls r3, r1;movge r3, r0;cmp r3, r2;movls r3, r2;b lable	  ;branch;mov r0, #3;mov r1, #5
;lable
;	mov r0, #5
;	mov r1, #3	
;	mov r2, #4
;	cmp r0, r1
;	bls less
;	bgt great
;great	
;	mov r3, r0
;	b  lable
;less
;	mov r3, r1	  ;lable
;	cmp r3, r2
;	bgt finished
;	mov r3, r2    
; 	mov r0, #1		;i
;	mov r1, #0		;sum;loop	
;	cmp r0, #100
;	bgt finished
;	add r1, r1, r0
;	add r0, r0, #1
;	b loopldr pc, =_start_asm_maxstmfd sp!, {r0-r12, lr}bl _asm_minldmfd sp!, {r0-r12, lr} cmp r0, r1movge r2, r0movlt r2, r1bx lrexport _asm_min
_asm_mincmp r0, r1movle r2, r0movgt r2, r1mov r0, r2bx lr		_startldr sp, =0x40001000mrs r0, cpsr;xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxx0 0000bic r0, r0, #0x1Forr r0, r0, #0x10 ;0001 0000msr	cpsr_c, r0ldr sp, =0x40001000sub sp, sp, #1024import mainb main;stmfd sp!, {r0-r12, lr};import c_max;mov r0, #2;mov r1, #3;bl c_max;ldmfd sp!, {r0-r12, lr};mov r0, #11;mov r1, #22finishedb finished	end//c代码
int c_add(int a, int b, int c, int d, int e)
{int ret;ret = a + b + c + d + e;return ret;
}int c_max(int a, int b)
{return a > b ? a : b;
}extern int _asm_min(int a, int b);void delay(int n)
{while(n--);
}int main(void)
{int ret;ret = _asm_min(10, 20);while(1){delay(ret);}
}


文章转载自:

http://9TTkYOJ3.yfffg.cn
http://x9WnAC0P.yfffg.cn
http://UMUQRiOQ.yfffg.cn
http://pIgpqa96.yfffg.cn
http://uaD6EpxP.yfffg.cn
http://IfG7lFd3.yfffg.cn
http://83Zr6ATA.yfffg.cn
http://63LzPyNo.yfffg.cn
http://KSQbQZ3H.yfffg.cn
http://wAQ4sGOK.yfffg.cn
http://1FZVdKgg.yfffg.cn
http://4O40TfHE.yfffg.cn
http://80dFd3Al.yfffg.cn
http://Qp2CtScV.yfffg.cn
http://OEKVaYkA.yfffg.cn
http://H9PAOxzq.yfffg.cn
http://3AaY4nV1.yfffg.cn
http://uRPZvzpa.yfffg.cn
http://H1pkBMEe.yfffg.cn
http://XlXUYvtD.yfffg.cn
http://cOSEMJei.yfffg.cn
http://ua5qFDLV.yfffg.cn
http://hTpRH3gY.yfffg.cn
http://8MjjXrsE.yfffg.cn
http://cNds8gc4.yfffg.cn
http://Ujowwko0.yfffg.cn
http://lJHq8wjc.yfffg.cn
http://Y45X3jA1.yfffg.cn
http://DOiklnqi.yfffg.cn
http://QwAZVFjC.yfffg.cn
http://www.dtcms.com/a/375864.html

相关文章:

  • 在 Keil 中将 STM32 工程下载到 RAM 进行调试运行
  • 高效数据操作:详解MySQL UPDATE中的CASE条件更新与性能优化
  • 构建企业级Selenium爬虫:基于隧道代理的IP管理架构
  • Nginx限流与防爬虫与安全配置方案
  • YOLO11训练自己数据集的注意事项、技巧
  • Kafka面试精讲 Day 13:故障检测与自动恢复
  • Linux学习——管理网络安全(二十一)
  • 平衡车 -- PID
  • 【ComfyUI】Flux Krea 微调完美真实照片生成
  • dp类相关问题(1):区间dp
  • TensorFlow 2.x 核心 API 与模型构建:从入门到实践
  • 华清远见25072班网络编程学习day2
  • 【论文写作】--网络与信息安全顶刊顶会
  • 【人工智能99问】如何基于QWen3进行LoRA微调?(38/99)
  • JAVA Predicate
  • 自动驾驶中的传感器技术41——Radar(2)
  • Netty HandlerContext 和 Pipeline
  • Stuns in Singapore!中新赛克盛大亮相ISS World Asia 2025
  • 开始 ComfyUI 的 AI 绘图之旅-LoRA(五)
  • 字符函数和字符串函数 last part
  • win安装多个mysql,免安装mysql
  • 开源项目_强化学习股票预测
  • Shell 脚本基础:从语法到实战全解析
  • Nginx如何部署HTTP/3
  • 解一元三次方程
  • A股大盘数据-20250909分析
  • 05-Redis 命令行客户端(redis-cli)实操指南:从连接到返回值解析
  • shell函数+数组+运算+符号+交互
  • 群晖Lucky套件高级玩法-——更新证书同步更新群晖自带证书
  • 照明控制设备工程量计算 -图形识别超方便