繁体   English   中英

[ebp * 2]是否引用DS或SS段?

[英]Does [ebp*2] reference DS or SS segment?

IDM表示,如果EBP用作基址寄存器,则内存操作使用SS段。 结果, [ebp + esi][esi + ebp]引用SS和DS段。 参见NASM的文档: 3.3有效地址

在上面的相同章节中,NASM提到了如何通过用[eax+eax]替换[eax*2]来生成更短的机器代码。

但是,NASM还为[ebp*2]生成[ebp + ebp] [ebp*2] (即没有基址寄存器)。

我怀疑[ebp+ebp]引用SS段, [ebp*2]引用DS段。

我问NASM这个问题。 他们认为[ebp*2][ebp+ebp]是相同的,但对我来说没有意义。 显然, [ebp+ebp] (ebp作为基址寄存器)引用SS段。 如果它们相同, [ebp*2必须引用SS。 这意味着只要ebp是基数或索引寄存器就可以引用SS,这反过来意味着[ebp + esi][esi + ebp]引用SS段,因此它们必须相同。

有谁知道哪个段[ebp*2]使用?

英特尔手册在下面的图3-11中告诉我们,它涉及Offset = Base + (Index * Scale) + Displacement

通用寄存器作为基本或索引组件的使用受到以下方式的限制:

  • ESP寄存器不能用作索引寄存器。
  • 当ESP或EBP寄存器用作基础时 ,SS段是默认段。 所有其他情况下 ,DS细分是默认细分。

这意味着NASM在将[ebp*2]更改为[ebp+ebp]时是错误的(为了避免32位位移)。

[ebp*2]使用DS因为ebp 不用作基础
[ebp+ebp]使用SS因为其中一个ebp 用作基础

然后,最好指定您不希望NASM出现此行为。
在NASM作者意识到他们的错误之前,您可以通过编写以下内容来禁用此行为(将EBP用作索引):

[NoSplit ebp*2]

实际上,NASM的优化选择是不一致的,假设ssds在将[ebp*2]拆分为[ebp+ebp]以保存3个字节(disp32与disp8)时是可互换的(即平坦内存模型),而不是优化[ebp + esi]进入[esi + ebp]以避免disp8。

(并且NASM手册甚至提到了不同的默认段 ,与您从[0 + ebp*2][0+ebp+ebp*1]的错误信息中得出的结论相矛盾。)

EBP或ESP 作为基址寄存器意味着SS,否则默认为DS。 当在NASM寻址模式中使用两个寄存器时,第一个寄存器是基数,除非您编写[ebp*1 + esi] ,明确将比例因子应用于第一个。 索引寄存器从不暗示一个段,如果考虑设计意图,这是有意义的:相对于段的索引:由基址寄存器或绝对disp32给出的偏移量。

如上所述, [ebp*2]是一种索引寻址模式,隐含地需要4个字节的零作为32位位移。 您可以使用[nosplit ebp*2]让NASM以这种方式对其进行编码。

也许NASM和YASM忽略了这个角落的情况,因为平面内存模型在16位代码之外几乎是通用的。 (并且16位寻址模式不同,不支持比例因子。虽然您可以在16位代码中使用32位寻址模式,以利用比例因子和更广泛的寄存器选择,即使在纯实模式下也是如此比“虚幻”模式允许您将段限制设置得足够高,可以使用偏移> 2 ^ 16。

所有主流的32位和64位x86操作系统都使用平面内存模型,其中SS和DS是可互换的,当你没有做任何奇怪的事情时,这种优化在这些操作系统下是安全的。 在页面表支持之前,分段有时用于制作非可执行堆栈 ,但这仍然是一个扁平的内存模型。 (64位代码修复了CS / DS / ES / SS的基本/限制,因此除非SS完全不可用,否则这种优化总是安全的,如果可能的话,可能会写保护。)

但是,任何平坦内存模型的假设都应该是可选的 这是NASM和YASM中的一个错误。 他们应该尊重SS和DS之间的区别,或者应该充分利用平坦的内存模型来帮助那些不记得哪些寻址模式需要“隐藏”额外字节的程序员,比如优化[ebp+esi]置换成[esi+ebp] 最好应该有一个选项或指令告诉汇编程序它可以假定SS和DS是相同的。

LEA的操作数总是可以利用,因为LEA只处理地址的偏移部分,因此段是无关紧要的。 (这将是[ebp*2]寻址模式的最常见用例,没有位移:使用它作为内存地址可能会模拟字可寻址内存?这很奇怪,通常有一个真正的指针作为一个组件地址。)


了解x86 32/64位寻址模式

除了64位RIP相对寻址之外,32/64位寻址模式是disp0/8/32 + base_reg + idx_reg*1/2/4/8任何子集,其中3个术语/组件中的每一个都是可选的。 至少需要一个disp32或基址寄存器。 (另请参阅引用内存位置的内容。(x86寻址模式) )。

[disp32=0 + ebp*2] (disp32 = 0)具有默认段= DS。 您可以从[nosplit ebp*2]在NASM中获取此编码,并且无法拆分[ebp*4]等地址。

[ebp + ebp + disp8=0]具有默认段= SS,因为EBP用作基址寄存器。

意味着没有位移的ebp的编码实际上意味着没有基址的disp32,因此disp32实际上是基数(暗示段寄存器DS,因为基数不是EBP或ESP)。 这是有或没有SIB字节的情况,因此[ebp + ebp*1]仍然必须用disp8 = 0进行编码。 其他寄存器没有这个问题,所以通常拆分为EBP节省4个字节而不是3个字节。 (除了使用与RBP相同的ModR / M编码的r13之外,我想这部分解码硬件不需要来自REX前缀的额外位。)

ESP不能是索引寄存器,因此[esp*2]无论是否分割都无法编码​​。 因此,NASM优化的特殊情况影响EBP*2 (base = ESP是SIB字节的转义码,SIB字节中的index = ESP表示没有索引,允许您对[esp + 12]进行编码。)

但不幸的是NASM / YASM分割EBP*2即使有一个常量需要一个disp32 ,比如[symbol + ebp*2] ,它不会保存任何字节,实际上会损害LEA的性能(但不是负载/在Sandybridge家庭CPU上 3分量lea eax, [symbol + ebp + ebp*1]比2分量lea eax, [symbol + ebp*2]lea eax, [symbol + ebp*2] :更高的延迟和1-per-clock吞吐量而不是2.根据http:/ /agner.org/optimize/ ,这些在AMD Bulldozer / Ryzen上同样会很慢,因为即使只有2个组件,缩放索引也会产生“慢速LEA”。

IDK,如果任何旧的CPU使用非标度索引和3分量寻址模式,LEA或实际内存操作数做得更好。


NASM和YASM行为

 $ nasm -felf32 -g -Fdwarf foo.asm
 $ objdump -drwC -Mintel -S foo.o | sed 's/DWORD PTR//'
 # (edited to put the NASM source line's addressing mode onto the same line as the disassembler output, instead of separate lines)
00000000 <sym-0x2c>:
   0:   8b 04 2e                mov    eax, [esi+ebp*1]         ; [esi+ebp]
   3:   8b 44 35 00             mov    eax, [ebp+esi*1+0x0]     ; [ebp + esi]
   7:   8b 04 2e                mov    eax, [esi+ebp*1]         ; [ebp*1 + esi]
   a:   8b 44 2d 00             mov    eax, [ebp+ebp*1+0x0]     ; [ebp*2]
   e:   8b 04 6d 00 00 00 00    mov    eax, [ebp*2+0x0]         ; [nosplit ebp*2]
  15:   8b 45 00                mov    eax, [ebp+0x0]           ; [ebp*1]   ; "split" into base=ebp with no SIB byte
  18:   8b 04 2d 00 00 00 00    mov    eax, [ebp*1+0x0]         ; [nosplit ebp*1]
  1f:   8b 84 2d d2 04 00 00    mov    eax, [ebp+ebp*1+0x4d2]   ; [ebp*2 + 1234]   ; bad split for LEA, neutral on modern CPUs for load/store
  26:   8b 85 15 cd 5b 07       mov    eax, [ebp+0x75bcd15]     ; [ebp*1 + 123456789]
sym:       ; using a symbol reference instead of a numeric constant doesn't change anything
  2c:   8b 84 2d 2c 00 00 00    mov    eax, [ebp+ebp*1+0x2c]    2f: R_386_32    .text   ; [ebp*2 + sym]
  33:   8b 84 2d 2c 00 00 00    mov    eax, [ebp+ebp*1+0x2c]    36: R_386_32    .text   ; [sym + ebp*2]

YASM将所有这些案例编码为与NASM相同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM