新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > ARM標準匯編與GNU匯編

        ARM標準匯編與GNU匯編

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


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

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

        起始點:
        gnu匯編器使用_start標簽表示默認的起始點, 此外如果想要匯編內(nèi)部的標簽能夠被外部程序訪問,
        需要使用.globl 指令, 如:.globl _start


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

        本文引用地址:http://www.104case.com/article/201611/319125.htm

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

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

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

        聲明指令:
        .ascii 文本字符串
        .asciz 以空字符結尾的字符串
        .byte 字節(jié)值
        .double 雙精度浮點值
        .float 單精度浮點值
        .int 32位整數(shù)
        .long 32位整數(shù), 和int相同
        .octa 16字節(jié)整數(shù)
        .quad 8字節(jié)整數(shù)
        .short 16位整數(shù)
        .single 單精度浮點數(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是為不會從本地匯編代碼之外進行訪問的數(shù)據(jù)保留的, 格式為:
        .comm/.lcomm symbol, length

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

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

        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)容。


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

        其中:movl value, ?x 只是把標簽value當前引用的內(nèi)存值傳遞給eax
        movl $value, ?x 把標簽value當前引用的內(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 無進位
        b/nae 小于/不大于等于
        c 進位
        be/na 小于或等于/不大于
        e/z 等于/零
        ne/nz 不等于/不為零
        p/pe 奇偶校驗/偶校驗
        np/po 非奇偶校驗/奇校驗

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

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

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

        如: bswap ?x

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

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

        cmpxchg
        cmpxchg source, destination
        其中source必須是寄存器, destination可以是內(nèi)存或者寄存器, 用來比較
        兩者的值, 如果相等,就把源操作數(shù)的值加載到目標操作數(shù)中, 如果不等就把
        目標操作數(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低位寄存器)進行比較, 如果目標值和EDX:EAX
        對中的值相等, 就把EDX:EAX對中的64位值傳遞給內(nèi)存位置, 如果不匹配就把
        內(nèi)存地址中的值加載到EDX:EAX對中



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

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

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


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

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

        比較:
        cmp operend1, operend2

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


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

        指令格式為: 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,否則會導致主匯編程序結束。

        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ù)器(在當前子段)使它指向規(guī)定的存儲邊界。第一個表達式參數(shù)(結果必須是純粹的數(shù)字)是必需參數(shù):邊界基準,單位為字節(jié)。例如,‘.balign 8’向后移動位置計數(shù)器直至計數(shù)器的值等于8的倍數(shù)。如果位置計數(shù)器已經(jīng)是8的倍數(shù),則無需移動。第2個表達式參數(shù)(結果必須是純粹的數(shù)字)給出填充字節(jié)的值,用這個值填充位置計數(shù)器越過的地方。第2個參數(shù)(和逗點)可以省略。如果省略它,填充字節(jié)的值通常是0。但在某些系統(tǒng)上,如果本段標識為包含代碼,而填充值被省略,則使用no-op指令填充空白區(qū)。第3個參數(shù)的結果也必須是純粹的數(shù)字,這個參數(shù)是可選的。如果存在第3個參數(shù),它代表本對齊命令允許跳過字節(jié)數(shù)的最大值。如果完成這個對齊需要跳過的字節(jié)數(shù)比規(guī)定的最大值還多,則根本無法完成對齊。您可以在邊界基準參數(shù)后簡單地使用兩個逗號,以省略填充值參數(shù)(第二參數(shù));如果您在想在適當?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的另一種作用
        標簽: word 2011-04-13 18:13


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

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

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



        關鍵詞: ARM標準匯編GNU匯

        評論


        技術專區(qū)

        關閉
        主站蜘蛛池模板: 新巴尔虎左旗| 炎陵县| 合作市| 武城县| 香河县| 黑河市| 茶陵县| 曲松县| 鄂温| 旬阳县| 灵石县| 福鼎市| 湖南省| 唐河县| 五指山市| 蒙自县| 大渡口区| 三原县| 永福县| 公安县| 灌云县| 中阳县| 清涧县| 吉首市| 大方县| 南召县| 赤城县| 宁乡县| 历史| 洪雅县| 丽水市| 皮山县| 宝清县| 尖扎县| 安溪县| 玉溪市| 尚义县| 孟连| 扎兰屯市| 盘山县| 镇江市|