汇编函数的调用约定

汇编的调用约定

函数调用过程的概述
stack frame
在这里插入图片描述

调用一个函数的时候,就会压入栈帧里面,在调用A函数后,再调用B函数,B函数的地址就会继续压栈,当B函数处理完之后,在栈帧里面的B地址就会出栈,入宫函数过多的话,有可能会出现爆栈的情况

函数调用约定

  • caller就是一个函数调用者,callee就是被调用函数
  • 在caller中调用call,调用了callee,callee执行完之后返回,返回到调用call的下一个地址

在这里插入图片描述

这里有一个问题,函数调用的时候,那些函数的调用参数,和函数的返回值应该放在哪里呢?
这就是我们下面要解决的问题

函数调用过程中的编程约定

有关寄存器的编程约定

x0-x31就是寄存器的最初始化的名字,最开始的32个寄存器
ABI就是在函数的时候吧这些寄存器普遍化修改的别名,主要使用的就是这些别名,我们之后都是使用这些别名,更好的进行理解
在这里插入图片描述

N/A:就是not available,没有人维护
ra:return address,就是jal函数返回后的下一个地址,由
调用者
来进行维护,因为函数返回之后要达到对应的位置
sp:stack pointer:就是用来存放栈指针,由被调用者来维护,因为出栈和入栈主要就是由被调用的子函数来执行
t:temporary:临时寄存器,用来函数调用者保存函数的一些临时变量
s :save :保存寄存器,就是和t是反过来的,对于调用者来说,要保证save里面的值在调用前和调用后值是不变
a:argument参数寄存器,用于在函数时候保存函数的参数,以及传递返回值

我们在写risc-v的时候,一般使用a0,a1来进行返回
使用a0-a7来进行传递函数的参数

函数跳转和返回指令的编程约定

(1)
在这里插入图片描述
(2)
在这里插入图片描述
在这里插入图片描述

我们要将函数的ra寄存器保存在栈里面,避免之后调用的时候这个ra寄存器没了,寄存器没了的话,函数返回地址就没了,不知道返回到那里,所以我们要用s寄存器来保存ra的值,退栈的时候恢复ra的值
在c语言里面调用汇编代码
在这里插入图片描述

  • 汇编

示例

# Calling Convention
# Demo how to write nested routines
#
# void _start()
# {
#     // calling nested routine
#     aa_bb(3, 4);
# }
#
# int aa_bb(int a, int b)
# {
#     return square(a) + square(b);
# }
#
# int square(int num)
# {
#     return num * num;
# }

	.text			# Define beginning of text section
	.global	_start		# Define entry _start,这个_start是一个全局的标签地址

_start:
	la sp, stack_end	# prepare stack for calling functions  ,同样进入主函数之后就开辟了栈内存空间

	# aa_bb(3, 4);
	li a0, 3
	li a1, 4			# 给函数两个参数的值,传参
	call aa_bb			# 一个3,一个4

stop:
	j stop			# Infinite loop to stop execution

# int aa_bb(int a, int b)
# return a^2 + b^2
aa_bb:
	# prologue
	addi sp, sp, -16	# 压栈
	sw s0, 0(sp)		# 这里把s0,s2保存起来,函数的参数,以及栈指针,把sp+0存储到s0里面
	sw s1, 4(sp)		
	sw s2, 8(sp)		
	sw ra, 12(sp)		# 这里还要保存ra的值,sw 是存字,把 ra 的低位四字节存入地址 rs1+立即数中。

	# cp and store the input params
	mv s0, a0
	mv s1, a1

	# sum will be stored in s2 and is initialized as zero
	li s2, 0

	mv a0, s0
	jal square		# 这里是尾调用,所以就不会回来了,如果不保存ra的话,就会把ra的地址给改调了
	add s2, s2, a0	# 上一层函数函数运行的结果的在a0里面,因为这就是用来处理函数参数和返回值的寄存器

	mv a0, s1
	jal square
	add s2, s2, a0	# a0里面放的就是第二个参数调用函数处理的结果,放到s2里面

	mv a0, s2		# 再把s2的值放到参数寄存器里面,返回

	# epilogue
	lw s0, 0(sp)	# 恢复寄存器,退出栈帧
	lw s1, 4(sp)
	lw s2, 8(sp)
	lw ra, 12(sp)
	addi sp, sp, 16	# 把栈镇退出
	ret				# 返回

# int square(int num)
square:
	# prologue
	addi sp, sp, -8
	sw s0, 0(sp)# 因为这里是最后一次调用函数所以不用存储函数的返回值ra
	sw s1, 4(sp)

	# `mul a0, a0, a0` should be fine,
	# programing as below just to demo we can contine use the stack
	mv s0, a0
	mul s1, s0, s0
	mv a0, s1

	# epilogue
	lw s0, 0(sp)
	lw s1, 4(sp)
	addi sp, sp, 8

	ret

	# add nop here just for demo in gdb
	nop

	# allocate stack space,开辟了栈空间
stack_start:
	.rept 12
	.word 0
	.endr
stack_end:

	.end			# End of file

在汇编代码里面调用c代码

# C all ASM

	.text			# Define beginning of text section
	.global	_start		# Define entry _start
	.global	foo		# foo is a C function defined in test.c,c函数定义到这里

_start:
	la sp, stack_end	# prepare stack for calling functions

	li a0, 1
	li a1, 2
	call foo # 调用c函数

stop:
	j stop			# Infinite loop to stop execution

	nop			# just for demo effect

stack_start:
	.rept 12
	.word 0
	.endr
stack_end:

	.end			# End of file
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zevin~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值