本文主要是介绍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系统上的操作步骤:
-
安装ARM编译工具链: 如果未安装,可以通过以下命令安装:
sudo apt-get install gcc-arm-none-eabi
-
编译生成汇编代码: 使用
-S
选项来生成汇编代码。arm-none-eabi-gcc -S simple.c -o simple.s
-
查看生成的汇编代码: 打开生成的
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, #0sub sp, sp, #12str r0, [fp, #-8]str r1, [fp, #-12]ldr r2, [fp, #-8]ldr r3, [fp, #-12]add r3, r2, r3mov r0, r3add sp, fp, #0@ sp neededldr fp, [sp], #4bx 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 = 0push {fp, lr}add fp, sp, #4sub sp, sp, #8mov r1, #3mov r0, #5bl addstr r0, [fp, #-8]ldr r3, [fp, #-8]mov r0, r3sub sp, fp, #4@ sp neededpop {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]
:分别将函数参数a
和b
存储到栈帧中。ldr r2, [fp, #-8]
和ldr r3, [fp, #-12]
:从栈帧中加载参数a
和b
的值到寄存器r2
和r3
。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, #3
和mov r0, #5
:将常数3
和5
分别加载到寄存器r1
和r0
中,作为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程序如何在低级别实现,包括函数调用、参数传递和返回值处理等细节。
这篇关于C语言函数是如何变成汇编的的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!