最近看鏈結器原始碼中,對位置無關**pic(共享庫)的鏈結問題,發現對call和jmp很多不常用的用法,這裡試驗並總結了一下各種用法。
我們最常用的jmp形式,就是 jmp後面跟個標籤!這個沒什麼可說的!
假如標籤叫做mylabel,它的位址是0x8048377,而且有個全域性變數b,b儲存的內容就是mylabel的位址,而b的位址是0x80494a8。
即有這樣的賦值(載入)語句:
movl
$mylabel,%eax
//把mylabel的位址載入到eax暫存器中
movl
%eax,b
//把mylabel的位址載入到b中
movl
$b,%ebx
//把b的位址載入到ebx暫存器中
我們考慮下面的語句:
1. jmp
mylable 2.
jmp0x8048377 3.
jmp%eax 4.
jmp*%eax 5.
jmp*(%ebx) 6.
jmp*0x80494a8
7. jmp
*b8. jmp
$0x5
這7句jmp語句!分別都做了什麼?
1. 不用說,跳轉到mylabel標籤處繼續執行**,但是,是如何跳轉的呢?就是pc加上了mylabel標籤處對於jmp處的乙個偏移位址!可執行的二進位制**是這樣表示的:eb 03,就是說,pc+0x03就可以了。
2. 這裡,0x8048377是mylabel的位址,我以前研究過,標籤的作用,更他的位址的作用是等效的。所以,這裡的執行效果跟1中的相同。但是,還有些不一樣!這裡的二進位制**成了:e9 03 00 00 00 這裡用了32位表示了這個偏移,而在1中,只用了8位!
3. 在編譯鏈結的時候,這句**會有警告:warning:indirect jmp without '*'。間接跳轉沒有『*』符號,但是,執行起來,還是沒有錯。看一下二進位制的可執行檔案的**,發現,給補上了個『*』號!而且二進位制是:ff e0.
4. 其實,4是3的補充版,正常的形式就是4,而三是有警告的被補充的版本。
5. %ebx是b的位址,那麼(%ebx)表示ebx的值為位址,指向的地方。這裡指向了b的內容,也就是mylabel的位址!於是,化簡後,5也就等效與2,但是,二進位制表示是:ff 23。
6. 0x80494a8是b的位址,這裡看做記憶體數,那麼實質上,b指向的值是mylabel的位址,於是,化簡後同2,二進位制**是:ff 25 a8 94 04 08。
7. b是標籤,代表乙個位址,所以,這裡同6,二進位制**也同6
8. 這句話是錯誤的,jmp不支援立即數!
所以說,正確的寫法有:
1. jmp
mylable
//eb 03
2.jmp
0x8048377
//e9 03 00 00 00 3.
jmp*%eax
//ff e0
4.jmp
*(%ebx)
//ff 23
5.jmp
*0x80494a8
//ff 25 a8 94 04 08 6.
jmp*b
//ff 25 a8 94 04 08
1和2叫做間接定址,就是算偏移量的。後面沒有『*』號,而是直接乙個標籤或者位址(標籤就可以看做是位址),所以說,就是乙個直接的位址的值。間接跳轉的二進位制**是eb或者e9,是e開頭的。
3,4,5,6叫做直接定址,直接定址的標識就是這個『*』號!直接定址,就是pc直接賦值某個位址,而不是加偏移量。所以,『*』號後面的部分,其實是乙個要付給pc的值,那麼,取值的方式就好想象了!直接跳轉的二進位制**是ff開頭的。
3是暫存器直接取值;4是暫存器間接取值;5是記憶體數取值;6是標籤取值(實質上同5)。
確實,有點意思~
call同jmp指令!
令人迷惑的隱藏規則
隱藏 是指派生類的函式遮蔽了與其同名的基類函式,規則如下 1 如果派生類的函式與基類的函式同名,但是引數不同。此時,不論有無virtual 關鍵字,基類的函式將被隱藏 注意別與過載混淆 2 如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有virtual 關鍵字。此時,基類的函式被隱...
JMP段的跳轉short near far
無條件轉移指令jmp 這種跳轉指令有三種方式 短 short 近 near 和遠 far 短是指要跳至的目標位址與當前位址前後相差不超過128位元組。近是指跳轉的目標位址與當前位址在用乙個段內,即cs的值不變,只改變eip的值。遠指跳到另乙個 段去執行,cs eip都要改變。短和近在編碼上有所不同,...
jmp指令的簡單應用
一 8086cpu的轉移指令行為分類 jmp short 標號 ip ip 8位位移 8位位移範圍 128 127 jmp near ptr 標號 ip ip 16位位移 16位位移範圍 32768 32767 二 原碼,反碼,補碼的基礎概念和計算方法 在探求為何機器要使用補碼之前,讓我們先了解原碼...