0

我必须通读一些随机生成的程序集并输入一些正确的输入才能到达最后,而无需调用 explode_bomb 函数。问题是有两条线似乎直接相互矛盾,我担心我的分配实际上可能由于随机生成而不可能。

这是完整的代码:

 08048d1b <phase_2>:
 8048d1b:       55                      push   %ebp
 8048d1c:       89 e5                   mov    %esp,%ebp
 8048d1e:       56                      push   %esi
 8048d1f:       53                      push   %ebx
 8048d20:       83 ec 30                sub    $0x30,%esp
 8048d23:       8d 45 e0                lea    0xffffffe0(%ebp),%eax
 8048d26:       89 44 24 04             mov    %eax,0x4(%esp)
 8048d2a:       8b 45 08                mov    0x8(%ebp),%eax
 8048d2d:       89 04 24                mov    %eax,(%esp)
 8048d30:       e8 42 04 00 00          call   8049177 <read_six_numbers>
 8048d35:       83 7d e0 00             cmpl   $0x0,0xffffffe0(%ebp)
 8048d39:       79 05                   jns    8048d40 <phase_2+0x25>
 8048d3b:       e8 f5 03 00 00          call   8049135 <explode_bomb>
 8048d40:       bb 01 00 00 00          mov    $0x1,%ebx
 8048d45:       8d 75 e0                lea    0xffffffe0(%ebp),%esi
 8048d48:       89 d8                   mov    %ebx,%eax
 8048d4a:       03 44 9e fc             add    0xfffffffc(%esi,%ebx,4),%eax
 8048d4e:       39 04 9e                cmp    %eax,(%esi,%ebx,4)
 8048d51:       74 05                   je     8048d58 <phase_2+0x3d>
 8048d53:       e8 dd 03 00 00          call   8049135 <explode_bomb>
 8048d58:       83 c3 01                add    $0x1,%ebx
 8048d5b:       83 fb 06                cmp    $0x6,%ebx
 8048d5e:       75 e8                   jne    8048d48 <phase_2+0x2d>
 8048d60:       83 c4 30                add    $0x30,%esp
 8048d63:       5b                      pop    %ebx
 8048d64:       5e                      pop    %esi
 8048d65:       5d                      pop    %ebp
 8048d66:       c3                      ret  

有问题的线路是 8048d4a 和 8048d4e。因为这是 2 的恭维,第一个数字是 -4,第二个数字是我的第一个输入(这甚至会更改为我的第二个和第三个吗?),第三个将是我们循环的任何迭代开,第四个也一样。

现在以直接顺序比较这些值基本上意味着我正在将一个数字与其自身进行比较 - 4,对吗?我怎么可能成功地通过那个测试?

谢谢您的帮助。

4

2 回答 2

3

我的 AT&T 语法不是最好的,但它似乎在做:

ADD EAX,[ESI + EBX * 4 - 4]
CMP EAX,[ESI + EBX * 4]

又名,它将前一个计数器和某个计数器的总和与当前条目进行比较。请参阅this以供参考,特别是:

Example:
Intel Syntax
instr   foo,segreg:[base+index*scale+disp]
mov     eax,[ebx+20h]
add     eax,[ebx+ecx*2h
lea     eax,[ebx+ecx]
sub     eax,[ebx+ecx*4h-20h]
AT&T Syntax
instr   %segreg:disp(base,index,scale),foo
movl    0x20(%ebx),%eax
addl    (%ebx,%ecx,0x2),%eax
leal    (%ebx,%ecx),%eax
subl    -0x20(%ebx,%ecx,0x4),%eax

至于为什么这样做,它似乎是一种优化以避免寄存器溢出或递减数组索引然后递增它的替代方法。

于 2012-11-04T15:17:51.790 回答
0
mov    $0x1,%ebx                        ; i = 1
lea    0xffffffe0(%ebp),%esi            ; ESI = address of array of 6 numbers
mov    %ebx,%eax                        
add    0xfffffffc(%esi,%ebx,4),%eax     ; add to element
cmp    %eax,(%esi,%ebx,4)

add    0xfffffffc(%esi,%ebx,4),%eax

上面的指令是访问数组的元素。这在 x86 中称为SIB寻址,用于 Scale、Index、Base。还有一个 Offset 组件。该数组基于由基址寄存器(EBX此处)加上偏移量(此处为-4)确定的地址。元素编号位于索引寄存器(ESI此处)。每个元素的大小由 Scale(此处为 4)确定。

lea    0xffffffe0(%ebp),%esi            ; ESI = address of array of 6 numbers

如果你再往上看,你会看到数组的地址是如何移动到%ESI. 数组是一个局部变量,位于帧指针下方 32 个字节(当使用帧指针时,包括数组在内的局部变量被寻址为相对于帧指针的偏移量)

add    0xfffffffc(%esi,%ebx,4),%eax

因此,该指令访问一个“虚拟”数组,该数组在实际数组之前 4 个字节开始。这是因为循环索引从 1 开始,但访问的元素是 0,所以使用“虚拟数组”一切都到位。

mov    $0x1,%ebx                        ; i = 1
lea    0xffffffe0(%ebp),%esi            ; ESI = address of array of 6 numbers
mov    %ebx,%eax                        
add    0xfffffffc(%esi,%ebx,4),%eax     ; add to element i-1
cmp    %eax,(%esi,%ebx,4)               ; compare against element i
于 2012-11-04T15:29:18.717 回答