LDR和ADR在使用標號表示式作為運算元的區別

2021-04-26 06:05:51 字數 2137 閱讀 3027

原文**http://hi.baidu.com/mikenoodle/blog/item/d5e95eee30cf62f3b3fb954d.html

arm彙編有ldr指令以及ldr、adr偽指令,他門都可以將標號表示式作為運算元,下面通過分析一段**以及對應的反彙編結果來說明它們的區別。

ldr     r0, _start

adr    r0, _start

ldr     r0, =_start

_start:

b _start

編譯的時候設定 ro 為 0x30000000,下面是反彙編的結果:

0x30000000: e59f0004 ldr r0, [pc, #4] ; 0xc

0x30000004: e28f0000 add r0, pc, #0 ; 0x0

0x30000008: e59f0000 ldr r0, [pc, #0] ; 0x10

0x3000000c: eafffffe b 0xc

0x30000010: 3000000c andcc r0, r0, ip

1.ldr     r0, _start

這是一條指令,從記憶體位址 _start 的位置把值讀入。

在這裡_start是乙個標號(是乙個相對程式的表示式),匯程式設計序計算相對於 pc 的偏移量,並生成相對於 pc的前索引的指令:ldr r0, [pc, #4]。執行指令後,r0 = 0xeafffffe。

ldr r0, _start是根據_start對當前pc的相對位置讀取其所在位址的值,因此可以在和_start標號的相對位置不變的情況下移動。

2.adr     r0, _start

這是一條偽指令,總是會被匯程式設計序彙編為乙個指令。匯程式設計序嘗試產生單個 add 或 sub 指令來裝載該位址。如果不能在乙個指令中構造該位址,則生成乙個錯誤,並且彙編失敗。

在這裡是取得標號_start 的位址到 r0,因為位址是相對程式的,因此adr產生依賴於位置的**,在此例中被彙編成:add r0, pc, #0。因此該**可以在和標號相對位置不變的情況下移動;

假如這段**在 0x30000000 執行,那麼 adr r0, _start 得到 r0 = 0x3000000c;如果在位址 0 執行,就是 0x0000000c 了。

通過這一點可以判斷程式在什麼地方執行。u-boot中那段relocate**就是通過adr實現當前程式是在ram中還是flash中,下面進行簡要分析。

relocate: /* 把u-boot重新定位到ram */

adr r0, _start /* r0是**的當前位置 */

/* adr偽指令,彙編器自動通過當前pc的值算出 如果執行到_start時pc的值,放到r0中:

當此段在flash中執行時r0 = _start = 0;當此段在ram中執行時_start = _text_base(在board/smdk2410/config.mk中指定的值為0x30000000,即u-boot在把**拷貝到ram中去執行的**段的開始) */

ldr r1, _text_base /* 測試判斷是從flash啟動,還是ram */

/* 此句執行的結果r1始終是0x30000000,因為此值是又編譯器指定的(ads中設定,或-d設定編譯器引數) */

cmp r0, r1 /* 比較r0和r1,除錯的時候不要執行重定位 */

3.ldr     r0, =_start

這是一條偽指令,是乙個相對程式的或外部的表示式。匯程式設計序將相對程式的標號表示式 label-expr 的值放在乙個文字池中,並生成乙個相對程式的 ldr 指令來從文字池中裝載該值,在此例中生成的指令為:ldr r0, [pc, #0],對應文字池中的位址以及值為:0x00000010: 3000000c。如果 label-expr 是乙個外部表示式,或者未包含於當前段內,則匯程式設計序在目標檔案中放置乙個鏈結程式重定位命令。鏈結程式在鏈結時生成位址。

因此取得的是標號 _start 的絕對位址,這個絕對位址(執行位址)是在連線的時候確定的。它要占用 2 個 32bit 的空間,一條是指令,另一條是文字池中存放_start 的絕對位址。因此可以看出,不管這段**將來在什麼地方執行,它的結果都是 r0 = 0x3000000c。由於ldr r0, =_start取得的是_start的絕對位址,這句**可以在_start標號的絕對位置不變的情況下移動;如果使用暫存器pc在程式中可以實現絕對轉移。

ldr和adr在使用標號表示式作為運算元的區別

arm彙編有ldr指令以及ldr adr偽指令,他門都可以將標號表示式作為運算元,下面通過分析一段 以及對應的反彙編結果來說明它們的區別。ldr r0,start adr r0,start ldr r0,start start b start 編譯的時候設定 ro 為 0x30000000,下面是反...

ldr和adr在使用標號表示式作為運算元的區別

arm彙編有ldr指令以及ldr adr偽指令,他門都可以將標號表示式作為運算元,下面通過分析一段 以及對應的反彙編結果來說明它們的區別。ldr r0,start adr r0,start ldr r0,start start b start 編譯的時候設定 ro 為 0x30000000,下面是反...

賦值表示式和逗號表示式

c 把賦值運算子連線而成的式子叫做賦值表示式,例如 a b a b c a 3 等。賦值運算子是乙個雙目運算子,必須兩個參與運算的值,其左邊的值叫做 l value 通常是變數或賦值表示式,常量和常變數不可以作為賦值表示式的左值。賦值運算子右端的值叫做 r value 通常乙個常量 變數或表示式。c...