1

我需要帮助解决家庭作业问题。我应该弄清楚edx这段代码运行后的值是多少。

0x40106e    <main+30>:      mov    $0x1,%edx
0x401073    <main+35>:      mov    $0x8,%ecx
0x401078    <main+40>:      test   %ecx,%ecx
0x40107a    <main+42>:      jg     0x40107e <main+46>
0x40107c    <main+44>:      jmp    0x40108a <main+58>
0x40107e    <main+46>:      lea    (%ecx,%ecx,1),%eax
0x401081    <main+49>:      lea    (%eax,%edx,1),%eax
0x401084    <main+52>:      lea    0xffffffff(%eax),%edx
0x401087    <main+55>:      dec    %ecx
0x401088    <main+56>:      jmp    0x401078 <main+40>
0x40108a    <main+58>:      // endpoint

由于这是家庭作业,我真的不想知道答案,而是想知道如何弄清楚。我在弄清楚循环时遇到了麻烦,但我想我明白了。我认为test %ecx,%ecx循环直到%ecx减少到 0。对吗?真正吸引我的是所有的lea东西。我无法弄清楚那在做什么。

4

2 回答 2

1

你是对的testand jg; 它确实会循环直到ecx为零。

lea

我对 AT&T 语法不是很熟悉,所以我将使用 Intel 语法(我觉得它更直观)。我希望它仍然可以理解。(主要区别之一是英特尔语法将目标放在首位。)

一些指令允许您从地址加载值:

mov eax, [esi]  ; load a DWORD from the address in ESI

您可以更改这些以添加偏移量:

mov eax, [esi + 4]  ; load a DWORD from four bytes after the address in ESI

允许寄存器、比例和偏移的某些组合:

mov eax, [esi + ecx * 4 + 16]  ; load a DWORD from (ECX * 4 + 16) bytes after the
                               ; address in ESI

这个比较方便;您无需手动计算有效地址。

lea代表“加载有效地址”。本质上,它可以让你做这样的事情:

lea eax, [esi + ecx * 4 + 16]

它不是将值加载到该位置的内存中,而是计算地址;换句话说:

EAX = ESI + ECX * 4 + 16

上面的lea指令汇编为 4 个字节。相比之下,对我来说最明显的方式:

mov eax, ecx
shl eax, 2
add eax, esi
add eax, 16

…汇编为 14 个字节。

于 2013-08-11T19:57:07.370 回答
1

正如 icktoofay 解释的那样,该lea指令会将edx寄存器设置为eax - 1. 让我们一步一步地浏览整个代码。

前两行将立即值移动到寄存器,因此edx等于1ecx设置为8

test指令在此处位于循环的开始处,并与在它说明循环执行条件之后的指令一起立即出现。该test指令影响了很多标志,但由于条件跳转是jg,我们将只关注ZF,OFSFjg仅当ZF=0while 时分支SF=OF。现在

  • ZF将为零,直到ECX!=0
  • OF将始终为零,同样适用于SF,因为8在二进制补码中大于零(更准确地说,8 的最高有效位是 0)。

第一lea条指令设置eax2*ecx. 第二个和最后一个leas 增加eaxedx减少它。最后,ecx递减并且指令指针设置为循环的开始。

象征性地写出来:

sum(8, n = 1, n*2 -1) + 1
于 2013-08-14T14:43:35.530 回答