[英]Understanding the purpose of some assembly statements
我試圖了解一些匯編代碼並設法完成大部分匯編代碼,除了幾行。 我能夠理解大部分內部發生的事情,但我無法完全理解代碼開頭和結尾發生了什么(以及為什么會發生)。 有人可以對此有所了解嗎?
int main() {
int a, b;
a = 12;
b = 20;
b = a + 123;
return 0;
}
拆卸版本:
8048394:8d 4c 24 04 lea 0x4(%esp),%ecx ; ??
8048398:83 e4 f0 and $0xfffffff0,%esp ; ??
804839b:ff 71 fc pushl -0x4(%ecx) ; ??
804839e:55 push %ebp ; Store the Base pointer
804839f:89 e5 mov %esp,%ebp ; Initialize the Base pointer with the stack pointer
80483a1:51 push %ecx ; ??
80483a2:83 ec 4c sub $0x4c,%esp ; ??
80483a5:c7 45 f8 0c 00 00 00 movl $0xc,-0x8(%ebp) ; Move 12 into -0x8(%ebp)
80483ac:c7 45 f4 14 00 00 00 movl $0x14,-0xc(%ebp) ; Move 20 into -0xc(%ebp)
80483b3:8b 45 f8 mov -0x8(%ebp),%eax ; Move 12@-0x8(%ebp) into eax
80483b6:83 c0 7b add $0x7b,%eax ; Add 123 to 12@eax
80483b9:89 45 f4 mov %eax,-0xc(%ebp) ; Store the result into b@-0xc(%ebp)
80483bc:b8 00 00 00 00 mov $0x0,%eax ; Move 0 into eax
80483c1:83 c4 10 add $0x10,%esp ; ??
80483c4:59 pop %ecx ; ??
80483c5:5d pop %ebp ; ??
80483c6:8d 61 fc lea -0x4(%ecx),%esp ; ??
堆棧向下增長。 push
從堆棧指針(esp)中減去,並且pop
添加到esp。 你必須牢記這一點,以了解很多這一點。
8048394:8d 4c 24 04 lea 0x4(%esp),%ecx ; ??
lea =加載有效地址
這將4字節的東西的地址保存到堆棧中。 由於這是32位(4字節字)x86代碼,這意味着堆棧中的第二項。 由於這是函數的代碼(在這種情況下為main),因此堆棧頂部的4個字節是返回地址。
8048398:83 e4 f0 and $0xfffffff0,%esp ; ??
此代碼確保堆棧對齊到16個字節。 在此操作之后,esp將小於或等於此操作之前的值,因此堆棧可能會增長,從而保護可能已存在於堆棧中的任何內容。 這有時在main
中完成,以防函數使用未對齊的堆棧調用,這會導致事情變得非常慢(我認為16字節是x86上的緩存行寬,盡管4字節對齊在這里非常重要)。 如果main有一個未對齊的堆棧,那么程序的其余部分也將如此。
804839b:ff 71 fc pushl -0x4(%ecx) ; ??
由於ecx之前被加載為指向前一個堆棧頂部返回地址另一側的東西的指針,所以因為它有一個-4索引,這指的是返回當前函數被推回的返回地址到堆棧的頂部,以便main可以正常返回。 (推送是神奇的,似乎能夠在同一指令中加載和存儲到RAM中的不同位置)。
804839e:55 push %ebp ; Store the Base pointer
804839f:89 e5 mov %esp,%ebp ; Initialize the Base pointer with the stack pointer
80483a1:51 push %ecx ; ??
80483a2:83 ec 4c sub $0x4c,%esp ; ??
這主要是標准的功能序言(以前的東西是主要的特殊功能)。 這是一個堆棧框架(ebp和esp之間的區域),其中局部變量可以存在。 推送ebp,以便可以在結尾(在當前函數的末尾)恢復舊的堆棧幀。
80483a5:c7 45 f8 0c 00 00 00 movl $0xc,-0x8(%ebp) ; Move 12 into -0x8(%ebp)
80483ac:c7 45 f4 14 00 00 00 movl $0x14,-0xc(%ebp) ; Move 20 into -0xc(%ebp)
80483b3:8b 45 f8 mov -0x8(%ebp),%eax ; Move 12@-0x8(%ebp) into eax
80483b6:83 c0 7b add $0x7b,%eax ; Add 123 to 12@eax
80483b9:89 45 f4 mov %eax,-0xc(%ebp) ; Store the result into b@-0xc(%ebp)
80483bc:b8 00 00 00 00 mov $0x0,%eax ; Move 0 into eax
eax是存儲整數函數返回值的地方。 這是設置為從main返回0。
80483c1:83 c4 10 add $0x10,%esp ; ??
80483c4:59 pop %ecx ; ??
80483c5:5d pop %ebp ; ??
80483c6:8d 61 fc lea -0x4(%ecx),%esp ; ??
這是功能結局。 由於開頭的奇怪堆棧對齊代碼,因此更難理解。 盡管如此,我在弄清楚為什么堆棧的調整次數比次數更少時會有一點麻煩。
很明顯,這個特定的代碼沒有使用優化編譯。 如果那里可能不會那么多,因為編譯器可以看到,即使它沒有在你的main
列出的數學,程序的最終結果是相同的。 對於實際執行某些操作(具有副作用或結果)的程序,有時更容易閱讀輕微優化的代碼(-cc或-0s參數到gcc)。
對於非main
函數,由編譯器生成的讀取匯編通常更容易。 如果你想閱讀以理解代碼,那么你自己寫一個函數,它接受一些參數來產生一個結果或者對全局變量起作用,你將能夠更好地理解它。
可能對你有幫助的另一件事就是讓gcc為你生成匯編文件,而不是反匯編它們。 -S
標志告訴它生成它(但不生成其他文件),並在末尾用.s
命名匯編文件。 這比閱讀反匯編版本更容易閱讀。
不知道為什么編譯器會完成所有這些工作,但這就是我能解讀的內容:
8048394:8d 4c 24 04 lea 0x4(%esp),%ecx ; ecx := esp+4
8048398:83 e4 f0 and $0xfffffff0,%esp ; align the stack to 16 bytes
804839b:ff 71 fc pushl -0x4(%ecx) ; push [ecx-4] ([esp])
80483a1:51 push %ecx ; push ecx
80483a2:83 ec 4c sub $0x4c,%esp ; allocate 19 dwords on stack
80483c1:83 c4 10 add $0x10,%esp ; deallocate 4 dwords from stack
80483c4:59 pop %ecx ; restore ecx
80483c5:5d pop %ebp ; and ebp
80483c6:8d 61 fc lea -0x4(%ecx),%esp ; esp := [ecx-4]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.