请考虑以下源代码,其中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);
}
Run Code Online (Sandbox Code Playgroud)
在编译该程序时,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
Run Code Online (Sandbox Code Playgroud)
我知道最后一条指令'movl $ 888,%eax'表示有888个字节相当于222个字节(i*j*k).正如你所看到的,我知道每个指令正在做什么,但是我很难对它进行逆向工程以确定传递给i,j和k的常量.
我不期待答案,但任何暗示我指向正确方向的提示都将非常感激
赠品是: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
Run Code Online (Sandbox Code Playgroud)
显然,(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)