为什么使用 JALR 而不是 JAL 从子程序返回
Why is JALR used instead of JAL for returning from subroutines
我了解到 jal
和 jalr
都可以用于调用函数,而相反只有 jal
可以用于从这样的函数返回:
sum3:
add a0, a0, a1
add a0, a0, a2
jalr x0, 0(ra)
但是,此代码使用 jal
而不是 jalr
从函数返回并且运行良好:
call sum3
ret_sum3:
# following instructions
# ...
sum3:
add a0, a0, a1
add a0, a0, a2
jal x0, ret_sum3
鉴于此,为什么说jalr
是函数返回的指令呢?我也可以使用 jal
。
您可能遗漏的一点是,一般来说,函数或子例程应该能够从代码中的不同位置调用(即,对子例程的多次调用分布在代码中),因此它也应该能够 return 到代码中的不同位置。
jal
指令跳转到的地址由pc
寄存器的内容加上指令中编码的21位常量偏移量决定。因此,使用 jal
进行 returning 的子例程仅限于 return 到相同(相对于 pc
固定)地址。
jal
还能用于子程序return吗?
如果您的子例程仅从代码中的一个位置调用,它仍然可以使用 jal
来 returning 到它的调用者——前提是 return 地址对应于一个内存位置与用于 returning 的 jal
指令相距大约 ±1MB。如果要防止 ra
寄存器被破坏,只需考虑将子例程调用为 jal x0, sum3
而不是 call sum3
。
我了解到 jal
和 jalr
都可以用于调用函数,而相反只有 jal
可以用于从这样的函数返回:
sum3:
add a0, a0, a1
add a0, a0, a2
jalr x0, 0(ra)
但是,此代码使用 jal
而不是 jalr
从函数返回并且运行良好:
call sum3
ret_sum3:
# following instructions
# ...
sum3:
add a0, a0, a1
add a0, a0, a2
jal x0, ret_sum3
鉴于此,为什么说jalr
是函数返回的指令呢?我也可以使用 jal
。
您可能遗漏的一点是,一般来说,函数或子例程应该能够从代码中的不同位置调用(即,对子例程的多次调用分布在代码中),因此它也应该能够 return 到代码中的不同位置。
jal
指令跳转到的地址由pc
寄存器的内容加上指令中编码的21位常量偏移量决定。因此,使用 jal
进行 returning 的子例程仅限于 return 到相同(相对于 pc
固定)地址。
jal
还能用于子程序return吗?
如果您的子例程仅从代码中的一个位置调用,它仍然可以使用 jal
来 returning 到它的调用者——前提是 return 地址对应于一个内存位置与用于 returning 的 jal
指令相距大约 ±1MB。如果要防止 ra
寄存器被破坏,只需考虑将子例程调用为 jal x0, sum3
而不是 call sum3
。