• Linux中的汇编简介


    GNU as汇编语法

    GNU汇编语法使用的是AT&T汇编它和Intel汇编的语法主要有以下一些不同:

    • AT&T汇编中的立即操作数前面要加上'$',寄存器操作数名前要加上百分号'%',绝对跳转操作数前要加上'*',Intel的语法均不包含这些符号;
    • AT&T语法与Intel语法中使用的源操作数和目的操作数顺序正好相反,AT&T的源操作数和目的操作数是从左到右,Intel语法是从右到左,例如add eax, 4在AT&T语法中是addl $4, %eax;
    • AT&T语法中内存操作数长度由操作码的最后一位字符来确定,操作码后缀有b/w/l分别代表内存引用宽度为8位,16位和32位,Intel语法则通过在内存操作数前使用前缀byte ptr,word ptr和dword ptr来达到此目的。例如Intel中的mov al, byte ptr foo对应AT&T中的语句为movb $foo, %al;
    • AT&T语法中立即跳转和调用为ljmp/lcall $section, $offset,而Intel中的是jmp/call far section:offset,AT&T中的返回指令lret $stack-adjust对应Intel的ret far stack-adjust;
    • AT&T汇编器不支持多代码段程序,类UNIX系统要求所有代码在一个段中;

    预处理:as汇编器能对汇编语言进行简单的预处理,包括删除多余的空格和制表符,删除注释语句,把字符常数转换为对应的数值,但此预处理不能处理宏,也没有处理包含文件的功能,如果需要这些功能,可以使用gcc的预处理器cpp来实现。

    符号:GNU汇编语言中的符号是由字符组成的标识符,组成符号的字符包含大小写字母,数字和_.$三个字符,符号不允许以数字开始,且区分大小写。在汇编程序中符号长度没有限制,符号使用空格来界定开始和结束。语句以换行符或者行分割符(;)作为结束,文件最后必须以换行符作为结束,语句有0个或多个标号开始(Label),后面可跟随一个确定语句类型的关键符号,标号由符号后面跟随一个冒号构成,关键符号确定了余下部分语句的语义,如果关键符号以.开始,那么当前语句就是一个汇编命令,如果关键符号以字母开始,那么当前语句就是一条汇编语言指令语句,一it哦啊语句的通用格式为:

    标号:汇编命令     注释语句
    或者
    标号:指令助记符 操作数1, 操作数2     注释语句

    常数:常数是一个数字,分为字符常数和数字常数两类,字符常数分为单个字符和字符串,数字常数分为整数和浮点数。汇编语言的单个字符表示一版为在该字符前加上单引号,而字符串需要添加双引号。

    指令:指令是CPU执行的操作,通常指令称为操作码,操作数是指令操作的对象,而地址是指令数据在内存中的位置,一条指令语句一版包括:标号,操作码(指令助记符),操作数,注释。

    操作数:操作数包含立即操作数,寄存器和内存。间接操作数含有实际操作数的地址值,AT&T语法通过在操作数前加上*来表示间接操作数,只有跳转和调用指令才能使用间接操作数。立即操作数前面需要加上$符号,寄存器名前面需要加上%符号,内存操作数由变量名或者含有变量地址的寄存器指定,变量名隐含指出了变量的地址,并指示cpu引用改地址内存处的内容。

    操作码:AT&T语法中指令操作码最后一个字符用来指明操作数的宽度,字符b,w和l分别制定byte,word和long类型的操作数。如果指令名没有带字符后缀,并且指定语句中不含内存操作数,那么as汇编器会根据寄存器操作数来尝试确定操作数宽度。操作码前缀用于修饰随后的操作码,他们用于重复字符串指令,提供区覆盖,执行总线锁定操作或者指定操作数和地址宽度。

    内存引用:AT&T语法的间接内存引用形式为section:disp(base, index, scale),其中base和index是32位的基寄存器和索引寄存器,disp是可选的偏移值,scale是比例因子,scale乘上index用来表示操作数地址,section为内存操作数指定的段寄存器。

    movl var, %eax                 #把内存地址var处的内容放入寄存器%eax
    movl %cs:var, %eax             #把代码段中的内存地址var处的内容放入%eax
    movb $0xa0, %es:(%ebx)         #把0xa0放入到es段的%ebx指定的偏移处
    movl $var, %eax                #把var的地址放入%eax
    movl array(%esi), %eax         #把array+%esi内存地址的内容放入eax
    movl (%ebx, %esi, 4), %eax     #把ebx+esi*4地址处的内容放到eax
    movl array(%ebx, %esi, 4), %eax#把array+ebx+esi*4地址的内容放到eax
    movl -4(%ebp), %eax            #把ebp-4地址处的内容放到eax

    指令跳转:跳转指令用于把执行点转移到程序的另外的位置执行,跳转的目的位置通常用一个标号来表示。jmp是无条件跳转,可分为直接跳转和间接跳转,直接跳转语句的写法是给出跳转目标处的标号,间接跳转语句的写法是使用*作为操作指示符的前缀字符。

    :段用于表示一个地址范围,它主要用来表示编译器生成的目标文件中的不同的信息区域。例如代码段,数据段,bss段。

    符号:符号有很多作用,可以用来命名对象,连接器通过符号执行链接操作,调试器利用符号进行调试。标号是后面接着一个冒号的符号,该符号用来表示代码当前的位置。特殊符号.用来表示汇编的当前位置。除了名字之外每个符号都有值和类型属性。符号的值通常是32位的,链接器会对未定义的符号值做特殊处理,如果未定义的符号值为0则表示该符号在此汇编程序中没有定义,链接器会尝试使用其他链接的文件来确定此符号值,

    as汇编器

    as汇编器的命令行格式为: as [选项] [-o objfile] [srcfile.s],如果没有指定输出文件名,会默认输出a.out文件。可以再as命令行上给出0个或多个输入文件名,as会按照从左到右的顺序读取这些文件中的内容,在命令行上的参数如果没有实际意义将会被当做输入文件名看待,如果命令行上没有任何文件名,那么as将会试图从终端读取输入文件内容。

    as的输出文件:由输入的汇编文件编译生成的二进制文件,目标文件最终作为连接器ld的输入文件。目标文件中包含汇编代码,协助ld产生可执行文件的信息,以及用于调试的符号信息。

    内联汇编

    内联汇编的基本格式为:

    asm("汇编语句"
          : 输出寄存器
          : 输入寄存器
          : 会被修改的寄存器)

    除了汇编语句是必须的的以外,其他若不使用都可以省略。其中asm是内联汇编的关键词,汇编语句用于编写汇编指令,输出寄存器表示当这段汇编语句执行完之后,哪些寄存器用于存放输出数据,输入寄存器表示开始执行代码时,制定某些寄存器中应该放入的输入值,会被修改的寄存器表示对列出的寄存器中的值进行了修改。

    常用的寄存器加载代码

    代码   说明 代码    说明
    a 使用寄存器eax m 使用内存地址
    b 使用寄存器ebx o 使用内存地址并且可以加偏移值
    c 使用寄存器ecx I 使用常数0~31
    d 使用寄存器edx J 使用常数0~63
    S 使用esi K 使用常数0~255
    D 使用edi L 使用常数0~65535
    q 使用动态分配字节可寻址寄存器 M 使用常数0~3
    r 使用任意动态分配寄存器 N 使用1字节常数
    g 使用通用有效地址 O 使用常数0~31
    A 使用eax和edx联合 = 输出操作数,输出值替换前值
    + 表示操作数可读可写 & 在使用完操作数之前内容会被修改

    在执行代码时,如果不希望汇编语句被gcc优化,需要在asm符号后面添加关键字volatile。关键字volatile也可以放在函数名前来修饰函数,用来通知gcc该函数不会返回。

  • 相关阅读:
    ORA02292:integrity constraint(xx) violated child record found 外键关联,无法删除记录
    自定义设置Ext.grid.gridPanel样式
    修改了grid的前3行的颜色为红色
    PLSQL导入导出表的正确步骤
    1000条数据写入到txt文件中,并且做了换行
    webservice 存根方式
    java日期时间
    extjs 页面打开时表格自动加载后台传来的json数据
    处理Clob数据(转)关于oracle中大对象处理的一些方法和实例
    44个提高博客影响力的方法
  • 原文地址:https://www.cnblogs.com/elvalad/p/4248375.html
Copyright © 2020-2023  润新知