我正在尝试调用本机语言代码。下面是我到目前为止所得到的(它得到一个总线错误):
char prog[] = {'\xc3'}; // x86 ret instruction
int main()
{
typedef double (*dfunc)();
dfunc d = (dfunc)(&prog[0]);
(*d)();
return 0;
}
它确实正确地调用了函数,并到达ret指令。但是当它尝试执行ret指令时,它会出现SIGBUS错误。是不是因为我在一个页面上执行代码,而这个页面并没有被清除,或者类似的东西?
那么我到底做错了什么呢?
发布于 2016-10-05 15:16:26
第一个问题可能是存储prog数据的位置是不可执行的。
至少在Linux上,生成的二进制文件会将全局变量的内容放在"data" segment或here中,这在most normal cases中是无法执行的。
第二个问题可能是您正在调用的代码在某种程度上是无效的。在C中有一个调用方法的特定过程,称为calling convention (例如,您可能正在使用"cdecl“方法)。对于被调用的函数来说,仅仅"ret“可能是不够的。它可能还需要做一些堆栈清理等工作,否则程序会意外地运行。一旦你解决了第一个问题,这可能会成为一个问题。
发布于 2016-10-05 16:01:55
为了使prog所在的页面成为可执行的页面,您需要调用memprotect。下面的代码进行了这个调用,并且可以执行prog中的文本。
#include <unistd.h>
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
char prog[] = {
0x55, // push %rbp
0x48, 0x89, 0xe5, // mov %rsp,%rbp
0xf2, 0x0f, 0x10, 0x05, 0x00, 0x00, 0x00,
//movsd 0x0(%rip),%xmm0 # c <x+0xc>
0x00,
0x5d, // pop %rbp
0xc3, // retq
};
int main()
{
long pagesize = sysconf(_SC_PAGE_SIZE);
long page_no = (long)prog/pagesize;
int res = mprotect((void*)(page_no*pagesize), (long)page_no+sizeof(prog), PROT_EXEC|PROT_READ|PROT_WRITE);
if(res)
{
fprintf(stderr, "mprotect error:%d\n", res);
return 1;
}
typedef double (*dfunc)(void);
dfunc d = (dfunc)(&prog[0]);
double x = (*d)();
printf("x=%f\n", x);
fflush(stdout);
return 0;
}
发布于 2016-10-05 18:57:55
正如每个人已经说过的,你必须确保prog[]
是可执行的,但是正确的方法是将符号放在可执行区域中,或者使用链接器脚本,或者在编译器允许的情况下指定C代码中的节,例如:
const char prog[] __attribute__((section(".text"))) = {...}
https://stackoverflow.com/questions/39867396
复制相似问题