美文网首页
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

相关文章

  • 逆向笔记(三)-汇编指令

    汇编指令 针对汇编来说,汇编指令是必须了解的,而且汇编中汇编指令比较多,但是每一个汇编指令对应的机器码是固定不变的...

  • 16位汇编简记

    汇编: 汇编即是机器指令助记符,机器指令让cpu工作。像是mov、jmp、jcxz等汇编指令都有对应的机器指令。有...

  • 学习汇编--写一个完整的汇编(一)

    汇编指令 汇编有两类指令组成汇编指令如move,add,sub等,有对应的机器指令,可以被编译为机器指令最终被CP...

  • 逆向学习 持续更新中

    什么是汇编 机器指令能被计算机直接识别 汇编指令需要通过编译器转为机器指令 汇编指令和机器指令的差别在于指令的表示...

  • <<汇编语言>>第1章笔记

    第一章 基础知识 汇编语言基本概念 汇编指令是机器指令便于记忆的书写格式,通过编译器把汇编指令对应到机器指令,汇编...

  • 汇编三

    完整的汇编指令:#### 汇编由两种指令组成1.汇编指令如mov、add、sub等有对应的机器指令,可以被编译为机...

  • 彻底搞清楚Java并发 (二) 底层实现

    Java代码 -> Java字节码 -> 汇编指令(汇编指令是cpu指令的集合) Volatile Java语言提...

  • 汇编程序基础

    汇编程序基础 一、汇编程序基本结构 二、汇编指令 1.汇编指令基本结构 三、伪指令 1.段定义 2.数据定义 数据...

  • 汇编语言学习笔记-仅供个人

    汇编语言 汇编指令通过编译器可以将汇编指令翻译成机器指令 伪指令告诉翻译软件,也就是编译器,这里怎么翻译,那里怎么...

  • 2.8 常用的汇编指令

    2.8 常用的汇编指令 本节必须掌握的知识点: 汇编指令 多动手实验,知道每个指令的功能 在此节之前汇编课程主要讲...

网友评论

      本文标题:02.汇编指令

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