C中的函数指针相等

fon*_*ons 15 c unix function-pointers elf dynamic-loading

我的问题:

  1. 函数指针是否由C标准保证?
  2. 如果(1)的答案是肯定的.是不是在不同的最终编译单元(例如主可执行文件和共享库)中获得指针的情况?
  3. 动态加载器如何处理?(我可以考虑一些可能导致棘手问题的原因,所有这些都与PIC代码有关(例如,精灵中的GOT表和COFF使用的等效表格)).无论(1)和(2)如何,linux加载器似乎都能保证这一点.

这是一个例子.上面的问题归结为C是否保证main.c打印: "Function equality: 1"或者"Function equality: 0",在第一种情况下,动态加载器如何实现这一点.

common.h:

extern void * getc_main;
extern void * getc_shared;
void assign_getc_shared(); 
Run Code Online (Sandbox Code Playgroud)

main.c:

#include <stdio.h>
#include "common.h"

int main()
{
  getc_main = (void*) getc;
  assign_getc_shared();
  printf("Function equality: %d\n", getc_main == getc_shared);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

shared.c:

#include <stdio.h>
#include "common.h"

void assign_getc_shared()
{
   getc_shared = (void*) getc;
}
Run Code Online (Sandbox Code Playgroud)

在Unix中,这将使用以下命令进行编译:

cc -shared -fPIC -o libshared.so shared.c
cc -o main main.c -L. -lshared
Run Code Online (Sandbox Code Playgroud)

并执行:

LD_LIBRARY_PATH=. ./main
Run Code Online (Sandbox Code Playgroud)

Eri*_*hil 14

C 2011(N1570委员会草案)6.5.9 6:"两个指针比较相等,当且仅当......两者都指向相同的......函数....... 所以,是的,同一个函数的两个指针比较相等.

当函数的地址在两个不同的对象模块中获取时,编译器将占位符放在目标代码中.当对象模块链接到可执行文件或在运行时与动态库链接时,将填充该占位符.

对于动态库,动态加载器根据需要填充可执行文件中的所有占位符,或者每个函数的地址实际上是跳转到实际函数的某些存根代码的位置,并且该存根代码中的占位符被填充或使用在动态加载器中.

另外,请注意,可执行文件可以包含多个函数实例.编译器可能会在几个地方插入函数内联,或者由于其自身的原因,可能包括函数的特化以及通用版本.但是,当执行函数的地址时,编译器必须提供单个通用版本的地址.(或者编译器必须确保程序的行为就像完成一样.例如,如果编译器可以检测到程序没有比较指针,那么理论上它可以为地址的某些实例使用不同的地址功能.)

  • @tristopia:我看不出你的结论如何.每个地址具有4096个潜在表示的事实不会阻止编译器确保相同地址的不同表示相等.编译器不需要用单个指令实现`a == b`; 可以自由地执行算术将`a`和`b`中的每一个从它们所处的格式转换为完整的唯一地址,然后比较生成的完整地址. (4认同)
  • 此外,编译器可以控制地址的获取,因此可以确保使用函数地址的特定表示,而不使用其他表示. (3认同)