C++的哪些功能利用了JR指令?
What feature of C++ makes use of JR instructions?
MIPS跳转寄存器(JR(指令经常出现在C++代码的二进制文件中。因此,C++中的哪些功能使用了JR指令,为什么使用这些指令?
分支指令只能用于目标地址在编译时已知且在当前指令的较小范围内的情况。您不能(轻松(使用它来分支到静态未知且必须在运行时计算/加载的地址,或者跳转到太远的目标
因此,这里有一些必须使用JR
或JALR
的示例(两者都完全相同,只是JALR
存储当前地址以供以后返回(:
-
跳转到任意地址:静态分支指令不能用于跳转到 32 位或 64 位地址,因为即时地址只有 16 或 26 位长。您需要在寄存器中加载完整地址并使用
JR
/JALR
跳转
函数 指针:调用函数仅在运行时已知,因此显然您需要某种方法来动态调用它
int Add(int a, int b); int Sub(int a, int b); int Mul(int a, int b); int Div(int a, int b); int (*p[4]) (int x, int y) = { Add, Sub, Mul, Div }; int test_function_pointer(int i, int x, int y) { return p[i](x, y); }
共享库中的函数(*.dll,*.so...(在加载之前也不知道进程,因此,如果您手动加载这些库(使用
LoadLibrary()
,dlopen()
...(,您还将获得函数指针的地址并使用JR
/JALR
调用它们。通常,函数将使用JALR
调用,但如果它位于函数的末尾并且启用了尾调用优化,则将使用JR
Vtable在许多OOP语言中,如C++也是函数指针的一个例子
struct A { virtual int getValue() = 0; }; int test_vtable(A *a) { return a->getValue() + 1; }
在Godbolt的编译器资源管理器上的演示
跳台(就像在一个大开关块中(
typedef int (*func)(int); int doSomething(func f, int x, int y) { switch(x) { case 0: return f(x + y); case 1: return f(x + 2*y); case 2: return f(2*x + y); case 3: return f(x - y); case 4: return f(3*x + y); case 5: return f(x * y); case 6: return f(x); case 7: return f(y); default: return 3; } }
GCC 将上述代码编译为
doSomething(int (*)(int), int, int): sltu $2,$5,8 beq $2,$0,$L2 # x >= 8: default case move $25,$4 lui $2,%hi($L4) addiu $2,$2,%lo($L4) # load address of $L4 to $2 sll $5,$5,2 # effective address = $L4 + x*4 addu $5,$2,$5 lw $2,0($5) nop j $2 nop $L4: .word $L11 .word $L5 .word $L6 .word $L7 .word $L8 .word $L9 .word $L10 .word $L11 $L11: jr $25 move $4,$6 $L9: sll $4,$6,2 jr $25 addu $4,$4,$6 # ... many more cases below
您可以在编译器资源管理器上看到完整的输出
$L4
是一个跳转表,其中包含您要分支到的位置的地址,即此代码段中的case
块。它的地址存储在$2
中,需要使用jr
将指令指针移动到该地址。j $2
如上所示,但我认为这是一个反汇编器错误,因为j
无法接收寄存器操作数。一旦你处于正确的大小写,那么jr
将再次用于调用f
函数指针
另请参阅MIPS组装中J与JAL的必要性(以及JR与JALR(的必要性
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 无法编译 rtmidi 测试 cmidiin.cpp 文件, 非法指令
- C++:对不存在的命名空间使用命名空间指令
- 函数名是c中该函数的第一条指令的地址吗
- 错误:无效的预处理指令 #i 的意思是 #if?
- 组装指令中乘法的下部和上部是什么
- OpenMP 与有序和关键指令并行
- C++中的移动分配出现问题.非法指令: 4.
- 嵌套命名空间的"using"指令,但需要命名内部命名空间
- C++CMake编译指令与
- 使用宏扩展的泛型:为什么指令缓存使用不当?
- 如何在 c++ 中确定一条指令(以字节为单位)在哪里结束,另一条指令从哪里开始?
- AVX 指令中寄存器和指针之间的客观差异
- while 循环 c++ 中的非法指令
- 如何在编译时定义C++预处理器指令的值?
- 存储指令是否会阻止缓存未命中的后续指令?
- 保证编译器指令在C++中重新排序
- VS2008中的AVX-512指令库
- 令人困惑的定义指令在C ++项目中
- C++的哪些功能利用了JR指令?