先复习一下C语言的内存部分
在32位操作系统下会生成4g的一个虚拟内存空间
kernel为内核大小为1g
stack则为栈区大小为8m 存放局部变量 函数参数 函数返回地址
heap为堆区大小不能确定取决于你的代码部分和栈区的使用情况 程序员自己管理的内存区域,使用是需要动态申请,----释放
bss初始化为0和未初始化的全局及静态变量
data:初始化不为0全局及静态变量
code:则为代码存放区域
编译流程: 预处理 main.c -> main.i 1. 去掉注释 2. 头文件展开 3. 宏替换 4. 特殊符号处理 __LINE__ __FILE__ __FUNCTION__ 编译 main.i -> main.s(汇编文件) 汇编 main.s -> main.o(二进制文件)不能直接执行 链接 main.o -> mainapp(可执行的二进制文件)
大小端的概念(高地址存放高位——小端)
union
定义了一个联合体test
,其中有一个int
类型的成员i
和一个char
数组c
。test.i = 1
:给int
变量i
赋值为1
。在内存中,1
的十六进制表示是0x00000001
。- 然后通过
char
数组c
访问相同的内存位置:- 如果系统是小端:
c[0]
会存储1
(最低有效字节),因此test.c[0] == 1
。 - 如果系统是大端:
c[0]
会存储0
(最高有效字节),因此test.c[0] != 1
。
- 如果系统是小端:
处理器框架
最小单元 电源、时钟(晶振)、复位、处理器、内存、flash(外存)、输入输出设备
处理器中包含CPU
CPU中有寄存器、运算单元、pc(程序计数器、也叫指令寄存器实际指向正在运行的下下条指令)、LR链接寄存器、SP:栈指针寄存器指向栈顶、CPSR:当前程序状态寄存器运算结果为正、负、进借位、工作状态、工作模式 、MMU:内存管理单元(将虚拟地址到物理地址的映射)
cache缓冲区D-Cache数据缓冲区 I-Cache指令缓冲区 哈佛结构数据和指令分开存储(提高效率)冯诺依曼结构将数据和指令一起存储
栈分为增栈、减栈、满栈、空栈一般存储为满减栈 将栈指针指向高地址,先减指针再读取栈区存放的数据
在ARM汇编中实现和c语言代码的混合编程调用
ldr sp, =0x40001000
: 设置栈指针 (sp
) 到内存地址0x40001000
。mov
指令: 将立即数加载到寄存器r0
到r3
中,准备好给c_add
函数传递参数。import c_add
和bl c_add
: 导入 C 语言中的函数c_add
,然后使用bl
指令进行分支调用。export asm_add
: 导出asm_add
函数,以便 C 语言可以调用它。stmfd sp!, {r4-r12, lr}
: 将寄存器r4
到r12
和lr
(链接寄存器)保存到栈中,保护这些寄存器的值。add r0, r0, r1
: 将r0
和r1
相加,结果存储在r0
中。ldmfd sp!, {r4-r12, pc}
: 从栈中恢复寄存器值,并将返回地址加载到pc
(程序计数器)中,返回到调用者。
C文件中
int asm_add(int x, int y);
: 声明外部汇编函数asm_add
,该函数接受两个int
参数,并返回一个int
结果。int c_add(int a, int b, int c, int d)
: 定义一个 C 函数c_add
,该函数接受四个整数参数。asm_add(a, b)
: 调用汇编函数asm_add
,传入参数a
和b
,并得到它们的和。asm_add(c, d)
: 再次调用asm_add
,传入参数c
和d
,并得到它们的和。sum += asm_add(c, d);
: 将两次调用的结果相加。return sum;
: 返回总和。
函数的返回值存放到寄存器R0中,在汇编语言中要给C语言传参的个数最好控制在4个参数以内R0~R3,超过4个则需要调用栈去存放后面的参数,再调用函数时要在函数开始位置往栈中存放
返回地址,避免在函数中调用其他函数时返回地址被覆盖 陷入死循环 称为保护现场 和 恢复现场