在語(yǔ)法上, 我們通常認(rèn)為以下的兩條語(yǔ)句是等價(jià)的:
mov ecx, offset DATA_LABLE //其中DATA_LABLE是數(shù)據(jù)定義標(biāo)簽
lea ecx, DATA_LABLE
而更進(jìn)一步, 我們也會(huì)認(rèn)為以下兩句是等價(jià)的:
mov ecx, ebp-8
lea ecx, [ebp-8]
第一種, 用的是存儲(chǔ)器尋址方式; 而第二種, 用的是寄存器尋址和寄存器間接尋址方式. 讓我意想不到的是, 在第二種情況下, vc的處理并沒(méi)有讓寄存器尋址和寄存器間接尋址方式的mov和lea兩者之間實(shí)現(xiàn)等價(jià). 在使用 _asm{} 的方式將"mov ecx, ebp-8"這條語(yǔ)句括起來(lái)編譯之后, 很遺憾地, 我在vc的反匯編窗口發(fā)現(xiàn)它變成了這樣的一條語(yǔ)句: "mov ecx, ebp". 啊哦, 我的"-8"竟然不翼而飛了! 到目前為止, 我尚沒(méi)有查到造成這種現(xiàn)象的原因所在, 我只能暫時(shí)將它歸為vc的bug了.
對(duì)gcc下會(huì)不會(huì)存在這個(gè)問(wèn)題呢? 為更進(jìn)一步證實(shí), 我使用gcc重新寫(xiě)了這句代碼: "mov ecx, ebp-8", 但重寫(xiě)后的代碼由當(dāng)初的一句變成了這樣的兩句:
movl %ebp, %ecx
subl $8, %ecx
之所以改寫(xiě)成這樣的兩句, 是因?yàn)槲野l(fā)現(xiàn)在AT&T的匯編語(yǔ)法中, 對(duì)于雙寄存器尋址的操作, 不能對(duì)寄存器取的值作任何變換, 也就是說(shuō)不能寫(xiě)成"movl %ebp-8, %ecx"的形式, 而寄存器間接尋址的操作就可以作變換, 比如:
movl -8(%ebp), %ecx 此句相當(dāng)于intel asm里的: mov ecx, [ebp-8]
movl (%ebp, %eax), %ecx 此句相當(dāng)于intel asm里的: mov ecx, [ebp+eax]
movl (%ebp, %eax, 4), %ecx 此句相當(dāng)于intel asm里的: mov ecx, [ebp+eax*4]
movl -8(%ebp, %eax, 4), %ecx 此句相當(dāng)于intel asm里的: mov ecx, [ebp+eax*4-8]
從以上幾條語(yǔ)句來(lái)看, 似乎AT&T語(yǔ)法對(duì)寄存器間接尋址方式的支持沒(méi)有intel asm更具人性化, 但我猜想AT&T之所以采用這樣的方法, 可能一定程度上也是為了提高微指令級(jí)的執(zhí)行效率.
當(dāng)然, "mov ecx, ebp-8"這句也可以改寫(xiě)成這樣的兩句:
subl $8, %ebp
movl %ebp, %ecx
但一般不會(huì)這么作, 道理是很顯然的, ebp通常會(huì)作為函數(shù)內(nèi)的基址寄存器, 用于存放函數(shù)入口點(diǎn)的堆棧首地址, 這個(gè)值的改變會(huì)直接影響其后語(yǔ)句對(duì)局部變量以及函數(shù)參數(shù)的引用發(fā)生變化, 所以, 在函數(shù)首部之后的執(zhí)行體中, ebp通常是不允許被改變的, 這也是我們?cè)O(shè)計(jì)自己的匯編代碼時(shí)所應(yīng)該遵循的原則.
不知道vc為什么會(huì)將ebp之后的立即數(shù)作丟棄處理, 這顯然是沒(méi)有道德的行為. 這讓我想起了這樣的一句話: 不要試圖幫助用戶去糾正錯(cuò)誤, 而是當(dāng)錯(cuò)誤發(fā)生時(shí)去提醒用戶, 因?yàn)槌绦蛟俾斆饕膊粫?huì)始終明白設(shè)計(jì)者的真正意圖 ,我們所需要作的就是"為異常捕獲提供盡可能詳細(xì)的日志, 并及時(shí)通知用戶這種異常, 試圖糾正異常的作法從方法上就是錯(cuò)誤和愚蠢的".
mov ecx, offset DATA_LABLE //其中DATA_LABLE是數(shù)據(jù)定義標(biāo)簽
lea ecx, DATA_LABLE
而更進(jìn)一步, 我們也會(huì)認(rèn)為以下兩句是等價(jià)的:
mov ecx, ebp-8
lea ecx, [ebp-8]
第一種, 用的是存儲(chǔ)器尋址方式; 而第二種, 用的是寄存器尋址和寄存器間接尋址方式. 讓我意想不到的是, 在第二種情況下, vc的處理并沒(méi)有讓寄存器尋址和寄存器間接尋址方式的mov和lea兩者之間實(shí)現(xiàn)等價(jià). 在使用 _asm{} 的方式將"mov ecx, ebp-8"這條語(yǔ)句括起來(lái)編譯之后, 很遺憾地, 我在vc的反匯編窗口發(fā)現(xiàn)它變成了這樣的一條語(yǔ)句: "mov ecx, ebp". 啊哦, 我的"-8"竟然不翼而飛了! 到目前為止, 我尚沒(méi)有查到造成這種現(xiàn)象的原因所在, 我只能暫時(shí)將它歸為vc的bug了.
對(duì)gcc下會(huì)不會(huì)存在這個(gè)問(wèn)題呢? 為更進(jìn)一步證實(shí), 我使用gcc重新寫(xiě)了這句代碼: "mov ecx, ebp-8", 但重寫(xiě)后的代碼由當(dāng)初的一句變成了這樣的兩句:
movl %ebp, %ecx
subl $8, %ecx
之所以改寫(xiě)成這樣的兩句, 是因?yàn)槲野l(fā)現(xiàn)在AT&T的匯編語(yǔ)法中, 對(duì)于雙寄存器尋址的操作, 不能對(duì)寄存器取的值作任何變換, 也就是說(shuō)不能寫(xiě)成"movl %ebp-8, %ecx"的形式, 而寄存器間接尋址的操作就可以作變換, 比如:
movl -8(%ebp), %ecx 此句相當(dāng)于intel asm里的: mov ecx, [ebp-8]
movl (%ebp, %eax), %ecx 此句相當(dāng)于intel asm里的: mov ecx, [ebp+eax]
movl (%ebp, %eax, 4), %ecx 此句相當(dāng)于intel asm里的: mov ecx, [ebp+eax*4]
movl -8(%ebp, %eax, 4), %ecx 此句相當(dāng)于intel asm里的: mov ecx, [ebp+eax*4-8]
從以上幾條語(yǔ)句來(lái)看, 似乎AT&T語(yǔ)法對(duì)寄存器間接尋址方式的支持沒(méi)有intel asm更具人性化, 但我猜想AT&T之所以采用這樣的方法, 可能一定程度上也是為了提高微指令級(jí)的執(zhí)行效率.
當(dāng)然, "mov ecx, ebp-8"這句也可以改寫(xiě)成這樣的兩句:
subl $8, %ebp
movl %ebp, %ecx
但一般不會(huì)這么作, 道理是很顯然的, ebp通常會(huì)作為函數(shù)內(nèi)的基址寄存器, 用于存放函數(shù)入口點(diǎn)的堆棧首地址, 這個(gè)值的改變會(huì)直接影響其后語(yǔ)句對(duì)局部變量以及函數(shù)參數(shù)的引用發(fā)生變化, 所以, 在函數(shù)首部之后的執(zhí)行體中, ebp通常是不允許被改變的, 這也是我們?cè)O(shè)計(jì)自己的匯編代碼時(shí)所應(yīng)該遵循的原則.
不知道vc為什么會(huì)將ebp之后的立即數(shù)作丟棄處理, 這顯然是沒(méi)有道德的行為. 這讓我想起了這樣的一句話: 不要試圖幫助用戶去糾正錯(cuò)誤, 而是當(dāng)錯(cuò)誤發(fā)生時(shí)去提醒用戶, 因?yàn)槌绦蛟俾斆饕膊粫?huì)始終明白設(shè)計(jì)者的真正意圖 ,我們所需要作的就是"為異常捕獲提供盡可能詳細(xì)的日志, 并及時(shí)通知用戶這種異常, 試圖糾正異常的作法從方法上就是錯(cuò)誤和愚蠢的".