ARM 彙編的mov操作立即數的疑問

ARM 彙編的mov操作立即數的疑問
1. 因爲對arm彙編有些指令還不能理解,特別是一些相似功能指令間的區別。偶然在網上搜到“faq ARM assembly”,其中描述的幾個問題還是值得好好研究一下。

2. 慢慢的發現自己也不再害怕英文的文檔了,耐心看至少也能懂個大概。大批經典的文章和書籍都是en文的,所以經常看英文文檔是一個非常好的習慣。看看GNU的一些reference manual,哪個不是經典而又值得學習並研究的!

3. 學習別人寫文檔的風格,重點要注意條理性。能夠把一個問題、一個知識點闡述清晰明白,這不僅需要對知識點的掌握,還需要良好的語言表達能力以及對文章細心、整潔的排版。我想,這些細節才能夠體現一個人的水平和他所能到達的高度。


-----------------------------------------------------------------------------------------------------------------------------------------------------------------------


本篇來看一下mov這個指令,相關指令 ldr

Question on MOV
Does the instruction “Mov” have indirect addressing?
Answer. No, e.g. you cannot use mov r1,[r2] 
“MOV loads a value into the destination register, from another register, a shifted register, or an immediate 8-bit value.”

Examples:
  MOV R0, R1 if R1 has 0x00001234, after this ,R1=R2=0x00001234
  MOV R0, #0x12; after this R0 has #0x12
  MOV R0, #300is wrong the value should be less than 255
  MOV R0, 200; is wrong, # is missing “mov R0,#200: is correct

Note: the immediate value must be prefixed by #

從上面的描述可以看出,mov的作用有兩個:

1. 在寄存器之間傳遞值。

2. 給寄存器傳遞一個立即數,此時需要用“#”來修飾立即數,並且立即數爲8位的,其值不能超過255.

但是在vivi中的head.S裏,有許多類似 mov r1, #0x53000000 的語句:


簡單的寫幾句彙編,測試一下:

.global _start 
.align 0 
_start: 
        mov r1, #0x12 
        mov r2, #300 
        mov r3, #0x53000000

.end


這樣,編譯並沒有報錯。

反彙編後如下

8000: e3a01012 mov r1, #18 ; 0x12 
8004: e3a02f4b mov r2, #300 ; 0x12c 
8008: e3a03453 mov r3, #1392508928 ; 0x53000000


這是爲什麼呢?爲什麼用mov也可以?看別的彙編裏都是寫ldr r1, =0x53000000


將程序改一下:

.global _start 
.align 0 
_start: 
        mov r1, #0x12 
        mov r2, #300 
        ldr r3, =0x53000000 
.end



彙編也沒有報錯,反彙編可看到如下三句話:

8000: e3a01012 mov r1, #18 ; 0x12 
8004: e3a02f4b mov r2, #300 ; 0x12c 
8008: e3a03453 mov r3, #1392508928 ; 0x53000000



發現,ldr r3, =0x53000000 被經過彙編之後,實際上變爲了 mov r3, #0x53000000 。可見,此處ldr相當於一個僞指令。



關於ldr,下面這段說的很清楚。在分析彙編時,很重要一點就是分清“地址” 和“地址裏的內容”,對這個能熟練把握了,相信能對C語言中的指針有更深的理解。

Question on the use of LDR,ADR

Are there any difference between statement 1,2,3 in the following program?

Data1p DCD 0, 0 ;just happen the address is at 0x40000000
;DCD (reserve a 32-bit word)is a pseudo instruction to
;allocate a memory location for this data.
align
align
:
:
Statment1 LDR R0, =Data1p ; Put the address Data1p into R0
Statment2 ADR R0, Data1p ; Put the address Data1p into R0
Statment3 LDR R0, =0x40000000 ; Put the value0x40000000 into R0,
;just happen it is the address of Data1p

Answer: They are all the same. Every statement will generate the same result.Such that the address, not the data content, will be saved into R0. Forexample, the value in R0 is 0x40000000.


到這裏,相信一定對“mov”和“ldr”兩個產生了一些疑惑。(注:此處的ldr指的是僞指令pseudo-instruction,而不是內存到寄存器傳遞值的instruction

下面的這段對兩者的區別作了很全面的分析。

Question on differences between LDR and MOV
What is the difference between MOV and LDR, they seem to have the same function of saving information into registers?

Answer part 1: How different are they?
Note: “#” for mov, “=” for ldr. To define an immediate value
MOV can only move an 8-bit value (0x00->0xff=255) into a register while LDR can move a 32-bit value into a register. The immediate value is prefixed by different characters in mov and ldr: “#” formov, “=” for ldr. E.g.


Mov r1,#255 ; ok, 255 is the biggest number you can mov
Mov r1,255 ; is wrong , missing #
Mov r1,#256 ; is wrong, the number is bigger than 255
Mov r1,#0x12340000 ; is wrong, the number is bigger than 255
Ldr r1,=255; you can do this,
Ldr r1,=256; you can do this,
Ldr r1,=0x12340000; you can do this,


1. MOV can run faster than LDR.
2. LDR can move a data from a memory address to a register, MOV can only i) move data between two registers or ii) save a 8-bit immediate value to a register. e.g.

value1 DCD 0; this define an integer variable “value1” with address “=value1”

:

;A standard pair of statements for moving a data into a register
Ldr r0,=value1 ; 1) save the address of the variable value1 in r0
Ldr r1,[r0] ;2)use r0 as the address (pointer) to get value1 to r1

r1 Note: Mov cannot be used to achieve the same result, because mov,[r0] is not allowed

Answer part 2 : How similar are they?.
MOV is a real instruction, LDR is a pseudo instruction. If the immediate value is small, the assembler will use “mov” to implement it , otherwise it uses a literal pool to achieve the result.
e.g.
ldr r0,=14; the immediate value 14 <255, so it will be implemented using mov r0,#14, (see the use of # and = ) but if the immediate value is large than 255, e.g.
The assembler will generate code to place the constant 0x55555555 ldr r0,=0x55555555; for a large immediate value “mov” does work.in a nearby table in the code area. Then it uses an instruction to load a data from that table pointed by the program counter and an offset to fill up r0. The reason is because there is no way to fit a 2-bit data into a 32-instruction, and ARM design always want to make sure instructions are 32-bit. Details can be found at 
http://www.keil.com/support/man/docs/armasm/armasm_chdcegci.htm

see also the directive “LTORG” for how to setup the table. Usually it is placed at the near by code area. You don’t need to worry too much because everything is automatic; you only need to place “LTORG” at the end of the code area as shown in the example at Keil.


但是我在看完上面這段話之後還是存在疑問:爲什麼”mov r3, #0x53000000”是可行的呢?



http://www.keil.com/support/man/docs/armasm/armasm_cihcdbca.htm

這個網頁上對mov做了一些說明,截取有關立即數的部分如下:


Syntax
MOV{cond} Rd, #imm16
where:
imm16
is any value in the range 0-65535.

可以看到,這裏說 立即數是16位的。


看到這裏,確實把自己弄糊塗了。理清一下:

第一個說imm8位是在網絡上搜的一分資料,沒有什麼權威性,其可信程度也值得懷疑。

第二個是keil官司方網站裏關於arm彙編的說明。


另外,在《arm體系結構與編程》這本書裏,並沒有說立即數的具體範圍,在26頁有一句:

mov r0, #0xfc0

明顯立即數大於255了。

144頁有提到,“ldr僞指令讀取的數據超過mov操作範圍”。這說明mov可操作的立即數是有一定範圍的,且比ldr小。


再來分析一下立即數的產生,其尋址方式是這樣的:

11         8 7                              0 
 +----------+-------------------------------+
 | Rotate   |          Imm                  |
 +----------+-------------------------------+
[7:0] Unsigned 8 bit immediate value
[11:8] Shift applied to Imm

The immediate operand rotate field is a 4 bit unsigned integer which specifies a shift operation on the 8 bit immediate value. This value is zero extended to 32 bits, and then subject to a rotate right by twice the value in the rotate field. This enables many common constants to be generated, for example all powers of 2


1. 取低
8位,先用0擴展爲32位數
2. 將所得
32位數循環右移 2Rotate位,Rotate[11:8]

來分析一句:mov r2, #300。反彙編如下:

8004: e3a02f4b mov r2, #300 ; 0x12c

立即數是直接放在指令內部的。

1. 取其低8位:0x4b

2. 擴展爲32位:0x0000 004b

3.   2*Rotate = 2*15 = 30

4.   循環右移30位(相當於左移2位)。即0100 1011 左移2位,得到0001 0010 1100 ,即0x12c,十進制等於300

對於0x53000000的計算方法也是相同的。 mov r1, #0x53000000 這樣寫確實是可行的。

----------------------------------------------------------------------------------------------------------------------------------------------------

總結:對於mov 操作立即數時的操作範圍,現在還是不確定。但經過這麼多的分析以及實際寫的幾句測試代碼,至少可以說明在Linux裏,用arm-linux-as來編譯,mov是可以操作32位的立即數的,不然vivi如何編譯成功。(懷疑是否這跟實際彙編器相關。)

發佈了16 篇原創文章 · 獲贊 9 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章