天天看點

arm-linux-ld詳解,arm-linux-ld 指令詳解

本文轉自《S3C2410完全開發手冊》 在開始後續實驗之前,我們得了解一下arm-linux-ld連接配接指令的使用。在上述實驗中,我們一直使用類似如下的指令進行連接配接: arm-linux-ld -Ttext 0x00000000 crt0.o led_on_c.o -o led_on_c_tmp.o 我們看看它是什麼意思: -o選

本文轉自《S3C2410完全開發手冊》

在開始後續實驗之前,我們得了解一下arm-linux-ld連接配接指令的使用。在上述實驗中,我們一直使用類似如下的指令進行連接配接:

arm-linux-ld -Ttext 0x00000000 crt0.o led_on_c.o -o led_on_c_tmp.o

我們看看它是什麼意思:

-o選項設定輸出檔案的名字為led_on_c_tmp.o;

“--Ttext 0x00000000”設定代碼段的起始位址為0x00000000;

這條指令的作用就是将crt0.o和led_on_c.o連接配接成led_on_c_mp.o可執行檔案,此可執行檔案的代碼段起始位址為0x00000000(即從這裡開始執行)。

我們感興趣的就是“—Ttext”選項!進入LINK目錄,link.s代碼如下:

1         .text

2 .global_start

3  _start:

4          b step1

5  step1:

6          ldr pc,=step2

7  step2:

8          b step2

Makefile 如下:

1  link:link.s

2      arm-linux-gcc –c -o link.o link.s

3      arm-linux-ld -Ttext 0x00000000 link.o -o link_tmp.o

4      #arm-linux-ld -Ttext 0x30000000 link.o -o link_tmp.o

5      arm-linux-objcopy -O binary-S link_tmp.o link

6      arm-linux-objdump –D -b binary -m arm link>ttt.s

7      #arm-linux-objdump –D -b binary -m arm link>ttt2.s

8  clean:

9      rm -f link

10     rm -f link.o

11     rm -f link_tmp.o

實驗步驟:

1.進入目錄LINK,運作make生成arm-linux-ld選項為“-Ttext 0x00000000”的反彙編碼ttt.s

2.make clean

3.修改Makefile:将第4、7行的“#”去掉,在第3、6行前加上“#”

4.運作make生成arm-linux-ld選項為“-Ttext 0x30000000”的反彙編碼ttt2.s

link.s程式中用到兩種跳轉方法:b跳轉指令、直接向pc寄存器指派。

我們先把在不同“—Ttext”選項下,生成的可執行檔案的反彙編碼列出來,再詳細分析這兩種不同指令帶來的差異。

ttt.s:ttt2.s

6    00000000 <.data>:                                    |  6    00000000 <.data>:

7    0:   eaffffff    b   0x4                              |  7    0:   eaffffff    b   0x4

8    4:   e59ff000    ldr pc, [pc, #0]    ; 0xc       |  8    4:   e59ff000    ldr pc, [pc, #0]    ; 0xc

9    8:   eafffffe    b   0x8                              |  9    8:   eafffffe    b   0x8

10    c:   30000008    andcc   r0, r0, r8              | 10    c:   00000008    andeq   r0, r0, r8

先看看b跳轉指令:它是個相對跳轉指令,其機器碼格式如下:

[31:28]位是條件碼;[27:24]位為“1010”(0xeaffffff)時,表示B跳轉指令,為“1011”時,表示BL跳轉指令;[23:0]表示偏移位址。

使用B或BL跳轉時,下一條指令的位址是這樣計算的:

将指令中24位帶符号的補碼立即數擴充為32(擴充其符号位);将此32位數左移兩位;将得到的值加到pc寄存器中,即得到跳轉的目标位址。

我們看看第一條指令“b step1”的機器碼eaffffff:

1.24位帶符号的補碼為0xffffff,将它擴充為32得到:0xffffffff

2.将此32位數左移兩位得到:0xfffffffc,其值就是-4

3.pc

的值是目前指令的下兩條指令的位址,加上步驟2得到的-4,這恰好是第二條指令step1的位址。各位不要被被反彙編代碼中的“b

0x4”給迷惑了,香港虛拟主機,它可不是說跳到絕對位址0x4處執行,絕對位址得像上述3個步驟那樣計算。您可以看到b跳轉指令是依賴于目前pc寄存器的值的,這個特

性使得使用b指令的程式不依賴于代碼存儲的位置——即不管我們連接配接指令中“--Ttext”為何,都可正确運作。

//一堆廢話

再看看第二條指令ldr pc,=step2:從反彙編碼“ldr pc,[pc,#0]”可以看出,這條指令從記憶體中某個位置讀出資料,并賦給pc寄存器。這個位置的位址是目前pc寄存器的值加上偏移值0,其中存放的值依賴于連接配接指令中的“--Ttext”選項。

行這條指令後,對于ttt.s,pc=0x00000008;對于ttt2.s,pc=0x30000008。于是執行第三條指令“b

step2”時,它的絕對位址就不同了:對于ttt.s,絕對位址為0x00000008;對于ttt.s,絕對位址為0x30000008。

ttt2.s上電後存放的位置也是0,但是它連接配接的位址是0x30000000。

我們以後會經常用到“存儲位址和連接配接位址不同”(術語上稱為加載時域和運作時域)的特性:

大多機器上電時是從位址0開始運作的,但是從位址0運作程式在性能方面總有很多限制,是以一般在開始的時候,使用與位置無關的指令将程式本身複制到它的連接配接位址處,然後使用向pc寄存器指派的方法跳到連接配接位址開始的記憶體上去執行剩下的代碼。

arm-linux-ld指令中選項“-Ttext”也可以使用選項“-Tfilexxx”來代替,在檔案filexxx中,香港虛拟主機,我們可以寫出更複雜的參數來使用arm-linux-ld指令