引用一个存储器位置中的内容。 (86寻址模式) [英] Referencing the contents of a memory location. (x86 addressing modes)

查看:259
本文介绍了引用一个存储器位置中的内容。 (86寻址模式)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含我想与另一个字符比较字符的内存位置。 (这不是在顶部,所以我不能弹出它。我如何引用一个内存位置的内容,以便我可以比较吗?

I have a memory location that contains a character that I want to compare with another character. (It's not at the top so I can't pop it. How do I reference the contents of a memory location so I can compare it?

基本上我该怎么做语法。

Basically how do I do it syntactically.

推荐答案

另请参阅:AT&放表; T(GNU)语法与NASM语法不同的寻址模式的,包括间接跳转/调用。

For a more extended discussion of addressing modes (16/32/64bit), see Agner Fog's "Optimizing Assembly" guide, section 3.3. That guide has much more detail than this answer for relocation for symbols and or 32bit position-independent code, among other things.

See also: table of AT&T(GNU) syntax vs. NASM syntax for different addressing modes, including indirect jumps / calls.

另请参阅链接集合在这个答案的底部。

Also see the collection of links at the bottom of this answer.

建议表示欢迎,尤其。哪些部分是有用/有趣的,哪些部分不是。

86(32位和64位)有几个寻址模式可供选择。他们都是形式:

x86 (32 and 64bit) has several addressing modes to choose from. They're all of the form:

[base_reg + index_reg*scale + displacement]    ; or a subset of this
[RIP + displacement]   ; or RIP-relative: 64bit only.  No index reg is allowed

(其中,比例为1,2,4,或8,位移是带符号的32位常数)。 所有其他形式(除了RIP相对)是漏下一个或多个组件的子集,这个。这意味着你不需要归零 index_reg 访问 [RSI] 为例。在ASM源$ C ​​$ C,它无关紧要什么顺序写的东西: [5 + RAX + RSP + 15 * 4 + MY_ASSEMBLER_MACRO * 2] 工作正常。 (所有在常量数学发生在组装时间,从而在单个恒定位移。)

(where scale is 1, 2, 4, or 8, and displacement is a signed 32bit constant). All the other forms (except RIP-relative) are subsets of this that leave out one or more component. This means you don't need a zeroed index_reg to access [rsi] for example. In asm source code, it doesn't matter what order you write things: [5 + rax + rsp + 15*4 + MY_ASSEMBLER_MACRO*2] works fine. (All the math on constants happens at assemble time, resulting in a single constant displacement.)

所有寄存器必须是相同的大小,虽然。如果你想使用作为数组的索引,你需要零序或符号扩展它的宽度指针。 (有 RAX 的高位字节与寄存器乱搞之前就已经归零有时是可能的,而且是实现这一目标的好方法。)

All registers must be the same size, though. If you want to use al as an array index, you need to zero- or sign-extend it to pointer width. (Having the upper bits of rax already zeroed before messing around with byte registers is sometimes possible, and is a good way to accomplish this.)

一般情况下每个可能的子集可编码的,但是使用了那些 E / RSP *比例(在正常code显然是无用始终保持一个指针在堆栈内存尤其)。

Every possible subset of the general case is encodable, except ones using e/rsp*scale (obviously useless in "normal" code that always keeps a pointer to stack memory in esp).

通常,编码的code尺寸是:

Normally, the code-size of the encodings is:


  • 1B一个寄存器模式(MOD / RM(模式/注册,或内存))

  • 2B两个寄存器模式(MOD / RM + SIB(规模指数基)字节)

  • 位移可以是0,1(符号扩展),或4字节

code尺寸的例外:

code-size exceptions:


  • [注册*规模] 本身只能带32位位移codeD。智能装配解决,通过编码 LEA EAX,[RDX * 2] LEA EAX,[RDX + RDX] ,但是这招只适用于2缩放。

  • [reg*scale] by itself can only be encoded with a 32bit displacement. Smart assemblers work around that by encoding lea eax, [rdx*2] as lea eax, [rdx + rdx], but that trick only works for scaling by 2.

这是不可能的EN code E / RBP R13 因为没有基址寄存器位移字节,所以 [EBP] 为en codeD为 [EBP + 0字节] 。与 EBP 无位移编码作为基址寄存器,而不是意味着有的没有的基址寄存器(如 [显示+章*规模] )。

It's impossible to encode e/rbp or r13 as the base register without a displacement byte, so [ebp] is encoded as [ebp + byte 0]. The no-displacement encodings with ebp as a base register instead mean there's no base register (e.g. for [disp + reg*scale]).

[E / RSP] 要求,即使没有索引寄存器一个SIB字节。 (不论是否有一个位移)。将指定的MOD / RM编码 [RSP] ,而不是意味着有一个SIB字节。

[e/rsp] requires a SIB byte even if there's no index register. (whether or not there's a displacement). The mod/rm encoding that would specify [rsp] instead means that there's a SIB byte.

请参阅表2-5在英特尔的参考手册,和周围部分,对特殊情况的细节。 (它们是相同的32位和64位模式。添加RIP相对编码没有与任何其他编码,即使没有REX preFIX冲突。)

See Table 2-5 in Intel's ref manual, and the surrounding section, for the details on the special cases. (They're the same in 32 and 64bit mode. Adding RIP-relative encoding didn't conflict with any other encoding, even without a REX prefix.)

有关性能,它通常不值得花费额外的指令只是为了获得更小的x86机器code。在英特尔CPU一个缓存UOP公司,它比L1 I $较小,更precious资源。最小化融合域微指令通常是更重要的。

For performance, it's typically not worth it to spend an extra instruction just to get smaller x86 machine code. On Intel CPUs with a uop cache, it's smaller than L1 I$, and a more precious resource. Minimizing fused-domain uops is typically more important.

16位地址长度不能使用SIB字节,所以所有的一,两个寄存器寻址模式都设有coded到单一MOD / RM字节。 REG1 可以是BX或BP和 REG2 可SI或DI(或者你可以使用任何的4个寄存器的由自理)。缩放不可用。 16位code是过时了很多原因,包括这一项,并没有值得学习的,如果你不就得了。

16bit address size can't use a SIB byte, so all the one and two register addressing modes are encoded into the single mod/rm byte. reg1 can be BX or BP, and reg2 can be SI or DI (or you can use any of those 4 registers by themself). Scaling is not available. 16bit code is obsolete for a lot of reasons, including this one, and not worth learning if you don't have to.

需要注意的是16bit的限制,32位code申请使用地址大小preFIX的时候,所以16位LEA-数学严格限制。但是,您可以解决的: LEA EAX,[EDX + ECX * 2] AX = DX + CX * 2 ,<一个href=\"http://stackoverflow.com/questions/34377711/which-2s-complement-integer-operations-can-be-used-without-zeroing-high-bits-in\">because垃圾源寄存器的高位没有影响。

Note that the 16bit restrictions apply in 32bit code when the address-size prefix is used, so 16bit LEA-math is highly restrictive. However, you can work around that: lea eax, [edx + ecx*2] sets ax = dx + cx*2, because garbage in the upper bits of the source registers has no effect.

本表不完全匹配的寻址模式的硬件编码,因为我使用的是与使用小排量不变的标签(例如用于全局或静态数据)区分。所以我对涵盖硬件符号寻址模式+连接器的支持。

This table doesn't exactly match the hardware encodings of possible addressing modes, since I'm distinguishing between using a label (for e.g. global or static data) vs. using a small constant displacement. So I'm covering hardware addressing modes + linker support for symbols.

如果你有一个指针字符数组[] ESI


  • MOV人,[ESI] 加载指向的字节。

MOV人,[ESI + ECX] 加载数组[ECX]

MOV人,[ESI + 10] 加载数组[10]

MOV人,[ESI + ECX * 8 + 200] 加载数组[ECX * 8 + 200]

MOV人,[global_array + 10] global_array负载[10] 。在64位模式,这可能是一个RIP相对地址。使用默认REL 建议,产生而不必总是使用 [REL global_array + 10]

mov al, [global_array + 10] loads from global_array[10]. In 64bit mode, this can be a RIP-relative address. Using DEFAULT REL is recommended, to generate RIP-relative addresses by default instead of having to always use [rel global_array + 10].

MOV人,[global_array + ECX + EDX * 2 + 10] global_array负载[ECX + EDX * 2 + 10 ] 明明可以使用索引寄存器的静态/全局数组。即使使用两个独立的寄存器的2D阵列是可能的。 ($ P $对缩放一项所述的带额外的指令,对于除2,4等的比例因子,或8)。请注意, global_array + 10 数学在链接时进行。目标文件(汇编输出,连接器输入)通知+10的接头添加到最终的绝对地址,把正确的4字节位移到可执行(连接器输出)。这就是为什么不能使用的链接时间常数任意EX pressions未组装时间常数(如符号地址)。

mov al, [global_array + ecx + edx*2 + 10] loads from global_array[ecx + edx*2 + 10] Obviously you can index a static/global array with registers. Even a 2D array using two separate registers is possible. (pre-scaling one with an extra instruction, for scale factors other than 2, 4, or 8). Note that the global_array + 10 math is done at link time. The object file (assembler output, linker input) informs the linker of the +10 to add to the final absolute address, to put the right 4-byte displacement into the executable (linker output). This is why you can't use arbitrary expressions on link-time constants that aren't assemble-time constants (e.g. symbol addresses).

MOV人,0ABH 未负载在所有的,而是被储存在里面的指令立即常数。 (请注意,你需要preFIX一个 0 所以汇编知道这是一个常数,而不是一个象征。有些汇编也将接受是0xAB )。您的可以的使用符号作为立即数,得到一个地址到寄存器。

mov al, 0ABh Not a load at all, but instead an immediate-constant that was stored inside the instruction. (Note that you need to prefix a 0 so the assembler knows it's a constant, not a symbol. Some assemblers will also accept 0xAB). You can use a symbol as the immediate constant, to get an address into a register.


  • NASM: MOV ESI,global_array 组装成 MOV ESI,imm32 即把地址复制到ESI <。 / LI>
  • MASM: MOV ESI,OFFSET global_array 是需要做同样的事情

  • MASM: MOV ESI,global_array 组合成一个负载: MOV ESI,双字[global_array]

  • NASM: mov esi, global_array assembles into a mov esi, imm32 that puts the address into esi.
  • MASM: mov esi, OFFSET global_array is needed to do the same thing.
  • MASM: mov esi, global_array assembles into a load: mov esi, dword [global_array].

在64位模式,解决全球性的符号通常与RIP-相对寻址,你的汇编器将默认使用默认REL 指令做的做了,或者用 MOV人,[REL global_array + 10] 。没有索引寄存器可以与RIP相对地址,唯一不变的位移来使用。您的可以的还是做绝对地址(除OS X),并有 MOV 甚至一种特殊形式,可以从64位绝对地址加载( 而不是通常的32位符号扩展的),AT&放大器; T语法调用运code movabs (也可用于 MOV R64,imm64 ),而英特尔/ NASM语法仍然称其为形式 MOV

In 64bit mode, addressing global symbols is usually done with RIP-relative addressing, which your assembler will do by default with the DEFAULT REL directive, or with mov al, [rel global_array + 10]. No index register can be used with RIP-relative addresses, only constant displacements. You can still do absolute addressing (except on OS X), and there's even a special form of mov that can load from a 64bit absolute address (rather than the usual 32bit sign-extended.) AT&T syntax calls that opcode movabs (also used for mov r64, imm64), while Intel/NASM syntax still calls it a form of mov.

使用 LEA ESI,[REL global_array] 来得到RIP相对地址到寄存器,因为 MOV章,IMM 将硬codeA非相对地址到指令字节。

Use lea esi, [rel global_array] to get rip-relative addresses into registers, since mov reg, imm would hard-code a non-relative address into the instruction bytes.

需要注意的是OS X要求所有64位code到位置无关,而不仅仅是共享库。 <一href=\"https://stackoverflow.com/questions/26927278/relative-addressing-errors-mac-10-10/26929101#26929101\">The绝对地址的Linux的ELF的方式做macho64目标文件格式不支持重定位。确保不要在一个有效的地址使用标签名称作为一个编译时间常数的任何地方,除了像 [global_array +常数] ,因为这可以组装到RIP -relative寻址模式。例如 [global_array + ECX] 是不允许的,因为RIP不能与任何其他寄存器使用,因此它必须具有的绝对地址进行组装 global_array 硬件codeD为32位的位移(<一个href=\"http://stackoverflow.com/questions/6093547/what-do-r-x86-64-32s-and-r-x86-64-64-relocation-mean/6093910#6093910\">which将符号扩展为64B )。

Note that OS X requires all 64bit code to be position-independent, not just shared libraries. The macho64 object file format doesn't support relocations for absolute addresses the way Linux ELF does. Make sure not to use a label name as a compile-time constant anywhere, except in an effective-address like [global_array + constant], because that can be assembled to a RIP-relative addressing mode. e.g. [global_array + ecx] is not allowed, because RIP can't be used with any other registers, so it would have to be assembled with the absolute address of global_array hard-coded as the 32bit displacement (which will be sign-extended to 64b).

任何和所有的寻址方式可与<$ C $使用 C> LEA 做整数运算与不影响标志的奖金,无论它是否是一个有效的地址。 [ESI * 4 + 10] 通常只与LEA有用的(除非位移是一个符号,而不是一个小的常数)。在机器code,有一个规模注册独自一人,没有一个32B位移,而且装配简单地用一个零位移EN code [ESI * 4]

Any and all of these addressing modes can be used with LEA to do integer math with a bonus of not affecting flags, regardless of whether it's a valid address. [esi*4 + 10] is usually only useful with LEA (unless the displacement is a symbol, instead of a small constant). In machine code, there is no encoding for scaled-register alone, without a 32b displacement, but assemblers simply use a zero displacement to encode [esi*4].

您可以指定段覆盖像 MOV人,FS:[ESI] 。一个段重写的只是在通常的编码前增加了preFIX字节。其他一切保持不变,与相同的语法。

You can specify segment-overrides like mov al, fs:[esi]. A segment-override just adds a prefix-byte in front of the usual encoding. Everything else stays the same, with the same syntax.

如果操作数大小是不明确的(如在即时和内存操作数的指令),使用字节 / / DWORD / 四字 / xmmword / ymmword 来指定:

If the operand-size is ambiguous (e.g. in an instruction with an immediate and a memory operand), use byte / word / dword / qword / xmmword / ymmword to specify:

mov       dword [rsi + 10], 0xAB  ; NASM
mov   dword ptr [rsi + 10], 0xAB  ; MASM
movl              $0xAB, 10(%rsi) ; GNU(AT&T): operand size from insn suffix

请参阅的文档YASM为NASM语法的有效地址和/或维基百科的条目86对寻址模式部分。维基页面说什么是允许的16位模式。这里是另一个小抄的32位寻址模式

See the yasm docs for NASM-syntax effective addresses, and/or the wikipedia x86 entry's section on addressing modes. The wiki page says what's allowed in 16bit mode. Here's another "cheat sheet" for 32bit addressing modes.

还有href=\"http://www.ic.unicamp.br/~celio/mc404s2-03/addr_modes/intel_addr.html\" rel=\"nofollow\">更详细的指导寻址模式一个。 16位仍具有所有相同的寻址方式为32bit的,所以如果你发现寻址模式混乱,反正读

There's also a more detailed guide to addressing modes, for 16bit. 16bit still has all the same addressing modes as 32bit, so if you're finding addressing modes confusing, read it anyway

另请参阅 86 维基页面

这篇关于引用一个存储器位置中的内容。 (86寻址模式)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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