C与汇编深入分析
1、汇编怎么调用C语言
1.1、直接调用
bl main
1.2、想传参数怎么办?
(1)在arm中有个ATPCS规则:ARM-THUMB procedure call standard(ARM-Thumb过程调用标准)。 约定r0-r15寄存器的用途:
- r0-r3:调用者和被调用者之间传参数。
- r4-r11:函数可能被使用,所以在函数的入口保存它们,在函数的出口恢复它们。

(2)示例代码:
int delay(unsigned int d)
{while (d--);return 0;
}
在汇编里调用delay:
ldr r0, =1000000 /* 给delay函数传参数,保存在r0里 */
bl delay
cmp r0, #0 /* 返回值保存在r0中,比较返回值是否为0 */
1.3、寄存器与栈
(1)栈的作用:函数调用时,保存现场;函数返回时,恢复现场。
(2)函数传参和返回值会用到如上寄存器和栈。
2、程序下载到Flash中
2.1、反汇编示例

2.2、烧写在Flash上的内容
| 地址 | Flash内容 |
|---|---|
| 0x08000000 | 00000000 |
| 0x08000004 | 08000009 |
| 0x08000008 | f8dfd004 |
| 0x0800000c | f000f80c |
| 0x08000010 | 20010000 |
| 0x08000014 | bf00b501 |
| 0x08000018 | 1e419800 |
| …… | …… |
3.3、启动流程
上电后:
- 设置栈:CPU会从0x08000000读取值,用来设置SP(我们的程序里再次设置了SP)
- 跳转:CPU从0x08000004得到地址值,根据它的BIT0切换为ARM状态或Thumb状态,然后跳转
- 对于cortex M3/M4,它只支持Thumb状态,所以0x08000004上的值bit0必定是1
- 0x08000004上的值 = Reset_Handler + 1
- 从Reset_Handler继续执行
3、汇编启动代码分析
(1)PRESERVE8
- 解释:告诉汇编器当前文件保持 8 字节对齐,符合 ARM 的 AAPCS(ARM 架构过程调用标准)要求。
- 作用:确保函数调用时栈是 8 字节对齐的,避免某些指令出错。
(2)THUMB
- 解释:告诉汇编器接下来的代码是 THUMB 指令集(16 位压缩指令集),而不是 ARM 指令集(32 位)。
- 作用:Cortex-M 系列只支持 THUMB 指令集,所以必须加这一句。
(3)AREA RESET, DATA, READONLY
- 解释:定义一个名为
RESET的数据段,属性是只读(READONLY)。 - 作用:这个段通常用来存放中断向量表(Vector Table),它会被链接器放到 Flash 的起始地址(0x00000000)。
(4)EXPORT __Vectors
- 解释:把
__Vectors这个符号导出,让链接器或其他文件可以引用它。 - 作用:链接器需要知道这个向量表的位置,以便正确放置到 Flash 开头。
(5)DCD 0
- 解释:在向量表中定义第一个条目:初始主堆栈指针(MSP)的值。
- 作用:芯片上电后,CPU 会自动把这里的值加载到 MSP 寄存器(R13寄存器)。实际使用中应该改成 RAM 顶地址,否则程序会崩溃。
(6)DCD Reset_Handler ; Reset Handler
- 解释:定义向量表的第二个条目:复位中断向量。
- 作用:芯片复位后,CPU 会跳转到
Reset_Handler这个函数执行。
(7)AREA |.text|, CODE, READONLY
- 解释:定义一个名为
.text的代码段,属性是只读。 - 作用:接下来的代码会被放到 Flash 中,作为程序指令。
(8)Reset_Handler PROC
- 解释:定义一个名为
Reset_Handler的函数(过程)。 - 作用:这是芯片复位后执行的第一个函数,负责初始化系统并跳转到
main()。 - PORC:告诉汇编器“一个函数从这里开始,与ENDP相对应
(9)EXPORT Reset_Handler [WEAK]
- 解释:把
Reset_Handler导出为弱符号(weak symbol)。 - 作用:允许用户在其它文件中重新定义
Reset_Handler,覆盖这个默认版本。
(10)IMPORT main
- 解释:告诉汇编器
main是一个外部符号(在 C 文件中定义)。 - 作用:以便后面用
BL main跳转到 C 程序的入口。
(11)LDR SP, =(0x20000000+0x30000)
- 解释:设置主堆栈指针(MSP)为
0x20030000。 - 作用:
0x20000000是 SRAM 起始地址,+0x30000表示栈顶地址为 192KB 偏移(具体取决于芯片 SRAM 大小)。 - 注意: 如果芯片没有这么多 SRAM,这个值会出错。
(12)BL main
- 解释:调用 C 语言的
main()函数。 - 作用:进入用户程序入口,开始执行应用逻辑。
(13)ENDP:告诉汇编器:这个函数到这里结束 。
(14)END:告诉汇编器:文件结束。
PRESERVE8THUMB; Vector Table Mapped to Address 0 at ResetAREA RESET, DATA, READONLYEXPORT __Vectors__Vectors DCD 0 DCD Reset_Handler ; Reset HandlerAREA |.text|, CODE, READONLY; Reset handler
Reset_Handler PROCEXPORT Reset_Handler [WEAK]IMPORT mainLDR SP, =(0x20000000+0x30000)BL mainENDP END
参考资料:
- https://blog.csdn.net/weixin_42727214/article/details/154121558?spm=1011.2415.3001.5331
