我不知道JAL在RISC-V中的工作方式,因为我看到了多个冲突的定义。例如,如果我引用此网站: https://rv8.io/isa.html
它说:
JAL rd,offset
使用第三个参数作为偏移量,但是在某些情况下,显示JAL rd, imm
代替。有什么区别?
似乎JAL应该接受一个函数并在rd中返回其输出(我不知道为什么某些来源同时将其命名为ra
和rd
)。但是,如果是这样,子例程或函数是什么? rd
似乎被定义为寄存器的目标,而imm
似乎只是一个整数。.
真的很困惑,请帮忙。
答案 0 :(得分:2)
似乎您在混淆机器代码和汇编语言。
从机器代码的角度来看,整个指令及其所有字段都是简单的数字:
这些编码由指令集体系结构定义。硬件经过专门设计,可以根据其ISA规范解释这些数字位字段。
汇编器,链接器和操作系统加载器共同使您可以使用符号值来形成指令,而不是使用各个字段的数字(甚至整个指令甚至是一个数字):
我不会太在意一个文本是指ra
与rd
。它可以表示,或者只是记录指令机器码字段的另一种方式。
JAL指令对两个操作数进行编码:一个寄存器和一个立即数。
使用返回地址的位置(即jal指令的位置)加上jal指令的长度来更新所标识的寄存器号,以便寄存器获取下一个顺序的值(by 地址)在jal之后的指令,这是调用的正确返回地址。
就像指令中的所有位字段一样,立即数是一种编码-解码后的值最终产生分支目标地址。通过将立即数位字段转换为带符号的偏移量进行计算,并将其添加到jal指令的pc中。编码允许18位(分布在几个位字段中)和一个符号位,并且不对偏移量的最后一位进行编码(分支目标始终为16位对齐,这意味着最后一位始终为零,因此未存储)。最终jal可以从jal指令本身达到-0.5MB到+ 0.5MB。
如前所述,执行硬件将立即(子)字段转换为偏移量,并将其添加到pc中以标识最终的分支/调用目标。我们可以用汇编语言提供标签和其他复杂表达式是这些语言的功能,其目的是将标签和其他表达式压缩为处理器所需的立即数位字段常量。目标代码中的重定位和/或已加载的代码中的修复程序之间存在复杂的交互作用,以确保这些立即数位字段具有有用的位模式,硬件可以根据相对简单的字段提取和运行时添加来在硬件上使用它们,以达到预期的目的。
要使函数相互调用而又不会踩到对方的脚趾,调用者和被调用者的asm代码必须达成以下所有条件:
这被广泛称为调用约定。它决定了呼叫者如何与被呼叫者一无所知,反之亦然。它对哪个寄存器或堆栈位置保存第一个参数,第二个等等施加了软件约定要求。哪个寄存器或堆栈位置保存了返回地址,关于如何传递返回值以及保留调用者环境的哪些寄存器通话或可能被通话擦除(刮擦)。
正确遵守约定后,调用者(不知道被调用者的实现,只能知道参数的类型和返回值,也就是函数签名)
答案 1 :(得分:2)
在jal
指令中,imm
(或imm20
)是20位二进制数。
offset
是imm
指令对jal
的解释:imm
的内容左移1个位置,然后加符号-扩展为地址的大小(当前为32或64位),从而使整数值从-1百万(大约)到+1百万。
此offset
整数被添加到jal
指令本身的地址中,以获取您要调用的函数的地址。将该新地址放入PC,然后使用该地址上的任何指令恢复执行程序。
同时,jal
之后的指令的地址存储在CPU寄存器rd
中。被调用的函数可能稍后会使用jalr rn
指令使用此函数返回。
RISC-V硬件允许将32个整数寄存器中的任何一个指定为rd
。如果将寄存器0(x0)设置为rd
,则返回地址将被丢弃,您实际上将拥有一个+ / 1 MB的goto
而不是函数调用。
标准RISC-V ABI(软件约定,与硬件无关)规定,对于正常功能,rd
应该是寄存器1(x1),然后通常称为ra
(退货地址)。寄存器5(x5)也通常用于特殊的运行时库函数,例如用于在函数的开头和结尾保存和恢复寄存器的特殊函数。
RISC-V指令集手册建议CPU设计人员可以选择添加特殊硬件(return address stack
),以使jal x1/x5,offset
和`jalr x1 / x5'的严格嵌套对的运行速度比否则将是预期的,因此遵循标准ABI可能会有好处。但是,即使使用其他寄存器,该程序也可以正常运行。