gcc - __i686.get_pc_thunk 和 __x86.get_pc_thunk 有什么区别?
问题描述
GCC 和 Clang 在 32 位 x86 位置无关代码中使用这些辅助函数将当前执行地址放入寄存器,例如:
call __i686.get_pc_thunk.bx
addl $_GLOBAL_OFFSET_TABLE_, %ebx
movl $2, 4(%esp)
leal .LC0@GOTOFF(%ebx), %eax
movl %eax, (%esp)
call dlopen@PLT
似乎实现是等效的:
__x86.get_pc_thunk.bx:
movl (%esp), %ebx
ret
__i686.get_pc_thunk.bx:
movl (%esp), %ebx
ret
除了更名之外还有什么区别(似乎i686更旧)?有 i686 前缀而不是 i386 的原因吗?
解决方案
因此,在对提交历史和错误跟踪器进行了一些挖掘之后,我想我基本上已经弄清楚了。
很久以前,glibc 曾经有自己的 PIC 代码处理方式,其中涉及调用/弹出模式来获取 GOT 地址。
大约在 2002 年,__i686.get_pc_thunk.*
完成类似任务的 , 被添加到 GCC,最初是作为内部符号。
不久之后它也出现在 glibc 中,可能是为了避免在使用 GCC 编译时出现代码重复。
但是,当为 Pentium 2 或更高版本 ( -march=i686
) 构建时,GCC 定义了预处理器宏__i686=1
,破坏了 glibc 对存根代码的编译。这个问题很早就被发现了,但是几年来 glibc 使用了各种变通方法来处理这个问题。
在 2011 年(GCC 4.7?),名称更改为,__x86.get_pc_thunk.*
并且 glibc添加了一些检查以使用匹配的名称。最终对旧 GCC 版本的支持与旧名称一起被删除。GCC 和 glibc__x86.get_pc_thunk.*
现在都只能使用(尽管 GCC 也可以生成内联调用/弹出版本)。
所以,总结一下:
两者之间没有实际区别,由于预定义的宏冲突,名称更改只是历史性的。
参考:
https://gcc.gnu.org/git/?p=gcc.git&a=search&h=HEAD&st=commit&s=get_pc_thunk
https://sourceware.org/git/?p=glibc.git&a=search&st=commit&s=get_pc_thunk
推荐阅读
- typo3 - TYPO3 9.5 后端服务器时间错误
- c# - 将 StringContent Json 转换为 byte[]
- node.js - 如何使用 lambda 函数(nodejs)将 json 数据逐行导入 dynamodb
- solr - Solr如何将搜索范围缩小到特定品牌并在单个查询中获取该品牌的所有兄弟姐妹?
- ios - 使用空参数调用 IntentHandler
- python - 如何在熊猫中导入这个文件?
- python - 使用破折号的 Web 应用程序
- telegram - 从 Telegram 中收到的消息中获取机器人 ID
- c++ - shuffle() 函数和 SIMD 代码生成
- mysql - ERROR 1064 (42000): MySql Database Setup/Recovery Issue from Backupon Mac