4 内嵌汇编规则、ATPCS规则、内存操作指令
day4.txt
file a.out //查看a.out的基本信息(运行平台)
readelf -h a.out //查看elf格式文件的64字节头信息
objcopy -O binary a.out a.bin //a.out的elf文件格式转换位 a.bin
objdump -d a.out //将a.out的elf反汇编
strip a.out //删除a.out的标号信息
====================================================================
GNU内嵌汇编规则:在c语言中需要改变寄存器数值时使用内嵌汇编
__asm__ __volatile__(
“mov r0, #12\n” //指令域,所有的指令必须以“”包裹,必须以'\n'结束,可以是多条语句
: “=&r”(val) //输出变量声明域:(实现从汇编到c语言变量的数据传递) “=”代表变量是只写“r”编译工具需要给变量分配寄存器 “&”给变量分配的寄存器是之前没有使用过的 c的变量必须以()包裹
://输入变量声明域
:“r0” //改变声明域,本次汇编修改的寄存器
);
内嵌汇编如果改变了寄存器的数据,就必须声明改变,否则会出现未知错误
mov.c
1 #include <stdio.h>
2
3 int main()
4 {
5 int val;
6
7 __asm__( //内嵌汇编的规则
8 "mov r0, #1\n\t" //r0 = 1
9 "mov r0, #11\n\t"//r0 = 11
10 "mov %0, r0\n\t" //val = r0 %0表示c语言的val变量在汇编程序中的引用
11 :"=r&"(val)//输出变量声明域
12 ://输入变量声明域
13 :"r0" //改变声明域
14 );
15
16 printf("val = %d\n", val);
17
18 return 0;
19 }
===========================================================================================================================
APCS规则:汇编调用C程序的规则
1.寄存器命名规则:r0-r3 (a1-a4);
r4-r11(v1-v8); r11:fp; r12 :ip;
r13:sp; r14:lr; r15:pc 。
2.行参传递:行参少于4个使用r0-r3,多于4个时前4个使用r0-r3,其余使用栈。
3.函数返回值传递:使用r0。
4.局部变量分配:r4-r11。
--------------------------------------------------------------------------------------------------------------------------------
ATPCS即ARM-THUMB procedure call standard(ARM-Thumb过程调用标准)的简称。
PCS规定了应用程序的函数可以如何分开地写,分开地编译,最后将它们连接在一起,所以它实际上定义了一套有关过程(函数)调用者与被调用者之间的协议。
为了使C语言程序和汇编程序之间能够互相调用,必须为子进程间的调用制定规则,在ARM处理器中,该规则被称为ATCPS:ARM程序和Thumb程序中子进程调用的规则。
。R0 | a1 | 工作寄存器 |
R1 | a2 | 工作寄存器 |
R2 | a3 | 工作寄存器 |
R3 | a4 | 工作寄存器 |
。R4 | v1 | 必须保护;局部变量寄存器 |
R5 | v2 | 必须保护;局部变量寄存器 |
R6 | v3 | 必须保护;局部变量寄存器 |
R7 | v4 | 必须保护;局部变量寄存器 |
R8 | v5 | 必须保护;局部变量寄存器 |
R9 | v6 | 必须保护;局部变量寄存器 |
R10 | sl v7 | 栈限制 |
R11 | fp v8 | 帧指针 |
。R12 | ip | 指令指针 |
R13 | sp | 栈指针 |
R14 | lr | 连接寄存器 |
根据参数个数是否固定,可以将子程序分为参数个数固定的子程序和参数个数可变的子程序.这两种子程序的参数传递规则是不同的.
1.参数个数可变的子程序参数传递规则
对于参数个数可变的子程序,当参数不超过4个时,可以使用寄存器R0~R3来进行参数传递,当参数超过4个时,还可以使用数据栈来传递参数. 在参数传递时,将所有参数看做是存放在连续的内存单元中的字数据。然后,依次将各名字数据传送到寄存器R0,R1,R2,R3; 如果参数多于4个,将剩余的字数据传送到数据栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈. 按照上面的规则,一个浮点数参数可以通过寄存器传递,也可以通过数据栈传递,也可能一半通过寄存器传递,另一半通过数据栈传递.
2.参数个数固定的子程序参数传递规则
对于参数个数固定的子程序,参数传递与参数个数可变的子程序参数传递规则不同,如果系统包含浮点运算的硬件部件。 浮点参数将按照下面的规则传递: (1)各个浮点参数按顺序处理; (2)为每个浮点参数分配FP寄存器; 分配的方法是,满足该浮点参数需要的且编号最小的一组连续的FP寄存器.第一个整数参数通过寄存器R0~R3来传递,其他参数通过数据栈传递.
3、子程序结果返回规则
1.结果为一个32位的整数时,可以通过寄存器R0返回.
2.结果为一个64位整数时,可以通过R0和R1返回,依此类推.
3.结果为一个浮点数时,可以通过浮点运算部件的寄存器f0,d0或者s0来返回.
4.结果为一个复合的浮点数时,可以通过寄存器f0-fN或者d0~dN来返回.
5.对于位数更多的结果,需要通过调用内存来传递.
内存操作指令:
单寄存器操作:
ldr/str
从内存加载数据到寄存器 ldr r0, [r1] ==== r0 = *r1
保存寄存器的数值到内存地址 str r0, [r1] ==== *r1 = r0
标号寻址:ldr r0, =fun //将fun标号的地址存储到r0
ldr r0, fun //取出fun标号地址处的内容
****************************************
fun:
.word 0x1111
在标号fun处申请一个字的空间并且初始化为0x1111
****************************************
立即数寻址:
前索引:ldr r0, [r1, #4] === r0 = *(r1 + 4) r1 = r1 ,地址偏移后再进行内存操作,基地值不改变
str r0, [r1, #4] === *(r1+4) = r0 r1的数值不变
后索引: ldr r0, [r1], #4 === r0=*r1 r1=r1+4
str r0, [r1], #4 === *r1=r0 r1=r1+4
变址索引:ldr r0, [r1, #4]! === r0=*(r1+4) r1=r1+4
寄存器寻址:
前索引:ldr r0, [r1, r2] === r0 = *(r1+r2) r1不变
str r0, [r1, r2] === *(r1+r2) = r0 r1不变
后索引:ldr r0, [r1], r2 === r0=*r1 r1=r1+r2
str r0, [r1], r2 === *r1=r0 r1=r1+r2
变址索引:ldr r0, [r1, r2]! === r0=*(r1+r2) r1=r1+r2
ldrb/strb ldrh/strh ldrd/strd
多寄存器操作:
ldm/stm
ldm r0, {r1,r2,r3} === r1=*r0 r2=*(r0+4) r3=*(r0+8) r0不变
stm同ldm
ldm r0!, {r1-r3} ===r1=*r0 r2=*(r0+4) r3=*(r0+8) r0=r0+8
ldmia/stmia 先进行内存操作后地址+4 /*一般都是用*/
ldmda/stmda 先进行内存操作后地址-4
ldmib/stmib 先地址+4,后进行内存操作
ldmdb/stmdb 先地址-4,后进行内存操作
多寄存器操作规定:
小地址对小编号寄存器,大地址对大编号寄存器
特殊地址sp
满栈:sp指向的空间是不能直接使用的
空栈:sp指向的空间是可以直接使用的
减栈:栈的生长方向地址减小
增栈:栈的生长方向地址增大
满减栈也可以使用:
stmdb sp!,{r0-r12,lr}
ldmia sp!,{r0-r1,pc}
******************************************************
栈操作指令:
ldmfd/stmfd 满减栈操作
ldmed/stmed 空减栈操作
ldmfa/stmfa 满增栈操作
ldmea/stmea 空增栈操作
stmfd sp!, {r0-r12, lr} //入栈
ldmfd sp!, {r0-r12, pc}^ //出栈 "^"代表需要进行模式切换
push {r0-r12} //入栈
pop {r0-r12} //出栈
栈操作一般使用来进行保存现场
*********************
指令中的“!”代表
更新基地址
*********************
******************************************************
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?