16位x86汇编中栈内值的地址计算疑问
解答你的16位x86栈寻址疑问
你的核心误解来自两个关键点:16位x86栈操作的字长特性,以及小端序的内存存储规则,咱们一步步拆解清楚:
先明确16位x86栈的基本规则
在16位实模式下,push和pop都是字操作——也就是每次操作的是2字节(16位)的数据,而非你以为的1字节。栈是向下生长的:每次push会把栈指针sp减去2,每次pop会把sp加上2。
跟踪你的代码中栈的完整变化过程
初始状态:mov bp, 0x8000、mov sp, bp,此时栈为空,sp指向栈的基址0x8000。
push "A":NASM会把单个字符"A"(ASCII码0x41)打包成一个16位的字0x0041(高字节自动补0)压入栈。此时sp变为0x8000 - 2 = 0x7FFE。- 由于x86是小端序,这个字在内存中的存储是:低字节
0x41(也就是你要的'A')存在地址0x7FFE,高字节0x00存在地址0x7FFF。
- 由于x86是小端序,这个字在内存中的存储是:低字节
push "B":同理,压入字0x0042,sp变为0x7FFE - 2 = 0x7FFC,0x42存在0x7FFC,0x00存在0x7FFD。push "C":压入字0x0043,sp变为0x7FFC - 2 = 0x7FFA,0x43存在0x7FFA,0x00存在0x7FFB。
接下来的两次pop操作:
- 第一次
pop bx:弹出栈顶的0x0043到bx,sp回到0x7FFC,你打印bl(也就是0x43,对应'C')。 - 第二次
pop bx:弹出0x0042到bx,sp回到0x7FFE,你打印bl(0x42,对应'B')。
为什么mov al, [0x7ffe]是正确的?
你要打印的'A',对应的ASCII码0x41正好存在地址0x7FFE(也就是第一次push后字的低字节位置)。而你疑惑的0x7FFF存储的是这个字的高字节0x00,打印它的话只会输出空字符,根本不是'A'。
另外补充:如果你的代码里用push byte 'A'(显式压入字节),那栈的行为才会是每次sp减1,但16位下pop依然是字操作,这种混合操作很容易出错,所以你原始代码里默认的push "A"(字操作)才是符合16位栈规范的写法。
实际运行这段代码,会依次输出C、B、A,完全符合预期,也验证了[0x7ffe]的寻址是正确的。
内容的提问来源于stack exchange,提问作者Bilal Ahmed
相关产品推荐
相关产品推荐

