繁体   English   中英

LEA 指令可以模仿每条 MOV 指令吗?

[英]Can the LEA instruction mimic every MOV instruction?

最近遇到了M/o/Vfuscator

一个完整的单指令 C 编译器,它将程序编译成“mov”指令,并且只编译成“mov”指令。 算术、比较、跳转、function 调用,以及程序需要的所有其他内容,都通过 mov 操作执行; 没有自修改代码,没有传输触发的计算,也没有其他形式的非移动作弊。

问题

我很好奇是否每个 MOV 指令都可以用等效的 LEA 替换?

例如

 mov     rax, 10
 mov     rbx, rax
 ...

可以替换为

 lea     rax, [10]
 lea     rbx, [rax]
 ...

更新

糟糕,完全忘记了 LEA 不能进行指针取消引用。 例如

.data
     ten dq 10

.code

main proc

    mov     rax, offset ten
    mov     rbx, [rax]  ; <--- dereference, move 10 into rbx
     
    lea     rax, [ten]
                        ; <--- no dereference equivalent using lea
    ret
main endp

end

不,LEA 不能从 memory 加载或存储,不像mov eax, [rdi]mov [rdi+rcx*8], rax
movfuscator依赖于使用mov进行查表来做逻辑,所以这是一个很大的问题。 lea只能做加法(寄存器和有符号常量)和左移,所以它不那么强大。 以及不允许访问除寄存器以外的任何内容。


LEA 无法模仿每个立即源mov ,因为mov r64, imm64是唯一可以使用 64 位立即数的 x86-64 指令(例如mov rcx, 0xdeadbeefdeadbeef )。 lea r64, [disp32]只能使用符号扩展的 32 位绝对位移。 (相反,相对于 RIP 的 LEA 可以做 MOV 做不到的事情,比call $+5 / pop rdi / add rdi, imm32更有效)


LEA 无法读取或写入 8 位寄存器,包括无法模拟mov cl, ah或类似内容。

LEA 可以将寄存器复制到 16、32 和 64 位寄存器的寄存器,但效率较低( 寄存器重命名时的 mov-elimination特定于mov )。 一些指令还需要更长的机器代码,例如lea eax, [rbp]lea rax, [rsp]由于寻址模式特殊情况需要额外的机器代码字节,而mov eax, ebpmov rax, rsp是 2 和 3字节,分别。 看到rbp 不允许作为 SIB 基础? . 这也会影响[r12][r13] ,它们使用相同的 ModRM 值但在 REX 中有一点区别。

  401000:       8d 03                   lea    eax,[rbx]       # normal length, no REX
  401002:       89 d8                   mov    eax,ebx         # equivalent MOV
  401004:       41 8d 03                lea    eax,[r11]       # normal length, with a REX
  401007:       44 89 d8                mov    eax,r11d

  40100a:       8d 04 24                lea    eax,[rsp]    # [rsp] can only be encoded with a SIB byte
  40100d:       89 e0                   mov    eax,esp      # but mov reg,reg uses register-direct
  40100f:       41 8d 04 24             lea    eax,[r12]
  401013:       44 89 e0                mov    eax,r12d

  401016:       8d 45 00                lea    eax,[rbp+0x0]  # [rbp] can only be encoded with disp8=0 (or disp32 but that's longer)
  401019:       89 e8                   mov    eax,ebp
  40101b:       41 8d 45 00             lea    eax,[r13+0x0]
  40101f:       44 89 e8                mov    eax,r13d

  401022:       88 e1                   mov    cl,ah    # LEA can't do this at all.

当然,您使用 LEA 的原因是在寻址模式下进行数学运算,而不是复制寄存器或将其设置为立即数。 例如复制和增加像mov + add和/或移位和添加寄存器。 在不是地址/指针的值上使用 LEA?

你刚刚写的是相同的,但lea最常用于在方括号[]内进行一些地址计算,它可以将 2 个数字相乘,将第三个数字加到这些数字等。在某些地方,我遇到了lea指令做一些数学(这是为了那个)。 例如,当你有struct地址并且想要检索它的成员时,比如offset + 8 bytes away from offset 你做lea rax, [rbx+8]rbx是结构的地址。 mov可用于加载地址(就像lea一样),但也可以用于加载值。 mov rax, [rbx]等同于取消引用rbx中指向的指针。 通常你会看到mov rax, [rbx+8*4]这就是你如何加载int数组的值(假设它需要 4 个字节来存储你的系统上的 int),相当于 C 中的array[8] 因此,要结束leamov可以在寄存器中加载地址时互换使用,但lea不能执行指针取消引用,你需要mov为此,或者当在 memory 地址存储值时lea无济于事,你需要mov那些操作也。 请注意在lea的方括号[]中进行数学计算,问题是使用lea在数学方面具有更大的灵活性。 以下是在访问 memory 时如何使用mov进行数学运算以不违反规则。 链接

暂无
暂无

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

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