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

2021-01-15 電子產品世界
1. 因為對arm彙編有些指令還不能理解,特別是一些相似功能指令間的區別。偶然在網上搜到「faq ARM assembly」,其中描述的幾個問題還是值得好好研究一下。

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

本文引用地址:http://www.eepw.com.cn/article/201611/317882.htm

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 0x01234, after this ,R1=R2=0x01234
MOV R0, #0x12; after this R0 has #0x12
MOV R0, #300; is 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, #0x53 的語句:

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

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

.end

這樣,編譯並沒有報錯。

反彙編後如下

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

這是為什麼呢?為什麼用mov也可以?看別的彙編裡都是寫ldr r1, =0x53

將程序改一下:

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

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

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

發現,ldr r3, =0x53 被經過彙編之後,實際上變為了 mov r3, #0x53 。可見,此處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 0x40
;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, =0x40 ; Put the value0x40 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. For example, the value in R0 is 0x40.

到這裡,相信一定對「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,#0x12340 ; is wrong, the number is bigger than 255
Ldr r1,=255; you can do this,
Ldr r1,=256; you can do this,
Ldr r1,=0x12340; 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 0x55 ldr r0,=0x55; 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 athttp://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, #0x53」是可行的呢?

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位的。

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

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

第二個是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位數循環右移 2*Rotate位,Rotate為[11:8]

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

8004: e3a02f4b mov r2, #300 ; 0x12c

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

1. 取其低8位:0x4b

2. 擴展為32位:0x0 004b

3. 2*Rotate = 2*15 = 30

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

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

-

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

相關焦點

  • ARM彙編中的立即數
    -我是無辜的分割線--本文引用地址:http://www.eepw.com.cn/article/201611/317884.htm在 mov r2,#0xffb 這句中,不是MOV的用法出錯,而是立即數用法出錯。
  • arm 微學術 架構_arm彙編 - CSDN
    3、學ARM彙編要學的內容    彙編指令    偽指令    偽操作 /** 代碼演示 - 最簡單的彙編程序 **/.text @代表接下來的內容放入代碼段.code 32 @代表接下來的內容翻譯成ARM指令集.global start @聲明全局start標號start:mov r0, #10 @
  • ARM彙編編程基礎之四-ARM彙編偽操作
    掌握了基本的ARM彙編指令後,要寫出簡單的ARM彙編程序,還必須要掌握基本的ARM彙編偽操作(directive)。現在我們來看一個簡單的彙編程序,該程序調用子程序完成了加法操作。第6、8、10行的START、LOOP、ADD_SUB是標號,最經常用於跳轉指令B和BL,由於彙編語法要求的緣故,標號必須頂格寫(即:不能在行首有空格),否則編譯器會報錯。與之對應的是,彙編指令一定不能頂格寫。很明顯分號(;)在彙編程序中是注釋符號,相當於C語言的//號。除此之外,當然大家注意到了第3、4、5、13行是我們沒學習過的符號,其實它們就是本文的重點——ARM彙編偽操作。
  • 彙編:將兩位十進位數轉化為十六進位數
    這個是一個把兩位十進位數轉化為十六進位數的的彙編語言程序 考試題目a try again (yes "y",no "n"): ,$tital4 db welcome to use this program It is made by WQ 2012/5/17,$kongzi db 0dh,0ah,$data endscode segment assume cs:code,ds:datastart: mov
  • ARM 浮點運算詳解
    當使用軟浮點工具鏈編譯浮點操作時,編譯器會用內聯的浮點庫替換掉浮點操作,使得生成的機器碼完全不含浮點指令,但是又能夠完成正確的浮點操作。三:浮點協處理器:在較新版本的ARM中,可以添加協處理器。 一些ARM CPU為了更好的處理浮點計算的需要,添加了浮點協處理器。並定義了浮點指令集。
  • ARM中ADS環境下C語言和彙編語言混合編程及示例
    但對於一寫硬體上的操作,很多地方還是要用到彙編語言,例如硬體系統的初始化中的CPU 狀態的設定,中斷的使能,主頻的設定,RAM控制參數等。另外在一些對性能非常敏感的代碼塊,基於彙編與機器碼一一對應的關係,這時不能依靠C編譯器的生成代碼,而要手工編寫彙編,從而達到優化的目的。彙編語言是和CPU的指令集緊密相連的,作為涉及底層的嵌入式系統開發,熟練對應彙編語言的使用也是必須的。
  • ARM學習筆記--GPIO接口
    led_on_elf *.oled_on.S生成led_on.bin第一行做彙編第二行做連接,指定代碼段起始地址為0x00000000第三行把ELF格式轉為二進位格式clean用於清除編譯生成的文件2、使用c語言代碼點亮LED彙編可讀性比C差,我們用C來實現@**
  • ARM指令學習筆記
    有了個簡單了解之後,開始投入到了arm指令的學習。參考"arm百度百科","NDS百度百科"本文引用地址:http://www.eepw.com.cn/article/201611/316807.htm接下來就是對arm指令的學習。因為有過前面8086指令的學習,並且也寫過像高精度計算這樣的彙編程序,看arm指心裏面老在比較這兩套指令。
  • ARM彙編程序設計之:ARM彙編器所支持的偽操作
    表10.1 ARM源程序文件名後綴程序文件名彙編*.S引入文件*.INCC程序*.C頭文件*.H在一個項目中,至少要有一個彙編源文件,可以有多個彙編源文件或多個C程序,或者C程序文件和彙編文件兩者的組合。
  • ARM 一些特殊符號
    arm彙編程序中的符號 在arm彙編語言中,符號(symbols)可以代表地址(addresse)、變量(variables)和數字常量(numeric constants)。當符號代表地址時,又稱為標號(lable)。
  • ARM彙編程序基本知識
    1.彙編程序的基本組成本文引用地址:http://www.eepw.com.cn/article/201611/322725.htmARM彙編語言程序中,程序是以程序段為單位組織代碼的。段是相對獨立的指令或者代碼序列,擁有特定的名稱。
  • ARM彙編程序設計之:彙編語言文件格式
    本文引用地址:http://www.eepw.com.cn/article/257046.htm10.3.1ARM彙編語言語句格式ARM(Thumb)彙編語法語句格式如下所示。在指令和偽指令中通常為標號;在一些偽操作中符號可能是變量或常數。詳見ARM偽操作一節。在書寫中,符號必須從一行的行頭開始,前面不能包含空格或制表符tab。②instructionARM或Thumb指令。③directive偽操作。詳見ARM偽操作一節。
  • 彙編電子鐘的設計
    mini_second,#00h ;清零 ­ mov second,#00h ­ mov minute,#00h ­ mov clock,#00h ­ mov tmod,#01h ;置工作方式1,開定時器 ­ mov th0,#3ch ­ mov tl0,#0b0h ­ setb ea ­
  • 第1天-ARM彙編指令LSL/LSR/ASL/ASR
    你還可以使用桶式移位器影響在 LDR/STR 操作中的變址值。譯註:移位操作在 ARM 指令集中不作為單獨的指令使用,它是指令格式中是一個欄位,在彙編語言中表示為指令中的選項。如果數據處理指令的第二個操作數或者單一數據傳送指令中的變址是寄存器,則可以對它進行各種移位操作。
  • 關於ARM彙編裡的特殊符號
    先前企圖全部靠自己寫一個bootloader,結果嘗試了下,花了4天時間查各種技術資料,寫了個startup.s文件出來,寫的過程中才發現,原來還有很多問題是我基本上不知道的,比如說如何進行ARM的位操作、如何將堆棧設置到RAM中、UART的波特率計算方法等問題。在邊寫邊查資料的過程中,我又發現了別人的一些程序我看不懂。。。
  • 用AVR彙編語言實現AES及其優化
    本文在研究分析AES加密算法原理的基礎上,著重說明算法的實現步驟,並結合AVR彙編語言完整地實現AES加密和解密。根據AES原理,提出幾種列變化的優化算法,並根據實驗結果分析和比較它們的優缺點。本文以128為例,介紹算法的基本原理;結合AVR彙編語言,實現高級數據加密算法AES。1 AES加密、解密算法原理和AVR實現AES是分組密鑰,算法輸入128位數據,密鑰長度也是128位。用Nr表示對一個數據分組加密的輪數(加密輪數與密鑰長度的關係如表1所列)。
  • ARM彙編特殊符號 彙編符號引用
    280位元組內存並初始化[|] ----IF ELSE ENDIF----條件編譯,有選擇的確定需要編譯的代碼IF,ELSE,ENDIF,可以嵌套使用----IF 邏輯表達式指令或偽指令ELSE指令或偽指令ENDIF另外還有符號: $如果在串變量前有一個$,則在彙編
  • ARM彙編偽指令(1)
    ARM彙編程序由機器指令、偽指令和宏指令組成。本文引用地址:http://www.eepw.com.cn/article/201611/319390.htm1,符號定義偽指令符號定義偽指令用於定義ARM彙編程序的變量、對變量進行賦值、定義寄存器名稱。
  • ARM指令集和常用寄存器
    BX Rm 帶狀態切換的跳轉指令 PC4)ARM協處理器指令1,CDP 通知ARM協處理器執行特定的操作2,LDC 從某一連續的內存單元將數據讀取到協處理器的寄存器中LDC p5, c2, [R2, #4] //讀取R2+4指向內存單元的數據傳送到協處理器p5的c2寄存器中3,STC 將協處理器的寄存器數據寫入到某一連續的內存單元中
  • AVR彙編初探之二《AVR的指令與彙編系統》
    學單片機那麼久了,感覺想要深入,還得看彙編語言,至少得了解單片機內部結構。本文引用地址:http://www.eepw.com.cn/article/201701/342697.htm  下面就以ATmega16為例,介紹一下AVR單片機結構和彙編語言。  AVR單片機的CPU內核結構