<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 說(shuō)說(shuō)ARM匯編的LDR偽指令

          說(shuō)說(shuō)ARM匯編的LDR偽指令

          作者: 時(shí)間:2016-11-21 來(lái)源:網(wǎng)絡(luò) 收藏
          我們知道ARM CPU中有一條被廣泛使用的指令LDR,它主要是用來(lái)從存儲(chǔ)器(確切地說(shuō)是地址空間)中裝載數(shù)據(jù)到通用寄存器。但不論是ARMASM還是GNU ARM AS,都提供了一條與之同名的偽指令LDR,而在實(shí)際中使用該偽指令的情況也較多,那他們有什么不同呢?下面我談?wù)勎业睦斫狻?p>
          由于我使用GNU工具鏈,所以以下的內(nèi)容都以GNU AS的ARM語(yǔ)法為準(zhǔn)。

          LDR偽指令的語(yǔ)法形式如下:
          LDR , =

          這個(gè)常量表達(dá)式中可以包含Label(在ARM匯編中Label會(huì)在連接時(shí)解釋為一個(gè)常數(shù)),且其中的常數(shù)前不加#符號(hào)。

          范例demo.s:

          本文引用地址:http://www.ex-cimer.com/article/201611/319128.htm
          .equ STACK_BASE, 0x0c002000
          .equ STACK_SIZE, 0x00001000

          .text
          ldr sp, = STACK_BASE
          ldr sl, = STACK_BASE - STACK_SIZE
          ldr pc, = entry

          這是一個(gè)合法的匯編文件,它把堆?;吩O(shè)為0x0c002000,棧限設(shè)為0x0c001000,然后跳到entry所標(biāo)識(shí)的C程序中執(zhí)行。

          下面我們假設(shè)符號(hào)“entry”的地址為0x0c000000。

          我們?nèi)绻焉厦娲a寫成:
          .text
          mov sp, #0x0c002000
          mov sl, #0x0c001000
          mov pc, #0x0c000000

          匯編器會(huì)報(bào)錯(cuò):
          demo.s: Assembler messages:
          demo.s:2: Error: invalid constant -- `mov sp,#0x0c002000
          demo.s:3: Error: invalid constant -- `mov sl,#0x0c001000

          說(shuō)起這個(gè)錯(cuò)誤的原因可就話長(zhǎng)了,簡(jiǎn)而言之是因?yàn)镽ISC有一個(gè)重要的概念就是所有指令等長(zhǎng)。在ARM指令集中,所有指令長(zhǎng)度為4字節(jié)(Thumb指令是2字節(jié))。那問(wèn)題就來(lái)了,4字節(jié)是不可能同時(shí)存的下指令控制碼和32位立即數(shù)的,那么我要把一個(gè)32位立即數(shù)(比如一個(gè)32位地址值)傳送給寄存器該怎么辦?

          RISC CPU提供一個(gè)通用的方法就是把地址值作為數(shù)據(jù)而不是代碼,從存儲(chǔ)器中相應(yīng)的位置讀入到寄存器中,待會(huì)我們會(huì)看到這樣的例子。

          此外ARM還提供另一種方案。由于傳送類指令的指令控制碼部分(cond, opcode, S, Rd, Rn域)占去了20個(gè)字節(jié),那能提供給立即數(shù)的就只剩12個(gè)位了。

          ARM并未使用這12個(gè)位來(lái)直接存一個(gè)12位立即數(shù),而是使用了類似有效數(shù)字一樣的概念,只存8個(gè)字節(jié)的有效位和一個(gè)4位的位偏移量(偏移單位為2)。這個(gè)東西在ARM被叫做術(shù)語(yǔ)immed_8,有興趣的人可以找資料了解一下,到處都有介紹。

          可以看出ARM的這個(gè)方法能直接使用的立即數(shù)是相當(dāng)有限的,像0xfffffff0這樣的數(shù)顯然無(wú)法支持。別著急,ARM的傳送類指令中還有一個(gè)MVN指令可以解決該問(wèn)題。顯然0x0000000f是一個(gè)有效立即數(shù),MVN會(huì)先將其取反再傳送,這樣有效立即數(shù)的范圍又?jǐn)U充了一倍。

          可就算如此仍有大量的32位立即數(shù)是無(wú)效的,比如上面那個(gè)例子中的0x0c002000和0x0c001000。面對(duì)這種問(wèn)題一是使用RISC的通用方法,二是分次載入。

          比如可以這樣載入0x0c002000:
          .text
          mov sp, #0x0c000000
          add sp, sp, #0x00002000
          或者:
          .text
          mov sp, #0x0c000000
          orr sp, sp, #0x00002000

          感覺(jué)很狡猾是吧,呵呵。但是要注意它和方法一的一大區(qū)別:需要多條指令。那么在一些對(duì)指令數(shù)目有限制的場(chǎng)合就無(wú)法使用它,比如異常向量表處要做長(zhǎng)跳轉(zhuǎn)(超過(guò)±32MB)的話就只能用方法一;還有就是在同步事務(wù)中該操作不是原子的,因此可能需要加鎖。

          扯了這么多再回到LDR偽指令上來(lái)。顯然上面的內(nèi)容是復(fù)雜繁瑣的,如果然程序員在寫程序的時(shí)候還要考慮某個(gè)數(shù)是不是immed_8一定超級(jí)麻煩,因此為了減輕程序員的負(fù)擔(dān)才引入了LDR偽指令。

          你一定很好奇第一段代碼demo.s被GNU AS變成了什么,好,讓我們?cè)贚inux環(huán)境下執(zhí)行下面的命令:
          arm-elf-as -o demo.o demo.s
          arm-elf-objdump -D demo.o

          結(jié)果:
          demo.o: file format elf32-littlearm

          Disassembly of section .text:

          00000000 <.text>:
          0: e59fd004 ldr sp, [pc, #4] ; c <.text+0xc>
          4: e59fa004 ldr sl, [pc, #4] ; 10 <.text+0x10>
          8: e59ff004 ldr pc, [pc, #4] ; 14 <.text+0x14>
          c: 0c002000 stceq 0, cr2, [r0]
          10: 0c001000 stceq 0, cr1, [r0]
          14: 00000000 andeq r0, r0, r0
          Disassembly of section .data:


          由于entry還沒(méi)連上目標(biāo)地址,objdump反匯編會(huì)認(rèn)為是0,我們先不管它。另外兩條LDR偽指令變成了實(shí)際的LDR指令!但目標(biāo)很奇怪,都是[pc, #4]。那好我們看看[pc, #4]是什么。

          我們知道pc中存放的是當(dāng)前指令的下下條指令的位置,也就是. + 8。那么上面的第一條指令ldr sp, [pc, #4]中的pc就是0x8,pc + 4就是0xc,而[0xc]的內(nèi)容正是0x0c002000;同理,第二條ldr指令也是如此。顯然這里L(fēng)DR偽指令采用的是RISC通用的方法。

          另外要說(shuō)的是,如果LDR的是一個(gè)immed_8或者immed_8的反碼數(shù),則會(huì)直接被解釋成mov或mvn指令。如ldr pc, = 0x0c000000會(huì)被解釋成mov pc, 0x0c000000。

          最后一點(diǎn)補(bǔ)充,我發(fā)現(xiàn)arm-elf-gcc通常都用累加法。如C語(yǔ)句中的i = 0x100ffc04;會(huì)變成類似于以下的語(yǔ)句:
          mov r0, #0x10000004
          add r0, r0, #0x000ff000
          add r0, r0, #0x00000c00
          ...
          原因不詳。

          添加的內(nèi)容:

          1 指令LDR


          應(yīng)用舉例:


          u LDR R0, [R1, #4] ;將內(nèi)存單元R1+4中的字讀取到R0寄存器


          其中,R1為基址,#4為偏移地址,R0為目標(biāo)地址。注意,此時(shí)不更新R1。


          u LDR R0, [R1, #-4] ;將內(nèi)存單元R1-4中的字讀取到R0寄存器


          u LDR R0, [R1, #4]! ;將內(nèi)存單元R1+4中的字讀取到R0寄存器。同時(shí)更新R1,R1=R1+4。


          u LDR R0, [R1], #4 ;將地址為R1的內(nèi)存單元數(shù)據(jù)讀取到R0寄存器,然后R1=R1+4。


          2 偽指令LDR


          ARM中的偽指令不是真正的ARM指令或者Thumb指令,這些偽指令在匯編編譯器對(duì)源程序進(jìn)行匯編處理時(shí),被替換為相應(yīng)的ARM或者Thumb指令(序列)。


          LDR偽指令將一個(gè)32位的常數(shù)或者一個(gè)地址值讀取到寄存器中。


          語(yǔ)法格式:


          LDR{cond} register, =[expr | label-expr]


          其中,register為目標(biāo)寄存器


          expr為32位的常量。編譯器將根據(jù)expr的取值情況,如下處理LDR偽指令:


          u 當(dāng)expr所表示的地址值沒(méi)有超過(guò)MOV或MVN指令中的地址取值范圍時(shí),編譯器用合適的MOV或者M(jìn)VN指令代替LDR偽指令。


          應(yīng)用舉例:


          將0xFF0讀取到R1中


          LDR R1, =0xFF0


          匯編后得到:


          MOV R1, 0xFF0



          u 當(dāng)expr表示的地址值超過(guò)了MOV或者M(jìn)VN指令中的地址的取值范圍(第二操作數(shù)的取值范圍)時(shí),編譯器將該常數(shù)放在數(shù)據(jù)緩沖區(qū)中,同時(shí)用一條基于PC的LDR指令讀取該常數(shù)。


          LDR R1,=0xFFF


          匯編后得到:


          LDR R1, [PC, OFFSET_TO_LPOOL]



          LPOOL DCD 0xFFF


          關(guān)于label-expr的介紹我不是很理解。不理解其中關(guān)于“連接重定位偽操作”。(P144)


          聲明:本文為我在學(xué)習(xí)杜春雷編著的《ARM體系結(jié)構(gòu)與編程》時(shí)做的總結(jié)筆記,文中摘錄了書中的很多內(nèi)容。

          補(bǔ)充2:

          原文地址:http://hi.baidu.com/andylgh/blog/item/17dbdc1f7d102a62f624e4dc.html

          gnu下的arm匯編偽指令:.word說(shuō)明
          2007-04-08 20:14

          說(shuō)說(shuō)這個(gè).word的作用。

          word expression就是在當(dāng)前位置放一個(gè)word型的值,這個(gè)值就是expression
          舉例來(lái)說(shuō),
          _rWTCON:
          .word 0x15300000
          就是在當(dāng)前地址,即_rWTCON處放一個(gè)值0x15300000

          翻譯成intel的匯編語(yǔ)句就是:
          _rWTCON dw 0x15300000

          例如:

          ldr r1, _rWTCON

          _rWTCON:
          .word 0x15300000
          不是把地址0x1530 0000 上的內(nèi)容傳遞到r1,是把地址_rWTCON上的內(nèi)容放到r1,而地址_rWTCON上的內(nèi)容是0x15300000。實(shí)際上就是把r1設(shè)置為0x15300000




          關(guān)鍵詞: ARM匯編LDR偽指

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();