LV01-04-ARM汇编-04-汇编调用C程序
本文主要是汇编调用C程序的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows版本 | windows11 |
Ubuntu版本 | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
终端软件 | MobaXterm(Professional Edition v23.0 Build 5042 (license)) |
Linux开发板 | 正点原子 i.MX6ULL Linux 阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
Win32DiskImager | Win32DiskImager v1.0 |
点击查看本文参考资料
分类 | 网址 | 说明 |
官方网站 | https://www.arm.com/ | ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档 |
https://www.nxp.com.cn/ | NXP官方网站 | |
https://www.nxpic.org.cn/ | NXP 官方社区 | |
https://u-boot.readthedocs.io/en/latest/ | u-boot官网 | |
https://www.kernel.org/ | linux内核官网 |
点击查看相关文件下载
分类 | 网址 | 说明 |
NXP | https://github.com/nxp-imx | NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库 |
https://elixir.bootlin.com/linux/latest/source | 在线阅读linux kernel源码 | |
nxp-imx/linux-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga | NXP linux内核仓库tags中的rel_imx_4.1.15_2.1.0_ga | |
nxp-imx/uboot-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga | NXP u-boot仓库tags中的rel_imx_4.1.15_2.1.0_ga | |
I.MX6ULL | i.MX 6ULL Applications Processors for Industrial Products | I.MX6ULL 芯片手册(datasheet,可以在线查看) |
i.MX 6ULL Applications ProcessorReference Manual | I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网) | |
ARM | Cortex-A7 MPCore Technical Reference Manual | Cortex-A7 MPCore技术参考手册 |
ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition | ARM架构参考手册ARMv7-A和ARMv7-R版 | |
Arm Generic Interrupt Controller Architecture Specification- version 3 and version 4 | Arm通用中断控制器架构规范-版本3和版本4 | |
ARM Generic Interrupt Controller Architecture Specification - Version 2.0 | Arm通用中断控制器架构规范-版本2.0 | |
ARM Cortex-A Series Programmer's Guide for ARMv7-A | Cortex-A系列ARMv7-A编程指南 |
在 C 程序和 ARM 汇编程序之间相互调用时必须遵守 ATPCS 规则, ATPCS 规定了一些函数间调用的基本规则。
一、ATPCS 规则
ATPCS 即 ARM-THUMB procedure call standard( ARM-Thumb 过程调用标准)的简称,是基于 ARM 指令集和 THUMB 指令集过程调用的规范,规定了调用函数如何传递参数,被调用函数如何获取参数,以何种方式传递函数返回值。寄存器 R0~R15 在 ATPCS 规则的使用:
(1)在函数中,通过寄存器 R0~R3 来传递参数,被调用的函数在返回前无需恢复寄存器 R0~R3 的内容。
(2)在函数中,通过寄存器 R4~R11 来保存局部变量
(3)寄存器 R12 用作函数间 scratch 寄存器
(4)寄存器 R13 用作栈指针,记作 SP,在函数中寄存器 R13 不能用做其他用途,寄存器 SP 在进入函数时的值和退出函数时的值必须相等 。
(5)寄存器 R14 用作链接寄存器,记作 LR,它用于保存函数的返回地址,如果在函数中保存了返回地址,则 R14 可用作其它的用途。
(6)寄存器 R15 是程序计数器,记作 PC,它不能用作其他用途 。
二、参数传递
1. 汇编程序如何向 C 程序的函数传递参数
(1)当参数小于等下 4 个时,使用寄存器 R0~R3 来进行参数传递。
(2)当参数大于 4 个时,前四个参数按照上面方法传递,剩余参数传送到栈中,入栈的顺序与参数顺序相反,即最后一个参数先入栈 。
2. C 程序如何返回结果给汇编程序
(1)结果为一个 32 位的整数时,通过寄存器 R0 返回。
(2)结果为一个 64 位整数时,通过 R0 和 R1 返回,依此类推。
(3)结果为一个浮点数时,通过浮点运算部件的寄存器 f0, d0 或 s0 返回。
(4)结果为一个复合的浮点数时,通过寄存器 f0-fN 或者 d0~dN 返回。
(5)对于位数更多的结果,通过调用内存来传递 。
三、C 函数为何要用栈
总的来说,栈的作用就是:保存现场/上下文,传递参数 。
1. 保存现场/上下文
保存现场,也叫保存上下文。现场,相当于案发现场,总有一些现场的情况,要记录下来的,否则被别人破坏掉之后,就无法恢复现场了。而此处说的现场,就是指 CPU 运行的时候,用到了一些寄存器,比如 R0~R3, LR 等等,对于这些寄存器的值,如果不保存而直接跳转到函数中去执行,那么很可能会被破坏了,因为函数执行需要用到这些寄存器。
因此在函数调用之前,应该将这些寄存器等现场,暂时保持起来,等调用函数执行完毕返回后,再恢复现场,这样 CPU 就可以正确的继续执行了。
保存寄存器的值,一般用的是 push 指令,将对应的某些寄存器的值,一个个放到栈中,即所谓的入栈。
然后待被调用的子函数执行完毕的时候,再调用 pop,把栈中的一个个的值,赋值给对应的入栈的寄存器,即所谓的出栈。
2. 传递参数
当函数被调用并且参数大于 4 个时,(不包括第 4 个参数)第 4 个参数后面的参数就保存在栈中。