为什么在64位模式下使用"DS:"段覆盖无效? [英] Why is the use of the 'DS:' segment override illegal in 64-bit mode?

查看:174
本文介绍了为什么在64位模式下使用"DS:"段覆盖无效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有几行汇编代码,它们围绕一些数据移动,如下所示:

I have a pretty simple few lines of assembly code, which moves around some data, like this:

mov rax,qword ptr gs:[60]                         
mov rcx,qword ptr ds:[rax+20]                                         
mov rax,qword ptr gs:[60]                         
mov rcx,qword ptr ds:[rax+20]                     
mov rbx,qword ptr ds:[rcx+28] 

但是,编译器会返回

错误A2202:非法使用段寄存器

error A2202:illegal use of segment register

我觉得这可能是我的编译器或版本存在的问题,任何指针都将有所帮助

I have a feeling this may be an issue with my compiler or version, any pointers would be helpful

推荐答案

cs / ds / es / ss 段覆盖前缀 在64位模式下的机器代码中是允许的.但是一些汇编程序选择不允许它们.

cs/ds/es/ss segment override prefixes are allowed in machine code in 64-bit mode. But some assemblers choose not to allow them.

但是请注意,它们实际上对具有内存操作数的指令没有影响.这也许就是为什么masm显然选择不允许它的原因,以免使您避免浪费这样的前缀上的空间.其他汇编程序(例如NASM)也允许这样做.

But note that they have literally no effect on instructions with memory operands. This might be why masm apparently chooses not to allow it, to save you from the "mistake" of wasting space on such prefixes. Other assemblers, like NASM, do allow it.

所有这些段都具有相同的固定基地址= 0,甚至不更改将引发的异常.

All those segments have the same fixed base address=0, and don't even change which exception would be raised.

英特尔手册第1卷3.3.7.1规范寻址:

Intel manual vol.1 3.3.7.1 Canonical Addressing:

如果一条指令使用基址寄存器RSP/RBP并使用段覆盖前缀来指定非SS段,则规范故障会生成#GP(而不是#SS).在64位模式下,仅FS和GS段替代适用于这种情况.其他细分受众群覆盖前缀(CS,DS,ES和SS)将被忽略.请注意,这也意味着忽略了应用于非堆栈"寄存器引用的SS段替代.这样的序列仍然会产生#GP代表规范错误(而不是#SS).

If an instruction uses base registers RSP/RBP and uses a segment override prefix to specify a non-SS segment, a canonical fault generates a #GP (instead of an #SS). In 64-bit mode, only FS and GS segment-overrides are applicable in this situation. Other segment override prefixes (CS, DS, ES and SS) are ignored. Note that this also means that an SS segment-override applied to a "non-stack" register reference is ignored. Such a sequence still produces a #GP for a canonical fault (and not an #SS).

例如如果 mov eax,ds:[rbp] 是来自非规范地址的错误(高16位不是低48的正负号扩展),仍然是#SS错误(因为基数寄存器是RBP或RSP),而不是#GP.DS前缀确实会被忽略.

e.g. if mov eax, ds:[rbp] faults from a non-canonical address (high 16 bits aren't the sign-extension of the low 48), it's still a #SS fault (because the base register is RBP or RSP), not #GP. The DS prefix is really ignored.

您能分辨出差异的唯一另一种方法是,是否有可能为DS提供一个段选择器,如果任何加载或存储尝试使用它,该段选择器将出错,然后运行 mov eax,[ds:rbp] .但是我不确定是否有可能.尝试在Linux中设置非零值时,我立即在 mov ds,eax 上遇到了段错误.对于DS和ES,空段选择器起作用".鉴于NASM和FASM的汇编程序警告/行为,这些汇编程序的开发人员至少认为段前缀确实毫无意义.

The only other way you could tell the difference would be if it's possible to give DS a segment selector that will fault if any load or store tries to use it, then run mov eax, [ds:rbp]. But I'm not sure that's possible; I was getting a segfault right away on mov ds, eax when trying to set a non-zero value in Linux. NULL segment selectors "work" for DS and ES. Given the assembler warnings / behaviour of NASM and FASM, the developers of those assemblers at least think the segment prefixes truly are meaningless.

它们可以具有非零的基地址.

They can have non-zero base addresses.

CS/DS/ES/SS仅用于填充以使指令更长(出于对齐原因).可以使用哪些方法在现代的x86上有效地扩展指令长度?

请注意,除了 rbp / rsp 以外, ds 已经是所有基址寄存器的默认段,因此,显式的 ds 前缀根本不会改变指令的含义,即使它没有被忽略.如果您的汇编器拒绝接受 mov rcx,qword ptr ds:[rax + 20] ,则也有理由拒绝接受 mov ecx,dword ptr ds:[eax + 20](在32位模式下).

Note that ds is already the default segment for all base registers other than rbp / rsp, so an explicit ds prefix wouldn't change the meaning of the instruction at all even if it wasn't ignored. If your assembler refuses to accept mov rcx,qword ptr ds:[rax+20], it would be reasonable to also refuse to accept mov ecx, dword ptr ds:[eax+20] in 32-bit mode.

对于某些汇编程序(例如NASM),在asm源代码行中明确提及段会在指令上发出段前缀,即使它已经是默认值也是如此.将其用于文档化"目的不是一个好主意.

For some assemblers (e.g. NASM), mentioning a segment explicitly in an asm source line emits a segment prefix on the instruction, even if it's already the default. If that's how MASM works, then it's not a good idea to use it for "documentation" purposes.

如果您确实要发出用于填充的DS前缀,只需对其明确编码:

If you do want to emit DS prefixes for padding, just encode them explicitly:

mov   rax, gs:[60]
db    3Eh   ; ds prefix
mov   rcx, [rax+20]


其他汇编程序(GAS、NASM)

有趣的是,在GAS的 .intel_syntax noprefix (类似于MASM)中, ds:[rax + 20] 组装时没有显式前缀(因为它已经是默认值)),但 ss:[rax + 20] 确实会发出一个前缀.因此,即使在64位代码中,GAS也不认为cs/ds/es/ss是等效的.


Other assemblers (GAS, NASM)

Interestingly, in GAS's .intel_syntax noprefix (which is MASM-like), ds:[rax+20] assembles without an explicit prefix (because it's already the default), but ss:[rax+20] does emit a prefix. So GAS doesn't assume that cs/ds/es/ss are equivalent even in 64-bit code.

NASM警告: segments.asm:5:警告:生成了ds段基础,但在64位模式下将被忽略

mov rax, [gs: 60]             ; NASM requires the seg: to be
mov rcx, [ds: rax+20]         ;  inside the [] if present
mov rcx, [rax+20]

与NASM组装到此( objdump -drwC -Mintel 输出):

assembles with NASM to this (objdump -drwC -Mintel output):

  4000b0:       65 48 8b 04 25 3c 00 00 00      mov    rax,QWORD PTR gs:0x3c
  4000b9:       3e 48 8b 48 14          mov    rcx,QWORD PTR ds:[rax+0x14]
  4000be:       48 8b 48 14             mov    rcx,QWORD PTR [rax+0x14]

这篇关于为什么在64位模式下使用"DS:"段覆盖无效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆