C-通过func_ptr调用函数,为什么不起作用?

C-通过func_ptr调用函数,为什么不起作用?,c,function,pointers,C,Function,Pointers,我有以下代码: void print(const char* str){ system_call(4,1,str,strlen(str)); } void foo2(void){ print("goo \n");} void buz(void){ ...} int main(){ char buf[256]; void (*func_ptr)(void)=(void(*)(void))buf; memcpy(buf,foo2, ((void*)buz)-((v

我有以下代码:

void print(const char* str){
      system_call(4,1,str,strlen(str)); }

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


void buz(void){ ...}

int main(){
char buf[256];
    void (*func_ptr)(void)=(void(*)(void))buf;
    memcpy(buf,foo2, ((void*)buz)-((void*)foo2));
    func_ptr();
    return 0;
}
问题是,为什么这一准则会失效

答案是,不是通过指针调用函数是指向一个相对地址,但我还没有弄清楚这里出了什么问题?哪一行是有问题的


感谢您的帮助

首先,没有什么规定foo2()和buz()在内存中必须相邻。另一方面,正如你所猜测的,代码必须是相对的,这样的特技才能发挥作用。但最重要的是,这是标准不允许的


正如Chris Luts所提到的,堆栈(自动)变量在许多操作系统上不可执行,以防止攻击。

main()函数的前两行有问题

第1行<代码>(无效(*)(无效))buf 未定义将buf转换为函数指针

第2行<代码>((void*)buz)-(void*)foo2) 除非指针指向同一数组,否则指针的减法是未定义的


此外,
H&S
第5.8节函数
中说:“尽管指向函数的指针通常被认为是函数在内存中的代码地址,但在某些计算机上,函数指针实际上指向调用函数所需的信息块。”,C函数指针机制用于等签名函数调用抽象。如果没有这些特技,这是非常强大和容易出错的

我看不出将代码从一个地方复制到另一个地方有什么好处/意义。正如一些人所评论的,很难判断C函数中的相对性/可重新定位代码的数量

您尝试将函数的代码复制到数据存储区域。一些微控制器会告诉你“走开!”。在具有数据/程序分离内存的机器体系结构上,如果有一个非常理解的编译器(或识别数据/代码修饰符/属性的编译器),它将编译为特定的代码数据移动指令。这会有用的。。。然而,即使在数据/代码分离的内存ARCH中,也不可能执行数据内存指令


另一方面,在“普通”数据/代码共享内存PC中,它也可能无法工作,因为数据/代码段(由加载程序)在处理器的MMU上声明。根据处理器和操作系统的不同,试图在数据段上运行代码是段错误。

因为这是未定义的行为,法律允许它做任何事情?除此之外,您可能需要使
buf
中的数据可执行。操作系统有防止人们这样做的保护措施。你似乎在
print
上遗漏了一个
}
。嗯,从病毒代码的外观来探索它。你成了一个基本的受害者,相对寻址。绝对寻址漏洞也被堵住了,它被称为“地址空间布局随机化”。最近,NX位被添加到内核中。你不能只移动可执行字节,而不正确地重新定位任何必要的符号。我甚至没有想到这一点。有趣。同样在第2行中,将函数指针强制转换为非函数指针类型是非法的。@Chris Lutz:我认为将函数指针强制转换为(void*)是允许的。对生成的void指针唯一定义的操作是将其转换回原始函数指针类型。@sigjuice-您可能错了。您可以将它们强制转换为通用函数指针类型(我使用
typedef void(*func)(void);
我自己)并自由返回,但C标准不允许将它们强制转换为
void*
。(我相信POSIX确实允许将它们强制转换为
void
)@Chris Lutz H&S的“5.3.3一些指针注意事项”说“在标准C中,void*可以用作通用对象指针,但没有通用函数指针。”检查标准本身。我想引用一下,但我现在正在使用iPhone。首先,感谢大家的回复。据我所知,这种想法本身是不可能的,而且,将编译后的代码复制到数据段中,并从该段运行代码将导致分段错误。相对呼叫的想法是次要的,但对于这些“特技”的工作仍然很重要。再说一次,你的信息是无价的。这并非不可能,但您必须非常幸运地找到编译器和操作系统的组合,这将导致代码正常工作。如果您想复制代码,直接使用汇编程序更容易。