2014-02-11 48 views
5

考慮下面的源代碼,其中,R,S,和T是與#定義聲明的常量:有故障判定常數在這個彙編代碼

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個int(我*∫* K)。正如你所看到的,我知道每條指令都在做什麼,但是我很難逆向工程來確定傳遞給i,j和k的常量。

我不期待答案,但任何提示點我在正確的方向將不勝感激

+0

你正在使用哪個版本? –

+0

在查看代碼後,我能夠確定%edx經歷了一系列算術運算,然後在指令9%處將edx作爲解除引用移至%eax(其被設置爲當時的地址A) 。另外,非常感謝無論誰編輯我的帖子以適合適合的格式,我是本站的noob。 – user3296049

+0

這個版本是ATT – user3296049

回答

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)

+0

Brett,謝謝你非常感謝你的幫助。我希望能夠通過更多練習來更好地將這些問題概念化。很難直觀地看到asm指令列表有時候在做什麼 – user3296049

+0

你能解釋爲什麼我* 111 = i * 3 * 37嗎? –

+0

@大衛由於3 * 37 = 111 –

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個元素,就是我的索引)

+0

我得到了初始循環索引乘法混合,我已經糾正。你似乎也犯了一個類似的錯誤 - 如果你訪問元素:'A [0] [36] [0]',那麼'37.j'就會產生:'1332'! –

+0

你說得對,我把索引放錯了順序,修正了。謝謝! –