8086程序集问题,这个代码做什么



我在组装课程中收到了这个问题:

这个过程有什么作用
它应该如何命名?

push ebp
mov ebp, esp    
push esi
mov esi, [ebp+4]
mov eax, [esi]
sub eax, [esi+4]
add esi, 8
mov [ebp+4], esi
pop esi
pop ebp
ret

看起来[ebp+4]是一个参数,而不是返回地址,所以应该用"jmp"而不是"call"来调用它。我真的不明白[esi+4]esi+8(返回地址)上应该找到什么嗯,我真的很困惑,希望你能帮我
提前谢谢。

正如您正确地注意到的,如果使用call调用此例程,则[ebp+4]是返回地址。这并不意味着这是个坏主意。

假设该例程是用call调用的。此时,在堆栈上推送的"返回地址"是紧跟在call操作码后面的字节的地址。让我们把这个地址称为x。然后,例程从地址x中提取两个32位字,一个在地址x处,一个位于地址1x+4处。它从第一个字中减去第二个字,将结果存储在eax中。最后,例程将值x+8存储回堆栈槽[ebp+4]中,净效果是当达到ret时,在地址x+8处恢复执行。在这个假设下,例程看起来像是一种减去位于代码中间的整数的方法,类似于这样:

call yourroutine
dd   56478634
dd   18943675
mov  ebx, eax  ; an example instruction

这里,call返回到mov指令,此时eax包含值37534959(从56478634中减去18943675)。

作为一个代码例程,它并不是很有用,因为它是一种复杂的方式,可以用硬编码的常数值加载eax(代码空间在执行过程中通常是只读的)。可以想象,这样的例程可以作为某些体系结构上对动态链接的运行时支持的一部分出现(动态链接是一个棘手的主题)。

现在,让我们假设使用jmp调用该例程。[ebp+4]现在指定在该点上堆栈顶部的任何内容。例程获取该值(让我们称之为y),获取地址yy+4处的两个字,将减法结果计算到eax中,然后将y+8存储回[ebp+4]插槽中。最后,ret将该槽解释为返回地址,即执行应该跳转到的某些代码的地址。没有call操作码参与该地址的生成并不重要;尽管如此,ret还是会跳到它上面。这一次,调用代码可能看起来像:

    push   foobar
    jmp    yourroutine
    ...  ; unreached code
foobar:
    dd 56478634
    dd 18943675
    mov  ebx, eax  ; an example instruction

这一次,这看起来像是一个带有eax固有负载的参数化跳跃。类似的代码可以存在于一些线程代码解释器的实现中。然而,作为一个家庭作业问题,我确信这不是预期的(线程代码解释器甚至比动态链接更粗糙)。

不,它肯定应该用call调用——它的末尾有一个ret

就它的作用而言,你应该坐下来,拿一张纸,上面有寄存器列表和通过你的头脑进行编码的步骤,边走边更新寄存器。然后应该很明显发生了什么:

eax:
esp:
ebp:
esi:

以及其他相关存储器(例如栈顶周围的区域)。

这是学习编程的理想方式(不管怎样,对于小程序来说),因为你可以学习详细分析事物,并实际理解它们。恐怕这与我为家庭作业提供的帮助差不多:-)

调用此函数时,返回地址(调用后指令地址的eip)被推送到堆栈上,在第一个函数前导码之后,[ebp+4]引用该返回地址。然后,函数的主体将此地址视为2个整数,即减法,结果放入eax,然后返回地址增加8,即这2个整数的大小增加add esi,8mov [ebp+4], esiret只是把我们放回了那个新的返回地址(希望这是一条有效的指令……)

一个奇怪的函数,在一些自我修改的代码中出现。

最新更新