C++编译生成的汇编代码中cs:前缀的含义是什么
问题背景
为深入理解C++程序底层运行逻辑,尝试查看编译后生成的汇编文件,当前使用的编译环境为Windows 10 + WSL,使用的编译命令为g++ -c。
编写的测试代码如下:
int main() { static int c{12345}; }
查看对应汇编代码时,.data段中对该静态变量的定义如下:
.data:0000000000000080 ; =========================================================================== .data:0000000000000080 .data:0000000000000080 ; Segment type: Pure data .data:0000000000000080 ; Segment permissions: Read/Write .data:0000000000000080 _data segment dword public 'DATA' use64 .data:0000000000000080 assume cs:_data .data:0000000000000080 ;org 80h .data:0000000000000080 ; int main::c .data:0000000000000080 _ZZ4mainE1c dd 3039h ; DATA XREF: main+1E↑r .data:0000000000000080 _data ends
main函数中访问该静态变量的汇编指令如下:
.text:000000000000004B mov eax, cs:_ZZ4mainE1c ; main::c
核心疑问:上述汇编代码中出现的cs:部分具体代表什么含义?
解答
这里的cs:是x86/x86-64汇编语法中的段超越前缀,对应代码段寄存器(Code Segment Register),但在64位程序汇编场景下,它没有传统段机制下“切换访问段”的实际作用,具体逻辑如下:
- 首先注意.data段反汇编里的
assume cs:_data标记,这是反汇编工具(该输出是IDA类工具的典型风格)自行添加的段假设标注,不是编译器生成的机器码里真的强制要求从CS段寻址这个变量。 - x86-64长模式(即当前64位程序的运行模式)下,CS、DS、SS、ES四个传统段寄存器的段基址被硬件强制设为0,段覆盖范围为整个64位地址空间,内存权限检查完全由页表负责,传统的段式内存地址翻译机制已经失效。这时候给普通内存访问指令加
cs/ds/ss这类段前缀,最终计算出的内存访问地址完全一致,不会真的访问不同的内存区域。 - 反汇编器在这里显示
cs:前缀,是因为64位程序访问全局、静态变量默认使用RIP相对寻址(相对于当前指令指针的偏移计算目标地址),对于这类和程序映像绑定的符号,部分反汇编工具会默认加上cs:作为标记,仅表示该地址属于当前程序的虚拟地址空间,不代表变量真的存放在代码段里——从段属性就能看到,_ZZ4mainE1c(即main函数内的静态变量c)明确定义在可读写的.data段,和只读可执行的.text代码段属性完全不同。 - 补充说明:64位模式下只有FS、GS两个段寄存器还保留了自定义段基址的能力,通常用于访问线程局部存储、内核每CPU数据等特殊内存区域,其余段寄存器的段超越前缀基本都不会产生实际的地址翻译差异。
内容的提问来源于stack exchange,提问作者shiyon sufa
相关产品推荐
相关产品推荐

