x64汇编中从数据结构取数为何需使用子寄存器?
x64汇编中结构体字段转存到rdi必须用子寄存器的原因
问题核心在于内存操作数的大小歧义和零扩展的正确实现方式:
1. 直接MOV指令的操作数大小问题
你的结构体里sin_family、sin_port都是2字节的RESW类型,直接写 MOV rdi, [sa+sin_family] 时,汇编器无法确定你要从内存读取多少字节——是2字节、4字节还是8字节?x64的MOV指令要求内存操作数的大小必须和寄存器大小匹配,或通过指令前缀明确指定,否则会直接报错(比如NASM会提示error: invalid combination of opcode and operands)。就算某些汇编器默认按8字节读取,也会把sin_family后面的sin_port等数据一并读进rdi,导致值完全错误。
2. 子寄存器中转实现安全零扩展
你用的中转写法是正确的逻辑:
XOR rbx, rbx ; 先把rbx整个64位寄存器清零 MOV bx, [sa+sin_family] ; 只读取内存中的2字节,写入rbx的低16位(bx),高48位保持0 MOV rdi, rbx ; 把零扩展后的64位值传给rdi
x64架构中,写入16位子寄存器(如bx)时不会影响高48位的值,配合前置的XOR清零操作,就能得到正确的零扩展结果,确保rdi里是目标2字节字段的64位合规表示。
补充:更简洁的替代写法
其实不用中转也能实现,直接用MOVZX指令明确做零扩展:
MOVZX rdi, WORD [sa+sin_family]
这条指令会直接读取内存中的16位值,自动零扩展为64位后写入rdi,效果和中转方式完全一致,代码更紧凑。
内容的提问来源于stack exchange,提问作者Ben1782
相关产品推荐
相关产品推荐

