2017-10-22 117 views
1

我看彙編代碼看起來像這樣:使用添加一個空的註冊?

addl %eax, -8(%rbp) 

我知道寄存器%eax中有一個值,但-8(%RBP)尚未到這條線之前感動。我是否認爲它是空的,並且會將%eax + 0的值放入-8(%rbp)?

+2

不可以,以前肯定是指定的,你需要看起來更難。它可能是用不同的指針寫的,例如相對於'rsp'。請注意,內存通常不會被清零,特別是不會經常指向「rbp」的堆棧。 – Jester

回答

4

正如@Jester在評論中指出的,它應該在該行之前的某個位置有一個指定的值,否則您正在查看潛在的未定義行爲。

讓我們考慮下面的C源代碼和相應的組件輸出(編譯GCC,不優化):

文件add_1_noinit.c

int main(void) { 
     int a; 

     return a += 1; 
} 

文件add_1_noinit.s (GCC -O0 -S add_1_noinit.c):

... snip ... 
.LFB0: 
     .cfi_startproc 
     pushq %rbp 
     .cfi_def_cfa_offset 16 
     .cfi_offset 6, -16 
     movq %rsp, %rbp 
     .cfi_def_cfa_register 6 
     addl $1, -4(%rbp) 
     movl -4(%rbp), %eax 
     popq %rbp 
     .cfi_def_cfa 7, 8 
     ret 
     .cfi_endproc 
.LFE0: 
... snip ... 

正如你所看到的,add_1_noinit.c不會初始化變量a,導致未定義的行爲(返回值main()未知)。

現在讓我們看一個初始化一個變量的輸出:

文件add_1_init.c

int main(void) { 
     int a = 0; 

     return a += 1; 
} 

文件add_1_init.s(GCC -O0 -S add_1_init。 c):

... snip ... 
.LFB0: 
     .cfi_startproc 
     pushq %rbp 
     .cfi_def_cfa_offset 16 
     .cfi_offset 6, -16 
     movq %rsp, %rbp 
     .cfi_def_cfa_register 6 
     movl $0, -4(%rbp) 
     addl $1, -4(%rbp) 
     movl -4(%rbp), %eax 
     popq %rbp 
     .cfi_def_cfa 7, 8 
     ret 
     .cfi_endproc 
.LFE0: 
... snip ... 

正如你所看到的,在這個例子,我們知道什麼是的main()的返回值,並將其值是增加到之前設置爲由-4(%RBP)所指向的內存區域。

+0

所以-​​8(%rbp)在該行之前沒有提及,也沒有使用%rsp的任何引用,但是存在一個存儲在-24(%rbp)的數組指針。 -8(%rbp)會​​在該數組中存儲第5個元素嗎?我不認爲這是正確的,因爲我認爲指針會指向數組的其他位置。我完全喪失了。 – wenjay

2

通常在硅存儲位中只有兩個狀態0和1,所以即使你沒有看到設置該寄存器的代碼,它不是「空的」,它包含一個模式,指令將使用該模式,崩潰或正確執行。現在在模擬邏輯中,你可以有三個或更多的狀態位爲0,1,x,其中用x表示的任何東西都是x或者任何用x表示的x都是。在這種情況下,你可以有一個「空」或至少未初始化的寄存器。 Xes就像他們感染你的模擬的瘟疫一樣,最終把整個事情變成xes。所以你必須非常小心,在閱讀之前總是寫。包括寄存器。

我相信在這種情況下,如果這是有效的代碼,那麼在該指令之前的某個點rbp被寫入一個理智的值。取決於你如何分解這個或者看着它,它可能是你已經反編譯爲代碼的一些數據模式。作爲x86很難正確反彙編,所以如果這是組裝代碼,你必須假定一些百分比可能是錯誤的。如果這只是從編譯器直接彙編或手工編寫的,那麼假設它不是錯誤的代碼,那麼在代碼或調用前面看到正在寫入的寄存器就不夠用了。

注意一個寄存器不能爲空,這些位將會有一個狀態,而位存儲不是空狀態,只是零或一個。