映射库函数赋值的间接指针 - C - OSX

时间:2014-10-23 12:22:34

标签: c macos assembly dynamic-library mach-o

给出以下简单的代码片段:

int main (void) {
    void* foo =  scanf;
    void* bar = sscanf;
}

这是反汇编(取自mach-o可执行文件):

enter image description here

非惰性符号指针的一小部分:

enter image description here

符号表的一小部分:

enter image description here

我似乎不理解可执行文件中的第5行和第6行(scanf& sscanf的movq到rax / rcx)。 foo和bar(最终)如何拥有scanf&的地址? sscanf分别。 我认为它与映射到进程的动态库有关(而且很可能指向那里的非惰性符号指针)但我无法理解。

感谢

2 个答案:

答案 0 :(得分:1)

dyld是动态链接器,负责绑定符号。要查看会发生什么,请首先使用-fno-pie选项编译测试项目,以禁用“位置独立可执行文件”。这样,您在MachOView中看到的偏移量在运行时将是相同的。然后启动DYLD_PRINT_BINDINGS环境变量设置为YES的可执行文件。结果如下:

$ DYLD_PRINT_BINDINGS=YES ./a.out 
dyld: bind: a.out:0x100001010 = libsystem_c.dylib:_scanf, *0x100001010 = 0x7FFF94578017
dyld: bind: a.out:0x100001018 = libsystem_c.dylib:_sscanf, *0x100001018 = 0x7FFF94578707
...

答案 1 :(得分:1)

生成的代码从非惰性符号指针加载scanf的地址。那里没什么特别的。当dyld加载可执行文件时,它会绑定"每个非惰性符号指针,将其值设置为符号的正确地址。

非惰性符号指针用于引用(1)指向不同库中的某些内容,(2)是数据引用,而不是对函数的调用。在您的示例中,您未直接致电scanf,因此它是数据引用,而scanf不在您的可执行文件中,因此它是对不同库的引用。

同一个可执行文件中的引用使用固定的PC相对偏移:编译器和链接器知道代码和数据将相互加载,因此它们可以在构建时选择偏移量。函数调用的引用是惰性的:在运行时,对函数的第一次调用首先通过dyld进行路由,它会查找符号并绑定惰性符号指针以供将来调用。

正如0xced指出的那样,你可以设置环境变量DYLD_PRINT_BINDINGS来观察dyld工作。 dyld手册页描述了您可以设置的其他变量。