我需要将以下序列作为一条单独的ASM指令编写,但我不知道它是什么指令:
push ebp
mov ebp,esp
mov ebp,[ebp]
mov ebx,[ebp]
mov [esp],ebx
答案 0 :(得分:4)
不可能使用1条甚至2条指令来完全复制所有输入值的所有行为。
前3条指令推入EBP,然后将刚刚保存的EBP值重新加载到EBP中。因此,前3个的净效果是lea esp, [esp-4]
(不是SUB,因为那样会影响FLAGS) 1 。
push ebp ; save old EBP, ESP-=4
mov ebp,esp
mov ebp,[ebp] ; reload old EBP
;; net effects so far: ESP-=4.
;; memory at [ESP] replaced with old-EBP.
mov ebx,[ebp] ; EBX = [EBP]. This could overlap with dword [ESP]
mov [esp],ebx ; replace pushed original_EBP value with [original_EBP]
我怀疑他们回答他们正在寻找的push [ebp]
,但是如果是这样,那么这个问题就是垃圾。有2个关键的副作用无法重现:< / p>
[EBP]
值[EBP]
(部分)与[ESP-4]
重叠,则不一样要重现set-EBX行为,至少需要2条说明。 x86有一些复杂的指令,但是没有一个指令将存储器和推送到整数寄存器。 Jester的2条指令序列看起来最接近:mov ebx, [ebp]
/ push ebx
。
您还可以考虑使用push dword [ebp]
/ mov ebx, [esp]
,但这显然效率较低,并且与给定序列不同,它存储/重载[ebp]
值。
但是,如果[ebp]
与推送目标重叠,则这两个选项均无法再现确切的行为。例如在这些说明之前考虑使用lea ebp, [esp-2]
。 给定序列在加载[ebp]
之前会存储EBP,并且没有任何信息告诉我们没有重叠。如果您使用EBP作为帧指针,通常不会指向ESP下方,但我们没有被告知。
脚注1:当然,假设没有其他线程在修改我们存储/重新加载EBP的内存,否则存储/重新加载可能不会总是重新加载相同的值!我们最终确实会存储到[esp]
,因此,如果ESP指向无法读取和写入的内存,那么优化掉某些内存访问不会改变错误的行为。
问题什么都没有说,我无法对ESP指向的位置做出任何假设,或者与该内存位置异步发生的事情。
据我们所知,ESP指向MMIO区域,并且每个存储/装载都有明显的副作用,例如将位放在并行端口的引脚上或读取它们!
在正常情况下,ESP指向没有其他线程引用的回写区域中的可读写存储器,因此优化存储/重载是有效的。但是就像我说的,没有什么可以说我们可以假设的。