为何访问16位寄存器存储的值触发段错误,32位寄存器却正常?
问题分析与解决:x86-64下16位寄存器寻址触发段错误
核心原因:x86-64地址模式与16位寻址的冲突
在x86-64架构的Linux用户态环境中,程序默认运行在64位地址模式。当你使用16位寄存器(如si、bp)进行内存寻址时,CPU会强制切换到16位地址规则:
- 16位模式下,内存地址由
段寄存器值<<4 + 偏移量计算,最大寻址范围仅64KB - 现代Linux程序的代码段、数据段、栈段都映射在远大于64KB的高位地址空间,用16位寄存器计算出的地址必然无效,直接触发段错误。
而改用32位寄存器(如esi、ebp)或64位寄存器(如rbp)时,CPU会按32/64位地址模式处理,能正确访问程序的合法内存空间,因此不会出错。
代码修正方案
第一段数组操作代码
原问题:si是16位寄存器,无法存储现代程序中超过64KB的数组地址,寻址时直接越界。
修正:使用32位/64位寄存器存储地址:
myArray db 1,2,3,4; 已在正确段声明 ;----------------- mov esi, myArray ; 用32位寄存器存储数组地址 mov ax, [esi] ; 正常访问内存 sub ax, [esi+1] mov [esi+3], ax
第二段栈操作代码
原问题:bp是16位寄存器,ss:[bp]会按16位栈地址规则寻址,而x86-64的栈是64位宽,栈地址远超出16位范围。
修正:使用64位寄存器rbp:
mov dx, 1234h push dx mov dx, 0ABCDh push dx mov rbp, rsp ; 用64位寄存器指向栈顶 mov ax, ss:[rbp]
关于“语法错误”的说明
你的代码语法本身没有问题,但不符合x86-64默认地址模式的运行规则。16位寄存器寻址仅在x86-64的16位兼容模式下有效,而现代Linux用户态程序默认运行在64位模式,因此这种写法会导致非法内存访问。
内容的提问来源于stack exchange,提问作者Shadows_Puppet
相关产品推荐
相关产品推荐

