版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、轉(zhuǎn)自:ARM GCC 內(nèi)嵌(inline)匯編手冊(cè)關(guān)于這篇文檔這篇文章是本人為方便各位業(yè)界同仁而翻譯,方便大家開發(fā)底層代碼使用,轉(zhuǎn)載請(qǐng)注明出處,謝謝。要是你E文功底好,本人還是建議閱讀E文版的。http:/www.ethernut.de/en/documents/arm-inline-asm.html對(duì)于基于ARM的RISC處理器,GNU C編譯器提供了在C代碼中內(nèi)嵌匯編的功能。這種非??岬奶匦蕴峁┝薈代碼沒有的功能,比如手動(dòng)優(yōu)化軟件關(guān)鍵部分的代碼、使用相關(guān)的處理器指令。這里設(shè)想了讀者是熟練編寫ARM匯編程序讀者,因?yàn)樵撈臋n不是ARM匯編手冊(cè)。同樣也不是C語言手冊(cè)。這篇文檔假設(shè)使用的是GCC
2、 4 的版本,但是對(duì)于早期的版本也有效。GCC asm 聲明讓我們以一個(gè)簡(jiǎn)單的例子開始。就像C中的聲明一樣,下面的聲明代碼可能出現(xiàn)在你的代碼中。/* NOP 例子 */asm("mov r0,r0"該語句的作用是將r0移動(dòng)到r0中。換句話講他并不干任何事。典型的就是NOP指令,作用就是短時(shí)的延時(shí)。請(qǐng)接著閱讀和學(xué)習(xí)這篇文檔,因?yàn)樵撀暶鞑⒉幌衲阆胂蟮暮推渌腃語句一樣。內(nèi)嵌匯編使用匯編指令就像在純匯編程序中使用的方法一樣??梢栽谝粋€(gè)asm聲明中寫多個(gè)匯編指令。但是為了增加程序的可讀性,最好將每一個(gè)匯編指令單獨(dú)放一行。asm("mov r0, r0nt"&qu
3、ot;mov r0, r0nt""mov r0, r0nt""mov r0, r0"換行符和制表符的使用可以使得指令列表看起來變得美觀。你第一次看起來可能有點(diǎn)怪異,但是當(dāng)C編譯器編譯C語句的是候,它就是按照上面(換行和制表)生成匯編的。到目前為止,匯編指令和你寫的純匯編程序中的代碼沒什么區(qū)別。但是對(duì)比其它的C聲明,asm的常量和寄存器的處理是不一樣的。通用的內(nèi)嵌匯編模版是這樣的。asm(code : output operand list : input operand list : clobber list;匯編和C語句這間的聯(lián)系是通過上面a
4、sm聲明中可選的output operand list和input operand list。Clobber list后面再講。下面是將C語言的一個(gè)整型變量傳遞給匯編,邏輯左移一位后在傳遞給C語言的另外一個(gè)整型變量。/* Rotating bits example */asm("mov %result, %value, ror #1" : result "=r" (y : value "r" (x;每一個(gè)asm語句被冒號(hào)(:)分成了四個(gè)部分。 匯編指令放在第一部分中的“”中間。"mov %result, %value, ro
5、r #1" 接下來是冒號(hào)后的可選擇的output operand list,每一個(gè)條目是由一對(duì)(方括號(hào))和被他包括的符號(hào)名組成,它后面跟著限制性字符串,再后面是圓括號(hào)和它括著的C變量。這個(gè)例子中只有一個(gè)條目。result "=r" (y 接著冒號(hào)后面是輸入操作符列表,它的語法和輸入操作列表一樣value "r" (x 破壞符列表,在本例中沒有使用就像上面的NOP例子,asm聲明的4個(gè)部分中,只要最尾部沒有使用的部分都可以省略。但是有有一點(diǎn)要注意的是,上面的4個(gè)部分中只要后面的還要使用,前面的部分沒有使用也不能省略,必須空但是保留冒號(hào)。下面的一個(gè)
6、例子就是設(shè)置ARM Soc的CPSR寄存器,它有input但是沒有output operand。 asm("msr cpsr,%ps" : : ps"r"(status即使匯編代碼沒有使用,代碼部分也要保留空字符串。下面的例子使用了一個(gè)特別的破壞符,目的就是告訴編譯器內(nèi)存被修改過了。這里的破壞符在下面的優(yōu)化部分在講解。 asm("":"memory"為了增加代碼的可讀性,你可以使用換行,空格,還有C風(fēng)格的注釋。asm("mov %result, %value, ror #1": result&q
7、uot;=r" (y /* Rotation result. */: value"r" (x /* Rotated value. */: /* No clobbers */;在代碼部分%后面跟著的是后面兩個(gè)部分方括號(hào)中的符號(hào),它指的是相同符號(hào)操作列表中的一個(gè)條目。%result表示第二部分的C變量y,%value表示三部分的C變量x;符號(hào)操作符的名字使用了獨(dú)立的命名空間。這就意味著它使用的是其他的符號(hào)表。簡(jiǎn)單一點(diǎn)就是說你不必關(guān)心使用的符號(hào)名在C代碼中已經(jīng)使用了。在早期的C代碼中,循環(huán)移位的例子必須要這么寫:asm("mov %0, %1, ror #1&
8、quot; : "=r" (result : "r" (value在匯編代碼中操作數(shù)的引用使用的是%后面跟一個(gè)數(shù)字,%1代表第一個(gè)操作數(shù),%2代碼第二個(gè)操作數(shù),往后的類推。這個(gè)方法目前最新的編譯器還是支持的。但是它不便于維護(hù)代碼。試想一下,你寫了大量的匯編指令的代碼,要是你想插入一個(gè)操作數(shù),那么你就不得不從新修改操作數(shù)編號(hào)。優(yōu)化C代碼有兩種情況決定了你必須使用匯編。1st,C限制了你更加貼近底層操作硬件,比如,C中沒有直接修改程序狀態(tài)寄存器(PSR)的聲明。2nd就是要寫出更加優(yōu)化的代碼。毫無疑問GNU C代碼優(yōu)化器做的很好,但是他的結(jié)果和我們手工寫的匯
9、編代碼相差很遠(yuǎn)。這一部分有一點(diǎn)很重要,也是被別人忽視最多的就是:我們?cè)贑代碼中通過內(nèi)嵌匯編指令添加的匯編代碼,也是要被C編譯器的優(yōu)化器處理的。讓我們下面做個(gè)試驗(yàn)來看看吧。下面是代碼實(shí)例。bigtreejust:/embedded/basic-C$ arm-linux-gcc -c test.cbigtreejust:/embedded/basic-C$ arm-linux-objdump -D test.o編譯器選擇r3作為循環(huán)移位使用。它也完全可以選擇為每一個(gè)C變量分配寄存器。Load或者store一個(gè)值并不顯式的進(jìn)行。下面是其它編譯器的編譯結(jié)果。E420A0E1 mov r2, r4, r
10、or #1 y, x編譯器為每一個(gè)操作數(shù)選擇一個(gè)相應(yīng)的寄存器,將操作過的值cache到r4中,然后傳遞該值到r2中。這個(gè)過程你能理解不?有的時(shí)候這個(gè)過程變得更加糟糕。有時(shí)候編譯器甚至完全拋棄你嵌入的匯編代碼。C編譯器的這種行為,取決于代碼優(yōu)化器的策略和嵌入?yún)R編所處的上下文。如果在內(nèi)嵌匯編語句中不使用任何輸出部分,那么C代碼優(yōu)化器很有可能將該內(nèi)嵌語句完全刪除。比如NOP例子,我們可以使用它作為延時(shí)操作,但是對(duì)于編譯器認(rèn)為這影響了程序的執(zhí)行速速,認(rèn)為它是沒有任何意義的。上面的解決方法還是有的。那就是使用volatile關(guān)鍵字。它的作用就是禁止優(yōu)化器優(yōu)化。將NOP例子修改過后如下:/* NOP ex
11、ample, revised */asm volatile("mov r0, r0"下面還有更多的煩惱等著我們。一個(gè)設(shè)計(jì)精細(xì)的優(yōu)化器可能重新排列代碼??聪旅娴拇a:i+;if (j = 1x += 3;i+;優(yōu)化器肯定是要從新組織代碼的,兩個(gè)i+并沒有對(duì)if的條件產(chǎn)生影響。更進(jìn)一步的來講,i的值增加2,僅僅使用一條ARM匯編指令。因而代碼要重新組織如下:if (j = 1x += 3;i += 2;這樣節(jié)省了一條ARM指令。結(jié)果是:這些操作并沒有得到許可。這些將對(duì)你的代碼產(chǎn)生很到的影響,這將在下面介紹。下面的代碼是c乘b,其中c和b中的一個(gè)或者兩個(gè)可能會(huì)被中斷處理程序修改。
12、進(jìn)入該代碼前先禁止中斷,執(zhí)行完該代碼后再開啟中斷。asm volatile("mrs r12, cpsrnt""orr r12, r12, #0xC0nt""msr cpsr_c, r12nt" : "r12", "cc"c *= b; /* This may fail. */asm volatile("mrs r12, cpsrn""bic r12, r12, #0xC0n""msr cpsr_c, r12" : "r12&
13、quot;, "cc"但是不幸的是針對(duì)上面的代碼,優(yōu)化器決定先執(zhí)行乘法然后執(zhí)行兩個(gè)內(nèi)嵌匯編,或相反。這樣將會(huì)使得我們的代碼變得毫無意義。我們可以使用clobber list幫忙。上面例子中的clobber list如下:"r12", "cc"上面的clobber list將會(huì)將向編譯器傳達(dá)如下信息,修改了r12和程序狀態(tài)寄存器的標(biāo)志位。Btw,直接指明使用的寄存器,將有可能阻止了最好的優(yōu)化結(jié)果。通常你只要傳遞一個(gè)變量,然后讓編譯器自己選擇適合的寄存器。另外寄存器名,cc(condition registor 狀態(tài)寄存器標(biāo)志位),mem
14、ory都是在clobber list上有效的關(guān)鍵字。它用來向編譯器指明,內(nèi)嵌匯編指令改變了內(nèi)存中的值。這將強(qiáng)迫編譯器在執(zhí)行匯編代碼前存儲(chǔ)所有緩存的值,然后在執(zhí)行完匯編代碼后重新加載該值。這將保留程序的執(zhí)行順序,因?yàn)樵谑褂昧藥в衜emory clobber的asm聲明后,所有變量的內(nèi)容都是不可預(yù)測(cè)的。asm volatile("mrs r12, cpsrnt""orr r12, r12, #0xC0nt""msr cpsr_c, r12nt" : : "r12", "cc", "memo
15、ry"c *= b; /* This is safe. */asm volatile("mrs r12, cpsrn""bic r12, r12, #0xC0n""msr cpsr_c, r12" : "r12", "cc", "memory"使所有的緩存的值都無效,只是局部最優(yōu)(suboptimal)。你可以有選擇性的添加dummy operand 來人工添加依賴。asm volatile("mrs r12, cpsrnt""orr
16、r12, r12, #0xC0nt""msr cpsr_c, r12nt" : "=X" (b : "r12", "cc"c *= b; /* This is safe. */asm volatile("mrs r12上面的第一個(gè)asm試圖修改變量先b,第二個(gè)asm試圖修改c。這將保留三個(gè)語句的執(zhí)行順序,而不要使緩存的變量無效。理解優(yōu)化器對(duì)內(nèi)嵌匯編的影響很重要。如果你讀到這里還是云里霧里,最好是在看下個(gè)主題之前再把這段文章讀幾遍_。Input and output operands前面我們學(xué)到,
17、每一個(gè)input和output operand,由被方括號(hào)中的符號(hào)名,限制字符串,圓括號(hào)中的C表達(dá)式構(gòu)成。這些限制性字符串有哪些,為什么我們需要他們?你應(yīng)該知道每一條匯編指令只接受特定類型的操作數(shù)。例如:跳轉(zhuǎn)指令期望的跳轉(zhuǎn)目標(biāo)地址。不是所有的內(nèi)存地址都是有效的。因?yàn)樽詈蟮膐pcode只接受24位偏移。但矛盾的是跳轉(zhuǎn)指令和數(shù)據(jù)交換指令都希望寄存器中存儲(chǔ)的是32位的目標(biāo)地址。在所有的例子中,C傳給operand的可能是函數(shù)指針。所以面對(duì)傳給內(nèi)嵌匯編的常量、指針、變量,編譯器必須要知道怎樣組織到匯編代碼中。對(duì)于ARM核的處理器,GCC 4 提供了一下的限制。ConstraintUsage in AR
18、M stateUsage in Thumb statefFloating point registers f0 . f7Not availablehNot availableRegisters r8.r15GImmediate floating point constantNot availableHSame a G, but negatedNot availableIImmediate value in data processing instructionse.g. ORR R0, R0, #operandConstant in the range 0 . 255e.g. SWI oper
19、andJIndexing constants -4095 . 4095e.g. LDR R1, PC, #operandConstant in the range -255 . -1e.g. SUB R0, R0, #operandKSame as I, but invertedSame as I, but shiftedLSame as I, but negatedConstant in the range -7 . 7e.g. SUB R0, R1, #operandlSame as rRegisters r0.r7e.g. PUSH operandMConstant in the ran
20、ge of 0 . 32 or a power of 2e.g. MOV R2, R1, ROR #operandConstant that is a multiple of 4 in the range of 0 . 1020e.g. ADD R0, SP, #operandmAny valid memory addressNNot availableConstant in the range of 0 . 31e.g. LSL R0, R1, #operandONot availableConstant that is a multiple of 4 in the range of -50
21、8 . 508e.g. ADD SP, #operandrGeneral register r0 . r15e.g. SUB operand1, operand2, operand3Not availablewVector floating point registers s0 . s31Not availableXAny operand限制字符可能要單個(gè)modifier指示。要是沒有modifier指示的默認(rèn)為read-only operand。ModifierSpecifies=Write-only operand, usually used for all output operands
22、+Read-write operand, must be listed as an output operand&A register that should be used for output onlyOutput operands必須為write-only,相應(yīng)C表達(dá)式的值必須是左值。Input operands必須為read-only。C編譯器是沒有能力做這個(gè)檢查。比較嚴(yán)格的規(guī)則是:不要試圖向input operand寫。但是如果你想要使用相同的operand作為input和output。限制性modifier(+)可以達(dá)到效果。例子如下:asm("mov %valu
23、e, %value, ror #1" : value "+r" (y和上面例子不一樣的是,最后的結(jié)果存儲(chǔ)在input variable中。可能modifier + 不支持早期的編譯器版本。慶幸的是這里提供了其他解決辦法,該方法在最新的編譯器中依然有效。對(duì)于input operators有可能使用單一的數(shù)字n在限制字符串中。使用數(shù)字n可以告訴編譯器使用的第n個(gè)operand,operand都是以0開始計(jì)數(shù)。下面是例子:asm("mov %0, %0, ror #1" : "=r" (value : "0"
24、(value限制性字符串“0”告訴編譯器,使用和第一個(gè)output operand使用同樣input register。請(qǐng)注意,在相反的情況下不會(huì)自動(dòng)實(shí)現(xiàn)。如果我沒告訴編譯器那樣做,編譯器也有可能為input和output選擇相同的寄存器。第一個(gè)例子中就為input和output選擇了r3。在多數(shù)情況下這沒有什么,但是如果在input使用前output已經(jīng)被修改過了,這將是致命的。在input和output使用不同寄存器的情況下,你必須使用&modifier來限制output operand。下面是代碼示例:asm volatile("ldr %0, %1" &qu
25、ot;nt""str %2, %1, #4" "nt" : "=&r" (rdv : "r" (&table, "r" (wdv: "memory"在以張表中讀取一個(gè)值然后在寫到該表的另一個(gè)位置。其他內(nèi)嵌匯編作為預(yù)處理宏要是經(jīng)常使用使用部分匯編,最好的方法是將它以宏的形式定義在頭文件中。使用該頭文件在嚴(yán)格的ANSI模式下會(huì)出現(xiàn)警告。為了避免該類問題,可以使用_asm_代替asm,_volatile_代替volatile。這可以等同于別名。下面就是個(gè)例
26、程:#define BYTESWAP(val _asm_ _volatile_ ( "eor r3, %1, %1, ror #16nt" "bic r3, r3, #0x00FF0000nt" "mov %0, %1, ror #8nt" "eor %0, %0, r3, lsr #8" : "=r" (val : "0"(val : "r3", "cc" ;C 樁函數(shù)宏定義包含的是相同的代碼。這在大型routine中是不可以接受的。
27、這種情況下最好定義個(gè)樁函數(shù)。unsigned long ByteSwap(unsigned long valasm volatile ("eor r3, %1, %1, ror #16nt""bic r3, r3, #0x00FF0000nt""mov %0, %1, ror #8nt""eor %0, %0, r3, lsr #8": "=r" (val: "0"(val: "r3" ;return val;替換C變量的符號(hào)名默認(rèn)的情況下,GCC使用同函
28、數(shù)或者變量相同的符號(hào)名。你可以使用asm聲明,為匯編代碼指定一個(gè)不同的符號(hào)名unsigned long value asm("clock" = 3686400這個(gè)聲明告訴編譯器使用了符號(hào)名clock代替了具體的值。替換C函數(shù)的符號(hào)名為了改變函數(shù)名,你需要一個(gè)原型聲明,因?yàn)榫幾g器不接受在函數(shù)定義中出現(xiàn)asm關(guān)鍵字。extern long Calc(void asm ("CALCULATE"調(diào)用函數(shù)calc(將會(huì)創(chuàng)建調(diào)用函數(shù)CALCULATE的匯編指令。強(qiáng)制使用特定的寄存器局部變量可能存儲(chǔ)在一個(gè)寄存器中。你可以利用內(nèi)嵌匯編為該變量指定一個(gè)特定的寄存器。void Count(void register unsigned char counter asm("r3". some code.asm volatile("eor r3, r3, r3". more code.匯編指令“eor r3, r3, r3”,會(huì)將r3清零。Waring:該例子在到多數(shù)情況下是有問題的,因?yàn)檫@將和優(yōu)化器相沖突。因?yàn)镚CC不會(huì)預(yù)留其它寄存器。要是優(yōu)化器認(rèn)為該變量在以后一段時(shí)間沒有使用,那么該寄存器將會(huì)被再次使用。但是編譯器并沒有能力去檢查是否和編譯器預(yù)先定義的寄存器有沖突。如果你用這種方式指定了太多的寄存器,編譯器
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 課題申報(bào)參考:近十年公費(fèi)師范畢業(yè)生教師職業(yè)認(rèn)同演變、離職預(yù)警模型構(gòu)建及干預(yù)策略實(shí)證研究
- 2025版帶物業(yè)增值服務(wù)物業(yè)房產(chǎn)買賣合同書3篇
- 二零二五版新能源研發(fā)及生產(chǎn)廠房買賣合同范本3篇
- 二零二五年度廚具行業(yè)人才培養(yǎng)與輸送合同4篇
- 二零二五年度贖樓金融產(chǎn)品合作合同4篇
- 二零二五年度出軌婚姻解除后的子女撫養(yǎng)權(quán)及財(cái)產(chǎn)分割協(xié)議4篇
- 2025年度宗教活動(dòng)場(chǎng)地租賃合同范本3篇
- 二零二五年度彩鋼屋面防水隔熱一體化工程承包協(xié)議3篇
- 二零二五年度彩磚知識(shí)產(chǎn)權(quán)保護(hù)采購合同3篇
- 2025年人力資源經(jīng)理員工關(guān)系與勞動(dòng)爭(zhēng)議處理協(xié)議3篇
- GB/T 45120-2024道路車輛48 V供電電壓電氣要求及試驗(yàn)
- 春節(jié)文化常識(shí)單選題100道及答案
- 華中師大一附中2024-2025學(xué)年度上學(xué)期高三年級(jí)第二次考試數(shù)學(xué)試題(含解析)
- 12123交管學(xué)法減分考試題及答案
- 2025年寒假實(shí)踐特色作業(yè)設(shè)計(jì)模板
- 24年追覓在線測(cè)評(píng)28題及答案
- 高考滿分作文常見結(jié)構(gòu)
- 心肌梗死診療指南
- 食堂項(xiàng)目組織架構(gòu)圖
- 原油脫硫技術(shù)
- GB/T 2518-2019連續(xù)熱鍍鋅和鋅合金鍍層鋼板及鋼帶
評(píng)論
0/150
提交評(píng)論