在高級語言橫行的現(xiàn)在,能看懂機(jī)器語言的程序員并不多湿故。了解了寄存器阿趁,匯編等知識后,才能對進(jìn)程坛猪,線程有更深的認(rèn)識脖阵,而不僅僅只是一個Thread類。
寄存器
一個CPU包含一組8個存儲32位值寄存器墅茉。這些寄存器用來保存整數(shù)數(shù)據(jù)和指針命黔。訪問寄存器的速度比訪問內(nèi)存的速度快。特別留意下%esp和%ebp這兩個寄存器分別保存指向程序棧的棧頂位置的指針和指向程序棧棧底位置的指針就斤。下面規(guī)定%eax表示圖中%eax方法中的值悍募,是個32位整數(shù)。其他寄存器同理洋机。
函數(shù)的匯編實現(xiàn)
文中有這么一個例子:
這例子中有兩個函數(shù)caller()和swap_add()坠宴,下面左邊的圖是caller()的棧幀,右邊的圖是調(diào)用swap_add()后绷旗,在caller()棧幀下建了swap_add的棧幀喜鼓。
我們看下caller的匯編代碼忧设,看下它被調(diào)用時是如何建立自己的棧幀和swap_add的棧幀并為swap_add準(zhǔn)備好參數(shù)的:
第2行:保存%ebp指向內(nèi)存的值到棧頂
第3行:將%esp中的值賦給%ebp
第4行:將%esp-24,也就是將棧指針下移24個字節(jié)
第5行:將%ebp-4內(nèi)存處賦值為534颠通,也就是arg1
第6行:將%ebp-8內(nèi)存處賦值為1057,也就是arg2
第7行膀懈,8:將arg2的地址(&arg1)賦值給%esp+4指向的內(nèi)存
第9行顿锰,10:將arg1的地址(&arg2)賦值給%esp指向的內(nèi)存,也就是棧頂
第11行:調(diào)用swap_add方法
經(jīng)過這段匯編代碼启搂,就形成了上面的左圖硼控。再來看下建立swap_add棧幀的過程:
第2行:保存%ebp到棧頂
第3行:更新%ebp也指向棧頂,到這里新的棧幀已經(jīng)建立
第4行:%ebx保存著caller函數(shù)中的值胳赌,在調(diào)用swap_add時可能覆蓋%ebx牢撼,所以要先將%ebx里面的值保存到棧上,退出swap_add時要疑苫,恢復(fù)%ebx的值熏版,這樣才不會影響返回到caller后,caller正常執(zhí)行捍掺。到這里就形成了上面右邊的棧幀結(jié)構(gòu)撼短。
swap_add的棧幀建立好后,我們看下swap_add內(nèi)部的匯編代碼:
第5行:將參數(shù)&arg1保存到%edx
第6行:將參數(shù)&arg2保存到%ecx
第7行:將arg1保存到%ebx
第8行:將arg2保存到%eax
第9行:將%eax的值保存到%edx指向的內(nèi)存處
第10行:將%ebx的值保存到%ecx指向的內(nèi)存處挺勿,到這里實現(xiàn)了arg1和arg2值的交換
第11行:將%ebx加到%eax中曲横,%eax規(guī)定為保存返回值的寄存器
這個函數(shù)中,我們交換了arg1和arg2的值不瓶,并且將它們的和保存在寄存器%eax中禾嫉。
我們最后看下swap_add是如何返回到caller中的:
第12行:將上面保存在棧中的%ebx的值重新保存到%ebx中
第13行:%ebp指向caller的棧底
第14行:通知程序計數(shù)器回到caller中swap_add方法后面的那條指令,到這里又回到了caller的棧幀(上面左圖的棧幀)蚊丐,好像swap_add沒有調(diào)用過一樣熙参。
總結(jié)
熟悉了這個過程,我們對局部變量麦备,指針尊惰,棧溢出這些名詞肯定會更深刻的理解。下一節(jié)泥兰,我們看下虛擬存儲器弄屡。
參考:《深入理解計算機(jī)系統(tǒng)》