【发布时间】:2012-10-31 16:24:16
【问题描述】:
我正在尝试用 C 和 MIPS 编写一些自我修改的代码。
因为我想稍后修改代码,所以我正在尝试编写实际的机器指令(而不是内联汇编)并尝试执行这些指令。有人告诉我,可以只需 malloc 一些内存,在那里编写指令,将 C 函数指针指向它,然后跳转到它。(我包括下面的示例)
我已经用我的交叉编译器(sourcery codebench 工具链)尝试了这个,但它不起作用(是的,事后看来,我认为它确实看起来相当幼稚)。我怎样才能正确地做到这一点?
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void inc(){
int i = 41;
uint32_t *addone = malloc(sizeof(*addone) * 2); //we malloc space for our asm function
*(addone) = 0x20820001; // this is addi $v0 $a0 1, which adds one to our arg (gcc calling con)
*(addone + 1) = 0x23e00000; //this is jr $ra
int (*f)(int x) = addone; //our function pointer
i = (*f)(i);
printf("%d",i);
}
int main(){
inc();
exit(0);}
我在这里遵循 gcc 调用约定,其中参数传递给 $a0,函数的结果预计在 $v0 中。我实际上不知道返回地址是否会被放入 $ra (但我还不能测试它,因为我无法编译。 我在指令中使用 int,因为我正在编译 MIPS32(因此 32 位 int 就足够了)
【问题讨论】:
-
当你说“它不起作用”时,会发生什么?
-
您将
malloc返回的指针存储在一个 int 中。 int 是否足够大?为什么不使用正确的指针类型?另外,您确定您的 int 是指令的正确大小吗? -
我对 MIPS 的了解还不够,但是当我完成这种工作时 (1) 您需要确保内存具有正确的权限
mprotect和 (2) 您如果架构具有不连贯的单独指令/数据缓存,则可能需要刷新指令和数据缓存。 -
请记住,
jr在将控制权转移到目标地址(本例中为$ra)之前,会从其延迟槽执行一条指令。您需要*(addone + 2)处的“安全”指令(例如nop)。 -
或者把两条指令的顺序调换一下,让addi在jr的延迟槽中。
标签: c assembly mips inline-assembly mips32