无法确定此汇编代码中的常量

时间:2014-02-11 08:06:16

标签: c gcc assembly

考虑以下源代码,其中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的常量。

我不期待答案,但任何提示我指向正确方向的提示都将非常感激

2 个答案:

答案 0 :(得分:7)

赠品是: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 < 2)

同样,(j == 36)至少会产生的索引 (36 * 37 = 1332),因此它必须对应于素数:S = 3,其中:(j < 3) - 离开:T = 37,其中:(k < 37)

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

通常,索引为:((((i * S) + j) * T) + k),其中:(i < R, j < S, k < T)

答案 1 :(得分:0)

这就是我得到它的方式,如果我错了,请纠正我,因为我是新手。

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(如果你用剩余的k元素填充你有111,正好是i索引)