前提梗要:
自從又開始工作后(沒錯(cuò),又)烂斋,時(shí)間就顯得越來越寶貴了(指打游戲時(shí)間)屹逛,也因?yàn)檫@個(gè)原因,文章也沒怎么更新了源祈。雖然空閑之余也看了看最近新印的《0day安全》和剛買的《白帽子講web安全》煎源,但也沒能看的出個(gè)所以然,成為大師香缺。盡管沒能走上大師之路手销,但我還是為自己學(xué)過那么一點(diǎn)丟丟匯編而感到驕傲的。這不图张,前幾天公司的一個(gè)同事道貌岸然的問我:“a++和++a你知道有什么區(qū)別嗎锋拖?”我支支吾吾的說一個(gè)運(yùn)算的時(shí)候加一诈悍,一個(gè)沒加一(可不是嘛?大學(xué)老師都這么說的)兽埃。好家伙結(jié)果我剛說完侥钳,坐我隔壁的實(shí)習(xí)生馬上冒出來,說了棧柄错,又說了嘰里呱啦的一大堆我硬是沒整明白舷夺。在這之后我還遭到了同事的無情嘲諷。
事后我感到了無盡的空虛和悔恨售貌「“逆你??個(gè)向,整了半天這么基礎(chǔ)的都沒整明白颂跨「疑欤”我心中暗想。
說是遲那是快恒削,下班鐘聲一響起我就火速飛向宿舍池颈,打開了簡書,寫下了此文钓丰,然后再順便寫幾行代碼躯砰,拉去IDA一波帶走。
C++的代碼:
本文編寫a++和++a的代碼是用C++來實(shí)現(xiàn)的斑粱,當(dāng)然我捉摸JAVA等其他語言里的也差不多弃揽,這里只是為了方便方匯編罷了:
#include <iostream>
int main()
{
std::cout << "Hello World!\n";
int a = 1;
int resultA = a++;
int b = 1;
int resultB = ++b;
std::cout << resultA << std::endl;
std::cout << resultB << std::endl;
}
代碼很簡單,只要稍微學(xué)過一門編程語言的都能看懂则北;順便一提最后兩行std::cout ...
的代碼是控制臺(tái)打印輸出矿微,也不重要可略過。
匯編中的區(qū)別:
將程序編譯成debug版本后(release版本編譯器會(huì)優(yōu)化尚揣,a++和++a會(huì)被直接優(yōu)化成結(jié)果)拖進(jìn)了IDA里涌矢,因?yàn)楸旧沓绦蛞膊粡?fù)雜,還是自己寫的快骗,一下次就找到了對應(yīng)的地方:
看不懂匯編不要緊娜庇,我稍微改了下變量名字就明白了:
好了,現(xiàn)在無意義的局部變量都被改成了稍微有意義的名字了方篮,有人可能會(huì)說我還是看不懂名秀,在這里我們只要理解
mov [a], b //把b的值賦值到a的地址
如上圖第一句: mov [ebp+resultA], 1意為地址epb+resultA寫入1這個(gè)值。
push xx
call //傳入?yún)?shù)xx藕溅,并調(diào)用一個(gè)方法
如上圖最后一句 push eax call ds:std__cout匕得,意為用傳eax的參數(shù)并調(diào)用std__cout方法
我們可以看到匯編里有兩個(gè)call,剛好對應(yīng)我們代碼里調(diào)用的兩行std::cout語句:
std::cout << resultA << std::endl;
std::cout << resultB << std::endl;
用到的參數(shù)就是只有resultA和resultB了。所以我們看到匯編代碼中兩個(gè)call指令上面最近的一條push eax汁掠,就是指的是resutA和resutB略吨。
先從第一個(gè)call開始看,第一個(gè)call對應(yīng)的參數(shù)是resultA也就是a++了考阱,如上圖所示可以看到參數(shù)來自[ebp+copyA]翠忠,然后我們再通過對這個(gè)參數(shù)的向上追蹤就明顯可以看到:
.text:004125FB mov [ebp+resultA], 1
.text:00412602 mov eax, [ebp+resultA]
.text:00412605 mov [ebp+copyA], eax
.text:00412608 mov ecx, [ebp+resultA]
.text:0041260B add ecx, 1
.text:0041260E mov [ebp+resultA], ecx
[ebp+copyA]其實(shí)就是resultA剛初始化時(shí)候的副本,而我們a++后乞榨,這個(gè)加一事實(shí)上確實(shí)加到了resultA中秽之,只不過我們用的是他剛開始初始化后,在加一前產(chǎn)生的一個(gè)副本
那么如果是++a呢姜凄?同樣的我們看第二個(gè)call的參數(shù)政溃,他來源于[ebp+copyB]:
.text:00412611 mov [ebp+resultB], 1
.text:00412618 mov eax, [ebp+resultB]
.text:0041261B add eax, 1
.text:0041261E mov [ebp+resultB], eax
.text:00412621 mov ecx, [ebp+resultB]
.text:00412624 mov [ebp+copyB], ecx
這很明顯,與剛初始化就給副本的操作不同态秧,這里對自身[ebp+resultB]自加一后才再給[ebp+copyB]賦值,也就是說副本和原件值是一樣的扼鞋。
結(jié)語:
真的一點(diǎn)都不復(fù)雜申鱼,什么a++和++a,下次面試別人問你就直接說一個(gè)是加一前的副本云头,一個(gè)是加一后的副本就好了捐友,實(shí)在不行現(xiàn)場匯編給他看。