You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言函数指针指向jmp指令而非函数实际起始地址的技术问询

为什么取函数地址得到的是jmp指令位置而非真实入口?

这个现象其实是动态链接机制里的**PLT(Procedure Linkage Table,过程链接表)**在起作用,很常见,我来给你拆解一下:

  • 首先你的观察完全正确:当你用printf("%p", &func2);打印函数地址时,输出的确实是PLT段里的jmp指令地址,而不是函数实际栈帧开始的push ebp(或者x64下的push rbp)那一行的地址。

  • 背后的原因是动态链接的延迟绑定优化:
    现代操作系统默认会把程序编译为动态链接的形式,哪怕是你自己写的本地函数,只要编译器开启了位置无关代码(PIC)选项(比如-fPIC,很多系统默认启用),链接器就会为函数生成一个PLT桩。这个桩的核心就是一条jmp指令,指向GOT(Global Offset Table,全局偏移表)中的一个条目——而GOT里的内容会在程序第一次调用该函数时,由动态链接器(比如ld-linux.so)填充为函数的真实内存地址。

  • 举个反汇编的实际例子更清楚:
    假设你的空函数func2的真实入口反汇编是这样的:

    0x0000000000400550 <func2>:
      push   rbp
      mov    rbp,rsp
      nop         # 空函数的占位指令
      pop    rbp
      ret
    

    但你通过&func2拿到的地址对应的是PLT里的条目:

    0x0000000000400430 <func2@plt>:
      jmp    QWORD PTR [rip+0x200c0a]        # 跳转到GOT里的func2条目
      push   0x0
      jmp    0x400420                        # 动态链接器的解析入口
    

    这时候printf输出的就是0x400430,也就是那条jmp指令的位置。

  • 如果想获取函数的真实入口地址,你可以:

    1. 用objdump -d your_program查看反汇编,找不带@plt后缀的符号地址;
    2. 用nm -D your_program查看符号表,找到函数的真实地址;
    3. 在程序里通过dladdr函数(需要链接-ldl库)来解析,它能返回函数的实际起始地址。

内容的提问来源于stack exchange,提问作者Bar Fins

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:28:16