在调用函数f前,先做了一步将函数f的两个参数放入寄存器a1,a0中。这是因为寄存器a1,a0是调用者保存寄存器(a调用b的话,由a函数来管理调用者保存寄存器的内容) 调用函数f时,将保存着函数参数的a1,a0寄存器压入栈中。 这时我们可以发现,当一个参数寄存器(形式为ax)保存一个数后必定会先将其压入栈中再执行其他操...
函数调用约定:函数调用的具体步骤,包括参数传递、返回值处理等; 栈的使用:栈的增长方向、如何保存和恢复栈指针等; 系统调用:操作系统提供的服务调用方式和参数传递规则; ABI的存在使得不同的编程语言、编译器和操作系统之间能够进行二进制级的互操作,确保它们能够正确地调用和使用彼此所生成的代码。由于不同的体系结构...
函数调用过程通常分为 6 个阶段[Patterson and Hennessy 2017]。 将参数存储到被调用的函数可以访问到的位置; 跳转到函数起始位置; 获取函数需要的局部存储资源,按需保存寄存器(callee saved registers) ; 执行函数中的指令; 将返回值存储到调用者能够访问到的位置,恢复寄存器(callee saved registers),释放局部...
在RISC-V汇编语言中,函数调用的过程可以分为以下几个步骤: 1. 保存寄存器状态:在调用函数之前,需要将当前函数中需要使用的寄存器的值保存到栈中,以防止被调用函数修改这些值。通常使用指令"addi sp, sp, -n"将栈指针sp向下移动n个字节,然后使用指令"sw reg, 0(sp)"将需要保存的寄存器的值存储到栈中。 2....
3.2 函数调用规范(Calling convention) 函数调用过程通常分为 6 个阶段。 1. 将参数存储到函数能够访问到的位置; 2. 跳转到函数开始位置(使用 RV32I 的 jal 指令); 3. 获取函数需要的局部存储资源,按需保存寄存器; 4. 执行函数中的指令; 5. 将返回值存储到调用者能够访问到的位置,恢复寄存器,释放局部存储资...
Callee Saved寄存器在函数调用的时候会保存 这里的意思是,一个Caller Saved寄存器可能被其他函数重写。 假设我们在函数a中调用函数b,任何被函数a使用的并且是Caller Saved寄存器,调用函数b可能重写这些寄存器。 我认为一个比较好的例子就是Return address寄存器(注,保存的是函数返回的地址),你可以看到ra寄存器是Caller Sa...
在RISC-V架构中,函数的执行顺序遵循一定的流程。下面我们来看一下RISC-V函数执行的顺序。 1. 函数调用。 当一个函数被调用时,程序会将函数的参数传递到指定的寄存器中,然后通过JAL(Jump and Link)指令跳转到函数的入口地址。 2. 函数入口。 在函数的入口,程序会保存调用者保存寄存器的值,并为该函数创建一个新...
在add函数中,首先是在原来的地址基础上,继续开辟一块栈空间为32字节。第一步是保存返回地址,当add函数运行结束的时候跳转回原来调用的地方,并保存s0帧指针,当调用结束时,帧指针仍然执行调用之前的地址。在把常量保存至栈中后,取栈中的值进行加操作后,把结果赋值给a0作为返回寄存器,带着add函数的返回值返回。