色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > ARM標(biāo)準(zhǔn)匯編與GNU匯編

          ARM標(biāo)準(zhǔn)匯編與GNU匯編

          作者: 時間:2016-11-21 來源:網(wǎng)絡(luò) 收藏
          前段時間看arm的匯編,發(fā)現(xiàn)很多有一個小點(diǎn),但是借來的書上的語法卻沒有,問同學(xué)也不知道,于是在網(wǎng)上查了一番才發(fā)現(xiàn)我書上看到的是arm的標(biāo)準(zhǔn)匯編,而有小點(diǎn)的gnu的匯編,于是將收集到的資料整理后放到這里來。


          GNU匯編語言結(jié)構(gòu)
          主要包括三個常用的段:
          data 數(shù)據(jù)段 聲明帶有初始值的元素
          bss 數(shù)據(jù)段 聲明使用0或者null初始化的元素
          text 正文段 包含的指令, 每個匯編程序都必須包含此段

          使用.section 指令定義段, 如:
          .section .data
          .section .bss
          .section .text

          起始點(diǎn):
          gnu匯編器使用_start標(biāo)簽表示默認(rèn)的起始點(diǎn), 此外如果想要匯編內(nèi)部的標(biāo)簽?zāi)軌虮煌獠砍绦蛟L問,
          需要使用.globl 指令, 如:.globl _start


          使用通用庫函數(shù)時可以使用:
          ld -dynamic-linker /lib/ld-linux.so.2

          本文引用地址:http://cafeforensic.com/article/201611/319125.htm

          ################################################################################################
          # 四, 數(shù)據(jù)傳遞
          ################################################################################################
          1, 數(shù)據(jù)段
          使用.data聲明數(shù)據(jù)段, 這個段中聲明的任何數(shù)據(jù)元素都保留在內(nèi)存中并可以被匯編程序的指令讀取,
          此外還可以使用.rodata聲明只讀的數(shù)據(jù)段, 在聲明一個數(shù)據(jù)元素時, 需要使用標(biāo)簽和命令:

          標(biāo)簽:用做引用數(shù)據(jù)元素所使用的標(biāo)記, 它和c語言的變量很相似, 它對于處理器是沒有意義的, 它只是用做匯編器試圖訪問內(nèi)存位置時用做引用指針的一個位置。

          指令:指示匯編器為通過標(biāo)簽引用的數(shù)據(jù)元素保留特定數(shù)量的內(nèi)存, 聲明命令之后必須給出一個或多個默認(rèn)值。

          聲明指令:
          .ascii 文本字符串
          .asciz 以空字符結(jié)尾的字符串
          .byte 字節(jié)值
          .double 雙精度浮點(diǎn)值
          .float 單精度浮點(diǎn)值
          .int 32位整數(shù)
          .long 32位整數(shù), 和int相同
          .octa 16字節(jié)整數(shù)
          .quad 8字節(jié)整數(shù)
          .short 16位整數(shù)
          .single 單精度浮點(diǎn)數(shù)(和float相同)


          例子:
          output:
          .ascii "hello world."

          pi:
          .float 2.14

          聲明可以在一行中定義多個值, 如:
          ages:
          .int 20, 10, 30, 40


          定義靜態(tài)符號:
          使用.equ命令把常量值定義為可以在文本段中使用的符號,如:
          .section .data
          .equ LINUX_SYS_CALL, 0x80
          .section .text
          movl $LINUX_SYS_CALL, ?x



          2, bss段
          和data段不同, 無需聲明特定的數(shù)據(jù)類型, 只需聲明為所需目的保留的原始內(nèi)存部分即可。
          GNU匯編器使用以下兩個命令聲明內(nèi)存區(qū)域:
          .comm 聲明為未初始化的通用內(nèi)存區(qū)域
          .lcomm 聲明為未初始化的本地內(nèi)存區(qū)域

          兩種聲明很相似,但.lcomm是為不會從本地匯編代碼之外進(jìn)行訪問的數(shù)據(jù)保留的, 格式為:
          .comm/.lcomm symbol, length

          例子:
          .section .bss
          .lcomm buffer, 1000
          該語句把1000字節(jié)的內(nèi)存地址賦予標(biāo)簽buffer, 在聲明本地通用內(nèi)存區(qū)域的程序之外的函數(shù)是不能訪問他們的.(不能在.globl命令中使用他們)

          在bss段聲明的好處是, 數(shù)據(jù)不包含在可執(zhí)行文件中。在數(shù)據(jù)段中定義數(shù)據(jù)時, 它必須被包含在可執(zhí)行程序中, 因為必須使用特定值初始化它。因為不使用數(shù)據(jù)初始化bss段中聲明的數(shù)據(jù)區(qū)域,所以內(nèi)存區(qū)域被保留在運(yùn)行時使用, 并且不必包含在最終的程序中。

          3, 傳送數(shù)據(jù)
          move 指令:
          格式 movex 源操作數(shù), 目的操作數(shù)。 其中x為要傳送數(shù)據(jù)的長度, 取值有:
          l 用于32位的長字節(jié)
          w 用于16位的字
          b 用于8位的字節(jié)值

          立即數(shù)前面要加一個$符號, 寄存器前面要加%符號。

          8個通用的寄存器是用于保存數(shù)據(jù)的最常用的寄存器, 這些寄存器的內(nèi)容可以傳遞
          給其他的任何可用的寄存器。 和通用寄存器不同, 專用寄存器(控制, 調(diào)試, 段)
          的內(nèi)容只能傳送給通用寄存器, 或者接收從通用寄存器傳過來的內(nèi)容。


          在對標(biāo)簽進(jìn)行引用時:
          例:
          .section .data
          value:
          .int 100
          _start:
          movl value, ?x
          movl $value, ?x
          movl ?x, (?i)
          movl ?x, 4(?i)

          其中:movl value, ?x 只是把標(biāo)簽value當(dāng)前引用的內(nèi)存值傳遞給eax
          movl $value, ?x 把標(biāo)簽value當(dāng)前引用的內(nèi)存地址指針傳遞給eax
          movl ?x, (?i) 如果edi外面沒有括號那么這個指令只是把ebx中的
          值加載到edi中, 如果有了括號就表示把ebx中的內(nèi)容
          傳送給edi中包含的內(nèi)存位置。
          movl ?x, 4(?i) 表示把edi中的值放在edi指向的位置之后的4字節(jié)內(nèi)存位置中
          movl ?x, -4(?i) 表示把edi中的值放在edi指向的位置之前的4字節(jié)內(nèi)存位置中



          cmove 指令(條件轉(zhuǎn)移):
          cmovex 源操作數(shù), 目的操作數(shù). x的取值為:
          無符號數(shù):
          a/nbe 大于/不小于或者等于
          ae/nb 大于或者等于/不小于
          nc 無進(jìn)位
          b/nae 小于/不大于等于
          c 進(jìn)位
          be/na 小于或等于/不大于
          e/z 等于/零
          ne/nz 不等于/不為零
          p/pe 奇偶校驗/偶校驗
          np/po 非奇偶校驗/奇校驗

          有符號數(shù):
          ge/nl 大于或者等于/不小于
          l/nge 小于/不大于或者等于
          le/ng 小于或者等于/不大于
          o 溢出
          no 未溢出
          s 帶符號(負(fù))
          ns 無符號(非負(fù))

          交換數(shù)據(jù):
          xchg 在兩個寄存器之間或者寄存器和內(nèi)存間交換值
          如:
          xchg 操作數(shù), 操作數(shù), 要求兩個操作數(shù)必須長度相同且不能同時都是內(nèi)存位置
          其中寄存器可以是32,16,8位的

          bswap 反轉(zhuǎn)一個32位寄存器的字節(jié)順序

          如: bswap ?x

          xadd 交換兩個值并把兩個值只和存儲在目標(biāo)操作數(shù)中

          如: xadd 源操作數(shù),目標(biāo)操作數(shù)
          其中源操作數(shù)必須是寄存器, 目標(biāo)操作數(shù)可以是內(nèi)存位置也可以是寄存器
          其中寄存器可以是32,16,8位的

          cmpxchg
          cmpxchg source, destination
          其中source必須是寄存器, destination可以是內(nèi)存或者寄存器, 用來比較
          兩者的值, 如果相等,就把源操作數(shù)的值加載到目標(biāo)操作數(shù)中, 如果不等就把
          目標(biāo)操作數(shù)加載到源操作數(shù)中,其中寄存器可以是32,16,8位的, 其中源操作
          數(shù)是EAX,AX或者AL寄存器中的值


          cmpxchg8b 同cmpxchg, 但是它處理8字節(jié)值, 同時它只有一個操作數(shù)
          cmpxchg8b destination
          其中destination引用一個內(nèi)存位置, 其中的8字節(jié)值會與EDX和EAX寄存器中
          包含的值(EDX高位寄存器, EAX低位寄存器)進(jìn)行比較, 如果目標(biāo)值和EDX:EAX
          對中的值相等, 就把EDX:EAX對中的64位值傳遞給內(nèi)存位置, 如果不匹配就把
          內(nèi)存地址中的值加載到EDX:EAX對中



          4, 堆棧
          ESP 寄存器保存了當(dāng)前堆棧的起始位置, 當(dāng)一個數(shù)據(jù)壓入棧時, 它就會自動遞減,
          反之其自動遞增

          壓入堆棧操作:
          pushx source, x取值為:
          l 32位長字
          w 16位字

          彈出堆棧操作:
          popx source
          其中source必須是16或32位寄存器或者內(nèi)存位置, 當(dāng)pop最后一個元素時ESP值應(yīng)該
          和以前的相等


          5,壓入和彈出所有寄存器
          pusha/popa 壓入或者彈出所有16位通用寄存器
          pushad/popad 壓入或者彈出所有32位通用寄存器
          pushf/popf 壓入或者彈出EFLAGS寄存器的低16位
          pushfd/popfd 壓入或者彈出EFLAGS寄存器的全部32位

          6,數(shù)據(jù)地址對齊
          gas 匯編器支持.align 命令, 它用于在特定的內(nèi)存邊界對準(zhǔn)定義的數(shù)據(jù)元素, 在數(shù)據(jù)段中.align命令緊貼在數(shù)據(jù)定義的前面

          比較:
          cmp operend1, operend2

          進(jìn)位標(biāo)志修改指令:
          CLC 清空進(jìn)位標(biāo)志(設(shè)置為0)
          CMC 對進(jìn)位標(biāo)志求反(把它改變?yōu)橄喾吹闹?
          STC 設(shè)置進(jìn)位標(biāo)志(設(shè)置為1)


          循環(huán):
          loop 循環(huán)直到ECX寄存器為0
          loope/loopz 循環(huán)直到ecx寄存器為0 或者沒有設(shè)置ZF標(biāo)志
          loopne/loopnz 循環(huán)直到ecx為0或者設(shè)置了ZF標(biāo)志

          指令格式為: loopxx address 注意循環(huán)指令只支持8位偏移地址

          另有一個比較篇的如下:

          ARM匯編和Gnu匯編的轉(zhuǎn)換

          將ARM ADS下的匯編碼移植到GCC for ARM編譯器時,有如下規(guī)則:
          1, 注釋行以"@"或""代替";"

          2, GET或INCLUDE => .INCLUDE
          如:get option.a => .include "option.a"

          3, EQU => .equ
          TCLK2 EQU PB25 => .equ TCLK2, PB25
          SETA ==> .equ
          SETL ==> .equ
          BUSWIDTH SETA 16 => .equ BUSWIDTH, 16

          4, EXPORT => .global
          IMPORT => .extern
          GBLL => .global
          GBLA => .global

          5, DCD => .long

          6, IF :DEF: => .IFDEF
          ELSE => .ELSE
          ENDIF => .ENDIF
          :OR: => |
          :SHL: => <<

          7, END =>.end
          NOTE:在被include的頭文件中,如"option.a"中,不再需要.end,否則會導(dǎo)致主匯編程序結(jié)束。

          8, 符號定義加":"號
          Entry => Entry:
          AREA Word, CODE, READONLY ==> .text
          AREA Block, DATA, READWRITE ==> .data
          CODE32 ==> .arm
          CODE16 ==> .thumb

          9, MACRO ==> .macro
          MEND ==> .endm

          開始看start.s中的代碼,又一句.balignl 16,0xdeadbeef,不知什么意思,網(wǎng)上搜了一下了解到這條


          命令的作用如下:



          .balign[wl] abs-expr, abs-expr, abs-expr



          增加位置計數(shù)器(在當(dāng)前子段)使它指向規(guī)定的存儲邊界。第一個表達(dá)式參數(shù)(結(jié)果必須是純粹的數(shù)字)是必需參數(shù):邊界基準(zhǔn),單位為字節(jié)。例如,‘.balign 8’向后移動位置計數(shù)器直至計數(shù)器的值等于8的倍數(shù)。如果位置計數(shù)器已經(jīng)是8的倍數(shù),則無需移動。第2個表達(dá)式參數(shù)(結(jié)果必須是純粹的數(shù)字)給出填充字節(jié)的值,用這個值填充位置計數(shù)器越過的地方。第2個參數(shù)(和逗點(diǎn))可以省略。如果省略它,填充字節(jié)的值通常是0。但在某些系統(tǒng)上,如果本段標(biāo)識為包含代碼,而填充值被省略,則使用no-op指令填充空白區(qū)。第3個參數(shù)的結(jié)果也必須是純粹的數(shù)字,這個參數(shù)是可選的。如果存在第3個參數(shù),它代表本對齊命令允許跳過字節(jié)數(shù)的最大值。如果完成這個對齊需要跳過的字節(jié)數(shù)比規(guī)定的最大值還多,則根本無法完成對齊。您可以在邊界基準(zhǔn)參數(shù)后簡單地使用兩個逗號,以省略填充值參數(shù)(第二參數(shù));如果您在想在適當(dāng)?shù)臅r候,對齊操作自動使用no-op指令填充,本方法將非常奏效。.balignw和.balignl是.balign命令的變化形式。.balignw使用2個字節(jié)來填充空白區(qū)。.balignl使用4字節(jié)來填充。例如,.balignw 4,0x368d將地址對齊到4的倍數(shù),如果它跳過2個字節(jié),GAS將使用0x368d填充這2個字節(jié)(字節(jié)的確切存放位置視處理器的存儲方式而定)。

          如果它跳過1或3個字節(jié),則填充值不明確。

          GNU中的.word的另一種作用
          標(biāo)簽: word 2011-04-13 18:13


          不管是ARM的匯編還是GNU的匯編,都有DCD或者.word命令,它是用來開辟一個字空間。

          如:標(biāo)識1 .word 標(biāo)識2 它表示將標(biāo)識2的數(shù)據(jù)存放在以標(biāo)識1的地址上去。這個.word和DCD等指令,相當(dāng)于C語言的指針(如 char * p)。那么在匯編中用以上的代碼聲明的標(biāo)識1不需要在該文件中用extern的字段來表明是可以在外部引用的,它是內(nèi)存空間,可以在每個文件中使用這個標(biāo)識1.而ldr pc,內(nèi)存地址 它表示將內(nèi)存地址中的數(shù)據(jù)送入pc寄存器中去,而ldr pc,=內(nèi)存地址它表示將內(nèi)存地址放入pc寄存器中去。

          這些是在分析代碼時候遇到的不明白的地方,經(jīng)過查找資料的出來的。



          評論


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

          關(guān)閉