我已經分解了反彙編,以顯示如何從C源代碼生成程序集。
8(%ebp)
= x
,12(%ebp)
= y
,16(%ebp)
= z
arith:
創建堆棧幀:
pushl %ebp
movl %esp,%ebp
移動
x
成
eax
,
y
成
edx
:
movl 8(%ebp),%eax
movl 12(%ebp),%edx
t1 = x + y
。
leal
(加載有效地址)將添加
edx
和
eax
,和
t1
將在
ecx
:
leal (%edx,%eax),%ecx
int t4 = y * 48;
在下面兩個步驟,乘以3,然後通過16
t4
最終將
edx
:
乘以edx
乘以2,並將edx
加上結果,即。 edx = edx * 3
:
leal (%edx,%edx,2),%edx
左移4位,即,由16乘:
sall $4,%edx
int t2 = z+t1;
。
ecx
最初保持
t1
,
z
是在
16(%ebp)
,在指令
ecx
的端部將被保持
t2
:
addl 16(%ebp),%ecx
int t5 = t3 + t4;
。
t3
只不過是
x + 4
,而不是計算和存儲
t3
,
t3
的表達式放在一行。該指令至關重要,它與
t3
+
t4
相同。它增加了
edx
(
t4
)和
eax
(
x
),並將4作爲
偏移量來實現該結果。
leal 4(%edx,%eax),%eax
int rval = t2 * t5;
相當直接的這一個; ecx
代表t2
和eax
代表t5
。返回值通過eax
傳回給調用者。
imull %ecx,%eax
銷燬堆棧幀和恢復
esp
和
ebp
:從日常
movl %ebp,%esp
popl %ebp
返回:
ret
從這個例子可以看出, resul噸是一樣的,但結構有點不同。最有可能的是,這些代碼是通過某種優化編譯的,或者有人自己寫了這些代碼來證明一個觀點。
正如其他人所說,你不能去準確地返回到從拆卸的來源。這取決於閱讀程序集的人的解釋以提供相應的C代碼。
爲了幫助學習組件和理解你的C程序的拆卸,你可以做在Linux上執行以下操作:
編譯與調試信息(-g
),這將嵌入源:
gcc -c -g arith.c
如果你是一個64位的機器上,你可以告訴編譯器創建與-m32
標誌一個32位二進制(我這樣做了下面的例子)。
使用objdump的轉儲對象文件與它的源交織:
objdump -d -S arith.o
-d
=拆卸,-S
=顯示源。您可以添加-M intel-mnemonic
,如果你喜歡,在過& T語法,你的例子使用使用英特爾ASM語法。
輸出:
arith.o: file format elf32-i386
Disassembly of section .text:
00000000 <arith>:
int arith(int x, int y, int z)
{
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 20 sub $0x20,%esp
int t1 = x+y;
6: 8b 45 0c mov 0xc(%ebp),%eax
9: 8b 55 08 mov 0x8(%ebp),%edx
c: 01 d0 add %edx,%eax
e: 89 45 fc mov %eax,-0x4(%ebp)
int t2 = z+t1;
11: 8b 45 fc mov -0x4(%ebp),%eax
14: 8b 55 10 mov 0x10(%ebp),%edx
17: 01 d0 add %edx,%eax
19: 89 45 f8 mov %eax,-0x8(%ebp)
int t3 = x+4;
1c: 8b 45 08 mov 0x8(%ebp),%eax
1f: 83 c0 04 add $0x4,%eax
22: 89 45 f4 mov %eax,-0xc(%ebp)
int t4 = y * 48;
25: 8b 55 0c mov 0xc(%ebp),%edx
28: 89 d0 mov %edx,%eax
2a: 01 c0 add %eax,%eax
2c: 01 d0 add %edx,%eax
2e: c1 e0 04 shl $0x4,%eax
31: 89 45 f0 mov %eax,-0x10(%ebp)
int t5 = t3 + t4;
34: 8b 45 f0 mov -0x10(%ebp),%eax
37: 8b 55 f4 mov -0xc(%ebp),%edx
3a: 01 d0 add %edx,%eax
3c: 89 45 ec mov %eax,-0x14(%ebp)
int rval = t2 * t5;
3f: 8b 45 f8 mov -0x8(%ebp),%eax
42: 0f af 45 ec imul -0x14(%ebp),%eax
46: 89 45 e8 mov %eax,-0x18(%ebp)
return rval;
49: 8b 45 e8 mov -0x18(%ebp),%eax
}
4c: c9 leave
4d: c3 ret
正如你可以看到,沒有優化編譯器產生比你有例如通過更大的二進制。你可以玩的是和編譯時添加一個編譯器優化標誌(即-O1
,-O2
,-O3
)。優化級別越高,反彙編看起來就越抽象。
例如,只有1級優化(gcc -c -g -O1 -m32 arith.c1
),產生的彙編代碼是短了很多:
00000000 <arith>:
int arith(int x, int y, int z)
{
0: 8b 4c 24 04 mov 0x4(%esp),%ecx
4: 8b 54 24 08 mov 0x8(%esp),%edx
int t1 = x+y;
8: 8d 04 11 lea (%ecx,%edx,1),%eax
int t2 = z+t1;
b: 03 44 24 0c add 0xc(%esp),%eax
int t3 = x+4;
int t4 = y * 48;
f: 8d 14 52 lea (%edx,%edx,2),%edx
12: c1 e2 04 shl $0x4,%edx
int t5 = t3 + t4;
15: 8d 54 11 04 lea 0x4(%ecx,%edx,1),%edx
int rval = t2 * t5;
19: 0f af c2 imul %edx,%eax
return rval;
}
1c: c3 ret
什麼優化你,當你正在編譯使用水平?如果您想要逐行轉換,請使用-O0,否則,您需要考慮優化。 – Maz
...和逆轉優化代碼回到原來的C語句順序並不完全可能的。 –
你確定這是一個天真的彙編?它看起來有點優化。寫下函數計算的代數表達式,看看你是否可以發現它。 –