指向从代码复制的函数的指针

时间:2016-07-03 10:27:46

标签: c memory-management

我正在研究内存处理,我遇到了这段代码:

void print(const char * str){
    printf(str);
}

void (*print_ptr)(const char *)=print;

void foo2(void){
    print("goo\n");
    return;
}

void baz(void){
    print("foo\n");
    return;
}

int main()
{
    char buf[256];
    void (*func_ptr)(void)=(void (*)(void))buf;
    memcpy(buf,foo2,((void *)baz)-((void *) foo2));
    func_ptr();
    return 0;
}

此代码将导致seg fault到达

func_ptr();

我不明白为什么。如果我将指针更改为指向静态函数(如func_ptr=&baz它将正常工作,但动态代码不会。) 根据我的理解,代码本身将被复制到堆栈中,应该是它 这段代码有什么问题?

1 个答案:

答案 0 :(得分:4)

您要做的是将包含foo2()的对象代码复制到缓冲区并执行它。由于以下几个原因,这不会起作用:

  1. 您的代码被复制到buf,这将被分配在数据空间中,这是不可执行的(即内存管理器不会在该内存区域设置执行权限)。

  2. 在一般情况下,代码不太可能重定位。它可能包含对自身的绝对引用,也可能包含对其余代码的相对引用,这两种代码都会在复制时中断。

  3. 您无法保证代码将按照给定的顺序使用函数进行编译,因此无法保证您只复制foo2()。实际上,无法保证编译器会将foo2()生成为单个连续的二进制blob。其中一部分可能(例如)在bar()之后。或者(相对常见的情况)函数的部分可能在入口点之前。

  4. 如果您真的想了解它为什么会中断,请使用bufmmap()MAP_ANON分配PROT_READ|PROT_WRITE|PROT_EXEC的内存来修复(1) ,然后在gdb下运行它。我建议使用-O0进行编译(禁用优化)以最大限度地提高某些工作的可能性,但我会重申你没有任何保证。

    更大的问题是为什么你要复制代码的原因。