有趣的 GCC 链接

Interesting GCC Linking

我最近在研究符号和函数指针,发现尽管以下代码运行良好:

#include <stdio.h>
int main(int argc, const char * argv[]) {
    printf("%p\n",printf); // <--this line makes it work
    int (*printfptr)(const char * restrict, ...);
    printfptr = 0x1001fe910;
    (*printfptr)("Hello world\n");
    return 0;
}

这不是:

#include <stdio.h>
int main(int argc, const char * argv[]) {
    // printf("%p\n",printf); // <-- commenting this out breaks it
    int (*printfptr)(const char * restrict, ...);
    printfptr = 0x1001fe910;
    (*printfptr)("Hello world\n");
    return 0;
}

(EXC_BAD_ACCESS)

当代码中没有对 printf 的引用时,为什么取消引用完全相同的指针会导致问题?即使这样也能正常工作:

#include <stdio.h>    
int main(int argc, const char * argv[]) {
    int (*printfptr)(const char * restrict, ...);
    printfptr = 0x1001fe910;
    (*printfptr)("Hello world\n");
    return 0;
}
void *_ = printf; // <-- because of this

这是为什么?

在共享对象 (.so) 上,符号仅在首次使用时才真正解析。默认情况下,linker 设置选项 -z lazy 告诉:

       When generating an executable or shared  library,  mark  it  to
       tell  the  dynamic  linker to defer function call resolution to
       the point when the function is called  (lazy  binding),  rather
       than at load time.  Lazy binding is the default.

您可以通过提供选项 -z now 来更改该行为。

man ld 所有血淋淋的细节。

编辑:在 POSIX 系统上使用动态 link API 解析符号。在 <dlfcn.h> 中定义的函数 dlsym()dlopen()dlclose()dlerror()。此版本添加,以便您可以搜索这些名称。