C语言函数是如何变成汇编的

为了说明C语言如何被编译成汇编语言,我们可以通过一个简单的C程序,并使用ARM编译器来生成相应的汇编代码。

// simple.c
int add(int a, int b) {
    return a + b;
}

int main() {
    int result = add(5, 3);
    return result;
}

使用ARM编译器生成汇编代码

我们使用 arm-none-eabi-gcc(GNU ARM Embedded Toolchain)来编译这个C程序并生成汇编代码。以下是在Linux或类似Unix系统上的操作步骤:

  1. 安装ARM编译工具链: 如果未安装,可以通过以下命令安装:

    sudo apt-get install gcc-arm-none-eabi

  2. 编译生成汇编代码: 使用 -S 选项来生成汇编代码。

    arm-none-eabi-gcc -S simple.c -o simple.s

  3. 查看生成的汇编代码: 打开生成的 simple.s 文件。

生成的汇编代码(simple.s)

	.cpu arm7tdmi
	.eabi_attribute 20, 1
	.eabi_attribute 21, 1
	.eabi_attribute 23, 3
	.eabi_attribute 24, 1
	.eabi_attribute 25, 1
	.eabi_attribute 26, 1
	.eabi_attribute 30, 6
	.eabi_attribute 34, 0
	.eabi_attribute 18, 4
	.file	"simple.c"
	.text
	.align	2
	.global	add
	.arch armv4t
	.syntax unified
	.arm
	.fpu softvfp
	.type	add, %function
add:
	@ Function supports interworking.
	@ args = 0, pretend = 0, frame = 8
	@ frame_needed = 1, uses_anonymous_args = 0
	@ link register save eliminated.
	str	fp, [sp, #-4]!
	add	fp, sp, #0
	sub	sp, sp, #12
	str	r0, [fp, #-8]
	str	r1, [fp, #-12]
	ldr	r2, [fp, #-8]
	ldr	r3, [fp, #-12]
	add	r3, r2, r3
	mov	r0, r3
	add	sp, fp, #0
	@ sp needed
	ldr	fp, [sp], #4
	bx	lr
	.size	add, .-add
	.align	2
	.global	main
	.syntax unified
	.arm
	.fpu softvfp
	.type	main, %function
main:
	@ Function supports interworking.
	@ args = 0, pretend = 0, frame = 8
	@ frame_needed = 1, uses_anonymous_args = 0
	push	{fp, lr}
	add	fp, sp, #4
	sub	sp, sp, #8
	mov	r1, #3
	mov	r0, #5
	bl	add
	str	r0, [fp, #-8]
	ldr	r3, [fp, #-8]
	mov	r0, r3
	sub	sp, fp, #4
	@ sp needed
	pop	{fp, lr}
	bx	lr
	.size	main, .-main
	.ident	"GCC: (GNU Arm Embedded Toolchain 9-2020-q2-update) 9.3.1 20200408 (release)"

代码分析

add 函数
  • str fp, [sp, #-4]!:将当前帧指针 fp 的值保存到栈中,并将栈指针 sp 向下偏移4字节。! 表示更新后 sp 的值。
  • add fp, sp, #0:将 sp 的值赋给 fp,即建立当前函数的栈帧。
  • sub sp, sp, #12:为局部变量分配12字节的空间。
  • str r0, [fp, #-8]str r1, [fp, #-12]:分别将函数参数 ab 存储到栈帧中。
  • ldr r2, [fp, #-8]ldr r3, [fp, #-12]:从栈帧中加载参数 ab 的值到寄存器 r2r3
  • add r3, r2, r3:计算 a + b,结果存储在 r3 中。
  • mov r0, r3:将计算结果 r3 设置为函数返回值。
  • add sp, fp, #0:恢复栈指针 sp 到函数调用前的位置。
  • ldr fp, [sp], #4:恢复帧指针 fp 的值。
  • bx lr:返回到调用该函数的地方。lr 寄存器保存了返回地址。
main 函数
  • push {fp, lr}:将当前的帧指针 fp 和链接寄存器 lr 保存到栈中。
  • add fp, sp, #4:建立当前函数的栈帧。
  • sub sp, sp, #8:为局部变量分配8字节的空间。
  • mov r1, #3mov r0, #5:将常数 35 分别加载到寄存器 r1r0 中,作为 add 函数的参数。
  • bl add:调用 add 函数。
  • str r0, [fp, #-8]:将 add 函数的返回值存储到栈帧中。
  • ldr r3, [fp, #-8]:从栈帧中加载 add 函数返回值到寄存器 r3
  • mov r0, r3:将 r3 设置为 main 函数的返回值。
  • sub sp, fp, #4:恢复栈指针 sp 到函数调用前的位置。
  • pop {fp, lr}:恢复帧指针 fp 和链接寄存器 lr 的值。
  • bx lr:返回到调用该函数的地方。

总结

通过上述步骤,我们展示了如何使用ARM编译器将一个简单的C程序编译成汇编代码。这个过程包括安装编译工具链、编写和编译C代码、生成和分析汇编代码。生成的汇编代码展示了C程序如何在低级别实现,包括函数调用、参数传递和返回值处理等细节。

  • 24
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值