2012-06-11 53 views
2

我想了解GNU的以下行爲爲。GNU作爲與全球標籤jmp的奇怪

在OS X下面的試驗程序(蘋果cctools-822/GNU爲1.38)

.globl foo 
    jmp foo 
foo: 
    ret 

被編碼以

00000000 e900000000 jmp   0x00000005 
foo: 
    00000005 c3   ret 

而GNU爲在Linux(GNU爲2.22)編碼到

       .global foo 
    0000  E9FCFFFF  jmp 0x35 # foo 
       FF 
foo: 
    0005  C3    ret 

爲什麼後者對我來說會造成奇怪的跳躍?

而且,顯然這神奇0xfcffffff地址用於 每次跳轉到一個全球性的標籤:

test2.s

.globl foo 
    jmp foo 
    .globl bar 
    jmp bar 
    .globl baz 
    jmp baz 
foo: 
    push $1 
    ret 
bar: 
    push $2 
    ret 
baz: 
    push $3 
    ret 

與GNU產生如在Linux(GNU爲2.22)

     .globl foo 
    0000 E9FCFFFF jmp foo 
      FF 
         .globl bar 
    0005 E9FCFFFF jmp bar 
      FF 
         .globl baz 
    000a E9FCFFFF jmp baz 
      FF 
foo: 
    000f 6A01  push $1 
    0011 C3   ret 
bar: 
    0012 6A02  push $2 
    0014 C3   ret 
baz: 
    0015 6A03  push $3 
    0017 C3   ret 

誰能解釋這種行爲?

回答

2

這僅僅是一個不同類型的重定位項(R_386_PC32)的。

你不必擔心它,連接器將插入正確的地址。

你可以看到定位項如果添加-r選項objdump,例如

objdump -Dr test2.o 

請注意,值爲0xfffffffc = -4,因爲x86是小尾數。

this question見。

+0

謝謝,確實如此。是否有任何形式的文件? – Tobias

+0

請參閱[System V ABI,Intel386體系結構處理器補充說明](http://www.sco.com/developers/devspecs/abi386-4.pdf) – starblue

+0

好的,這真的很重要。謝謝。 – Tobias

1

我假設你正在拆卸不是對象的可執行文件?這對於所有工具鏈都是非常典型的,所有的編譯語言都是在喜歡之前進行反對的。鏈接器...鏈接...對象,將全局變量鏈接到一起,函數名稱,變量等。直到鏈接階段,您無法知道您所處的地址空間以及變量名稱,因此某些本地人員對指令集和覆蓋範圍的長度以及全局變量在鏈接時間之前無法解析,因此對象將會放置某種填充數據,而不是可能會以奇怪方式進行反彙編的指令。

+0

那麼蘋果的彙編程序如何事先知道正確的地方以及linux/gnu沒有? – Tobias

+0

彙編程序必須像過去那樣將目標地址發送給它。 (.org 0x1234)或其他形式,用於彙編到對象,然後鏈接到可執行文件,這可能是您如何告訴鏈接器將它放在哪裏。每個工具鏈都可以有自己的解決方案。通常,如果執行兩個步驟(語言到對象,與可執行文件鏈接的對象),則對象不能具有全局知識,也不能具有多遠(要知道它是否可以使用近或遠的訪問),因此佔位符被內置以由鏈接器解析。根據定義,這是一個鏈接器。 –

+0

請注意,做一些像gcc myprog.c -o myprog * IS *做兩步它編譯爲對象,然後單獨調用ld鏈接,然後清理中間文件,所以你不知道有三個或四個程序涉及從.c到可執行文件。 –