【发布时间】:2016-04-02 01:55:48
【问题描述】:
我正在 Linux 上使用函数指针进行实验并尝试执行这个 C 程序:
#include <stdio.h>
#include <string.h>
int myfun()
{
return 42;
}
int main()
{
char data[500];
memcpy(data, myfun, sizeof(data));
int (*fun_pointer)() = (void*)data;
printf("%d\n", fun_pointer());
return 0;
}
不幸的是,它在fun_pointer() 调用时出现了段错误。我怀疑它与一些内存标志有关,但我没有找到有关它的信息。
您能解释一下为什么这段代码会出现段错误吗?不要看到固定的data数组大小,没问题,不调用函数复制成功。
UPD:最后我发现应该使用带有PROT_EXEC 标志的mprotect 系统调用将内存段标记为可执行。此外,内存段应由 POSIX 规范中所述的mmap 函数返回。
mmap 内存分配的代码与 PROT_EXEC 标志使用的代码相同(并且有效):
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
int myfun()
{
return 42;
}
int main()
{
size_t size = (char*)main - (char*)myfun;
char *data = mmap(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
memcpy(data, myfun, size);
int (*fun_pointer)() = (void*)data;
printf("%d\n", fun_pointer());
munmap(data, size);
return 0;
}
此示例应遵守-fPIC gcc 选项,以确保函数中的代码与位置无关。
【问题讨论】:
-
几乎可以肯定与以下错误相同:stackoverflow.com/a/7432634/168175
-
您能否解释一下为什么您希望它不会出现段错误?对我来说很明显,如果您尝试执行一个不指向代码的随机指针,它将出现段错误。
-
指针指向
myfun的代码副本,因为我将此代码复制到data数组中。 -
编译时,始终启用所有警告。 (对于 gcc,至少使用:
-Wall -Wextra -pedantic)然后修复这些警告。发布的代码会发出一整串警告。 -
我使用了类似的代码,这使我的程序几乎可以运行。我将它移植到 c++,我可以编辑变量并在函数中返回它们,但我无法从“myfun”函数执行其他函数。它们会导致段错误。有什么办法吗?