美文网首页
02.汇编指令

02.汇编指令

作者: 柏666 | 来源:发表于2019-06-03 23:43 被阅读0次

        按照编译器不同,汇编分为两大量:一类是ADS的汇编程序,一类是GNU汇编格式任。

        以冒号结尾的标识符都被认为是一个标号,而不一定非要在一行的开始。

        GNU汇编:http://web.mit.edu/gnu/doc/html/as_toc.html#SEC127


    一、ARM指令  (带点的一般都是ARM GNU伪汇编指令)

            1. ".title xxx":指定汇编列表的标题。

                ".list":用来输出列表文件。

                ".type xxx":指定符号的类型。


            2. ".text":代码段。已编译程序的可执行机器码。

                ".rodata":只读数据段。const全局变量。比如printf语句中的格式串和开关(switch)语句的跳转表。

                ".data":数据段。已初始化的非零全局变量和静态变量。它会在main函数之前被处理。

                ".bss":未初始化(或初值为0)的全局变量。它在目标文件中不占实际的空间(不保存在bin文件中),是一个占位符。目标文件格式区分初始化和未初始化变量是为了提高空间效率。启动代码完成两方面:①未初始化变量的清0。②设置已初始化变量的初值。保存了BSS段和COMMON段(存放注释)的内容。

                ".symtab":符号表。存放被定义和引用的函数及全局变量。每个可重定位目标文件在.symtab中都有一张符号表。与编译器中的符号表不同,.symtab不包含局部变量的表目。不一定要通过-g编译程序,得到符号表信息。

                注释:为了让启动代码简单,编译链接器会把已初始化的变量放.data段,这个段的映像(包含了各个变量的初值)保存在“只读数据段”。启动代码复制这个映像到 .data 段,初始化所有变量。初始化为0的变量保存在bss段,未初始化变量保存在common段,链接时再将其放入bss段。启动代码调用 memset 把所有未初始化变量清0。

                ".rel.text":保存着一系列在.text中的位置的列表。这些位置在链接时被修改。这些位置通常保存着引用全局变量,或外部函数的指令。在运行时并不需要它以及下面的.rel.data。生成可执行文件ELF object时会去掉。除非使用者去显式指示链接器包含这些信息。

                ".rel.data":保存全局变量的重定位信息。如果一个全局变量的初始化值,是另一个全局变量的地址,或者是外部函数的地址时,它就需要被重定位。

                ".debug":调试符号表。其可以是程序中定义的:局部变量、类型定义、全局变量的定义和引用、C源文件。只有" -g "选项才会生成这张表。

                ".line":源程序中的行号和.text中机器指令间的映射。只有以-g选项调用编译驱动程序时才会生成。

                ".strtab":字符串表。包含.symtab和.debug中的符号表,和各个section的名字。字符串表是以null结尾的字符串序列。.debug和.symtab中,保存name的域,等于保存了一个偏移值。可以通过这个偏移值在字符串表里面找到相应字符串。(https://www.veryarm.com/23019.html)


            3. ".section":自定义一个段。.section section_name [, "flags"[, %type[,flag_specific_arguments]]]。每一个段以段名为开始, 以下一个段名或者文件结尾为结束。这些段都有缺省的标志(flags),连接器可以识别这些标志。(与armasm中的AREA相同)。


            4. 注释:代码行中的注释符号: ‘@’。整行注释符号: ‘#’。语句分离符号: ‘ ; ’。直接操作数前缀: ‘#’ 或 ‘$’。


            5. "_start":汇编程序的缺省入口。如果想更改,到相应的链接脚本中去用ENTRY指明其他入口标志。标号可以直接认为是地址。

            6. ".globl/.global":定义一个全局符号,通常为ld使用。例如 .global _start(定义 _start 为外部程序可以访问的标签)。


            7. ".abort":停止汇编。

            8. ".string/.asciz/.ascii"、".byte"、".short"、".int"、".long"、".float"、".word"、".quad":定义一个类型并分配空间(字符串、字节(1 byte)、短整型(2 byte)、整型(4 byte)、长整型(4 byte)、浮点数、字(与系统位数有关。16位系统中是2字节)、quard word(4字))。用".string/.asciz"定义时要加双引号,用".ascii"定义时还要在末尾手动添加"\0"。

            9. ".align xxx, yyy":对齐方式。xxx表示对齐方式,4, 8,16或32。 yyy 表示填充的值。一般用于定义完字符串等类型之后的代码对齐。


            10. ".if" ".else" ".endif":条件预编译。if的变种如下:

            11. ".include "file" ":包含指定文件。可以把汇编常量定义放在头文件中。

            12. ".incbin "file"[,skip[,count]]":将二进制文件编译到当前文件中。skip是以字节为单位,从文件头部读取的偏移量。count是读取的字数。

            13. ".macro .endm":.macro定义的宏代码的开始, .endm宏代码的结束,.exitm跳出宏。若宏使用参数,则宏体中使用该参数时添加前缀“\”。宏定义时的参数还可以使用默认值。


            14. ".comm symbol, length":在bss段申请一段叫symbol的命名空间,长度为length。Ld连接器连接时会为它留出空间。

            15. ".rept x":重复定义x次其内的定义。用 .endr结束。

            16. "(.equ/.set) xxx, yyy":把符号定义成值。它不分配空间,相当于#define。或者用“ xxx equ yyy ”。

            17. ".req":为寄存器定义别名。

                  ".unreq":取消寄存器别名。

            18. ".code":.code [16|32]: 指定指令代码产生的长度, 16表示Thumb指令, 32表示ARM指令。

            19. ".ltorg/.pool":当前往下的定义在归于当前段,并为之分配空间。即声明数据缓冲池。

            20. ".space <x> {,<aaa>}":分配x字节空间,并用aaa填充。缺省填充0。


    二、进制的表示

            1. 二进制数以0b开头,其中字母也可以为大写

            2. 八进制数以0开始,如:0456,0123

            3. 十进制数以非0数字开头,如:123和9876

            4. 十六进制数以0x开头,如:0xabcd,0X123f

            5. 字符串常量用引号括起来,中间也可以使用转义字符。如: “You are welcome!\n”

            6. 当前地址以" . "表示

            7. 表达式:汇编程序中表达式可使用常数或数值。" - "取负数, " ~ "取补," < > "不相等," +、-、*、 /、%、<、<<、>、>>、|、&、^、!、==、>=、<=、&&、|| "跟C语言用法相似。


    三、操作寄存器

            "ldr    r0,    [ r1 ]":读取地址 [ r1 ] 上的数据,并保存到 R0 寄存器中,长度为4字节。(方括号内的表示地址)

            "ldr    r0,    [ r1, #4 ]":将地址为 r1+4 的内存单元数据读取到 r1 中。

            "ldr    r0,    [ r1 ],    #4:将地址为 [ r1 ] 的内存单元数据读取到 r0 中,然后 r1 = r1+4。

            ★.在32位ARM指令中会用某些位表示当前执行的指令(LDR等)及寄存器(R0等)。剩下的位数不足以表示任意值,所以引入伪指令。伪指令会被拆分成ARM指令。

            ldr 伪指令的三种用法:

                    ①. ldr r0, = 0x10:给 r0 赋值为0x10

                    ②. ldr pc, =Label:将 Label 符号放入pc寄存器中。编译时会替换成一条 ldr 指令和一条 dcd 伪指令。符号地址由编译器指定。

                    ③. ldr pc, Label_addr:读取存储器中 Label_addr 符号所表示的地址中的值放入 pc 。多读一次存储器。


            "str    r0,    [ r1 ]":把 r0 寄存器上的值,保存到地址 [ r1 ] 的地方,长度为4字节。

            "str    r0,    [ r1, #4 ]":将 r0 的数据保存到地址为 r1+4 的内存单元中。

            "str    r0,    [ r1 ],    #4":将 r0 的数据保存到地址为 r1 的内存单元中,然后 r1=r1+4。


            "ldmia    r0,    { r1, r2, r3, r4 }   stmdb    r0!,    { r1, r2, r3, r4 }":一次设置多个寄存器。后增,即先操作后增加。32位芯片的话,增加/减少的单位是4。按寄存器编号依次操作寄存器,高编号寄存器存放在高地址。(ld/st) + m + (i/d/f/e) + (a/b) = (读取/设置)+ 多个寄存器 +(增加/减少/满/空)+(之后/之前)。" "表示此寄存器的值等于最终被修改后的值。否则最终值等于初始值。ldm命令末尾的" "表示将spsr写回到cpsr,用于异常返回后工作状态的恢复,不允许在用户模式和系统模式下运行。

            当堆栈指针指向最后压入的数据时为满堆栈,当指针指向下一个将要放入数据的空位置时为空堆栈。当堆栈由低地址向高地址生成时称递增堆栈,当堆栈由高地址向低地址生成时称递减堆栈。下列是入栈和出栈的指令对:

                    Full descending :    stmdb--ldmia  或  stmfd--ldmfd  

                    Full ascending :      stmib--ldmda  或  stmfa--ldmfa  

                    Empty descending :stmda--ldmib  或  stmed--ldmed  

                    Empty ascending :  stmia--ldmdb  或  stmea--ldmea  

            注意:虽然ARM处理器核对于两种生长方式的堆栈均支持,但ADS的C语言编译器仅支持一种方式,即从上往下长,并且必须是满递减堆栈。所以STMFD等指令用的最多。

            "adr    r0,    xxx":将基于PC相对偏移的地址值读取到 r0。编译时ADR伪指令会被替换。通常是用ADD或SUB指令。若不能用一条指令实现,则会产生错误,编译失败。


            "mrs    r1,    cpsr":读出 cpsr 中的值到 r1 中。

            "msr    cpsr,    r1":将 r1 寄存器中的值恢复到 r1 中。

            "swi    xxx":执行软中断。xxx 为24位的二进制数,表示处理不同软中断。


            "mov    R0,    R1":把 R1 的值赋给 R0 。

            "mov    R0,    [ R1 ]":把 R1 地址的值赋给 R0 。

            "mov    R0,    #0x10":把立即数 0x10 赋给 R0 。立即数是小于0xff(65535)的数,如果大于65535,则用ldr指令赋值。

            "mvn    r0,    #0":把0取反(即-1)传给 r0。

            注意:ARM是RISC结构,数据在内存和CPU间的移动只能通过ldr/str指令。mov只是在寄存器间移动数据,或把立即数移动到寄存器中。而X86中没有ldr这种指令。因为X86的mov指令可以将数据从内存中移到寄存器中。


            "nop":空操作指令。可以用作延时。

            "add    r0,    r1,    r2":r0 = r1 + r2。

            "adds    r0,    r1,    r2":r0 = r1 + r2。s表示把进位结果写入cpsr。sub同理。

            "sub    r0,    r1,    r2":r0 = r1 - r2。

            "mul    r0,    r1,    r2": r0 = r1 * r2。


    <opcode>{<cond>}{S} <Rd>,<Rn>{,<shifter_operand>}

            对shifter_operand参数的位移。

            左右移:http://www.eeworld.com.cn/mcu/2015/0930/article_22693.html


            "tst    r0,    r1":位比较。先按位与并把结果写入CPSR,供下一句使用。结果为1,则设置标志位zero=0,会执行bne语句。否则不执行bne。beq则相反。

            "cmp    xxx,    yyy":两值相减,只改标志位。标志位存入CPSR供下一句语句使用。

            (分支指令)

            "b    xxx":简单的跳转,即调用子程序。跳转到到目标标号处执行。跳转范围是当前指令的前后32M。

            "bl    xxx":带链接的程序跳转,即要带返回地址。跳转前将当前PC-4(返回地址)保存至R14(LR)。子程序返回时会执行 MOV PC, LR。跳转范围是当前指令的前后32M。

            "bx{<condition>}  <rx>":<condition>为指令执行的条件码,缺省时无条件执行。<rx>寄存器中为跳转的目标地址。当<rx>寄存器bit[0]为0时,目标地址处的指令为ARM指令;当bit[0]为1时,则为Thumb指令。(ARM汇编)

            注意:反汇编文件里,用 B或BL 等跳某个值,只是方便查看,并不是真的跳转。

            (条件执行指令)

            "bne    xxx":数据跳转指令,标志寄存器中Z标志位不等于零时,跳转到BNE后标签处。

            "beq    xxx":数据跳转指令,标志寄存器中Z标志位等于零时,跳转到BEQ后标签处。

            注意:bne 1f,或beq 1b。1f:程序之后的"1"标号(forward)。1b:程序之前的"1"标号(before)。

             bvs:  Branch if overflow(溢出) Set

             bvc:  Branch if overflow(溢出) Clear

             bhi:   Branch if HIgher

             bls:   Branch if Lower or the Same

             bpl:   Branch if Plus

             bmi:   Branch if MInus

             bcs:   Branch if Carry Set(进位设置)

             bcc:   Branch if Carry Clear(进位清除)

             bge:   Branch if Greater than or Equal

             bgt:   Branch if Greater Than

             ble:   Branch if Less than or Equal

             blt:   Branch if Less Than

             bleq:  Branch with Link if Equal(带返回链接的判断型跳转)

             bllt:  Branch with Link if Less Than(带返回链接的判断型跳转)

            "moveq    r1, #0": 如果上一句条件执行码<condition>判断为相等,则执行mov指令。ARM汇编指令。

            "movgt    r1, #0":如果上一句条件执行码<condition>判断左边大,则执行mov指令。ARM汇编指令。


            "and    r0,    r1":r0 &= r1。按位与。

            "and    r0,    r1,    r2":r0 = r1 & r2。

            "orr    r0,    r1":r0 |= r1。按位或。

            "orr    r0,    r1,    r2":r0 = r1 | r2。

            "not    r0":r0 = ! r0。按位取反。指令的执行不影响任何标志位。

            "bic    r0,    r1":r0 &= ~r1。按位清零。

            "bic    r0,    r1,    #%1011":r0 = r1 & 4。%表示二进制,0x表示十六进制。

            "orn    r0,    r1":r0 = r0 | ~r1。按位或反。

            "eor    r0,    r1":r0 ^= r1。按位异或(不同为1,相同为0)。


    1、注释行以“@”代替“;”

    2、伪操作符替换:INCLUDE 替换成 .INCLUDE

    TCLK2 EQU PB25 替换成 .equ TCLK2, PB25

    EXPORT 替换成 .global

    IMPORT 替换成 .extern

    DCD 替换成 .long

    IF :DEF: 替换成 .IFDEF

    ELSE 替换成 .ELSE

    ENDIF 替换成 .ENDIF

    :OR: 替换成 |

    :SHL: 替换成 <<

    END 替换成 .end

    符号定义后要加":"号

    AREA Word, CODE, READONLY --> .text

    AREA Block, DATA, READWRITE --> .data

    CODE32 --> .arm

    CODE16 --> .thumb

    LTORG --> .ltorg

    相关文章

      网友评论

          本文标题:02.汇编指令

          本文链接:https://www.haomeiwen.com/subject/gtvnzqtx.html