【问题标题】:Having trouble determining constants in this assembly code无法确定此汇编代码中的常量
【发布时间】:2014-02-11 08:06:16
【问题描述】:

考虑以下源代码,其中 R、S 和 T 是用#define 声明的常量:

int A[R][S][T]; 

int store_ele(int i, int j, int k, int *dest)
{ 

*dest = A[i][j][k]; 
 return sizeof(A); 

} 

在编译这个程序时,GCC 生成如下汇编代码:

i at %ebp+8, j at %ebp+12, k at %ebp+16, dest at %ebp+20 

1. movl 12(%ebp), %edx    //move j into register %edx 
2. leal (%edx, %edx, 8), %eax //move address %edx+%edx*9 into %eax
3. leal (%edx, %eax, 4), %eax //move address %edx + %eax*4 into %eax
4. imull $111, 8(%ebp), %edx //111*i goes into %edx
5. addl %edx, %eax 
6. addl 16(%ebp), %eax //add k to %eax
7. movl A(, %eax, 4), %edx //%eax*4 offset by address of A moved into %edx 
8. movl 20(%ebp), %eax 
9. movl %edx, (%eax) 
10. movl $888, %eax 

我知道最后一条指令 'movl $888, %eax' 表示有 888 个字节,相当于 222 个整数 (i * j * k)。如您所见,我知道每条指令在做什么,但我很难对其进行逆向工程以确定传递给 i、j 和 k 的常数。

我不期待答案,但任何能指出我正确方向的提示将不胜感激

【问题讨论】:

  • 你用的是哪个版本?
  • 在查看了更多代码之后,我能够确定 %edx 经历了一堆算术,然后在指令 9 %edx 被移动作为对 %eax 的取消引用(它被设置为A当时的地址)。另外,感谢编辑我的帖子以适应适当格式的人,我是这个网站的菜鸟。
  • 不,我是说 gcc 的版本
  • 它在虚拟机上,所以我现在登录并检查...gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-54)

标签: c gcc assembly


【解决方案1】:

赠品是:i * 111 = i * 3 * 37。之前 2 个 LEA 指令结合起来设置eax = 37 * j。将k 添加到总和:eax = 3 * 37 * i + 37 * j + k。由于int 是 4 个字节,数组大小是 888 个字节,所以数组有 222 个元素。数组维度是素数的顺序:{2,3,37}

展开:

edx <- j
eax <- edx + 8 * edx = 9.j
eax <- edx + 4 * eax = j + 4 * 9j = 37.j

edx <- i * 111 = 3 * 37.i
eax <- eax + edx = 3 * 37.i + 37.j
eax <- eax + k = 3 * 37.i + 37.j + k

很明显,(i == 2) 将我们置于元素 A[222],它超出了范围。所以假设(i,j,k)对应(R,S,T),我们有:R = 2,其中:(i &lt; 2)

同样,(j == 36) 产生一个 至少 (36 * 37 = 1332) 的索引,因此它必须对应于素数:S = 3,其中:(j &lt; 3) - 留下:T = 37,其中:(k &lt; 37)

因此我们有数组:A[2][3][37],其中:(i &lt; 2, j &lt; 3, k &lt; 37)

一般索引为:((((i * S) + j) * T) + k),其中:(i &lt; R, j &lt; S, k &lt; T)

【讨论】:

  • 布雷特,非常感谢您的帮助。我希望通过更多的练习,我可以更好地概念化这些问题。有时很难想象 asm 指令列表在做什么
  • 你能解释一下为什么 i * 111 = i * 3 * 37 吗?
  • @David 因为 3*37 = 111
  • 我知道了,但他从哪里知道 i*111 一开始是 3*37..?
  • @DavidKernin 第 4 行和第 5 行,它偏移了 %edx 中的指针,这与 111 只有两个因子(3 和 37)的事实相结合:wolframalpha.com/input/?i=factorize+111
【解决方案2】:

这就是我的理解,如果我错了,请纠正我,因为我是新手。

1. movl 12(%ebp), %edx    // move j into edx
2. leal (%edx, %edx, 8), %eax // eax = j + j*8 = 9j
3. leal (%edx, %eax, 4), %eax // eax = j + 4*9j = 37j
4. imull $111, 8(%ebp), %edx // edx = 111*i
5. addl %edx, %eax // eax = 111*i + 37j
6. addl 16(%ebp), %eax // eax = 111*i +37j + k
7. movl A(, %eax, 4), %edx // edx = A(eax * 4)
8. movl 20(%ebp), %eax 
9. movl %edx, (%eax) 
10. movl $888, %eax 

在字节寻址中你会写类似

I want the [111][37][3]-th element

但由于您有一个 int 数组,因此上面的索引必须不同(我假设为 int = 4 字节)

111 只能分解为 3*37,因为内存布局表明 k 是最内层数组的索引,j 是中间数组的索引,i 是最外层数组分组的索引

(2x2x2 case)
( ( ( int, int ), ( int, int ) ), ( ( int, int ), ( int, int ) ) )

所以在 i=1,j=0,k=0 的情况下,我们将采用第 111 个元素。

这意味着数组是A[2][3][37],因为 A[1][0][0] 将产生 111*1 + 37*0 + 0 = 111,正好等于 37*3(所有 j 和 k 维在它们的最大容量)和 A[0][2][0] 将产生 37*2 (如果你用你有 111 的 k 个元素填充剩余部分,正好是 i 索引)

【讨论】:

  • 我把初始循环索引乘法弄混了,我已经更正了。您似乎犯了类似的错误 - 如果您访问元素:A[0][36][0]37.j 术语产生:1332
  • 你说得对,我把索引的顺序弄错了,修复了。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-18
  • 2015-03-02
  • 1970-01-01
  • 2015-12-15
  • 2011-09-13
相关资源
最近更新 更多