AT&T汇编简介

时间:2022-07-01 02:03:12

AT&T汇编简介

Intel 386汇编与AT&T区别

AT&T语法与Intel汇编程序使用的语法很不一样,他们之间的主要区别有以下几点:

  • AT&T语法中立即操作数前面要加一个字符$,寄存器操作数前要加%;绝对跳转操作数前面要加星号*。而Intel汇编语法没有这些限制

  • AT&T语法与Intel语法使用的源和目的操作数次序正好相反。AT&T的源和目的操作数是从左到右。例如Intel的语句add eax, 4对于AT&T的add $4, %eax

  • AT&T语法中内存操作数的长度(宽度)由操作码最后一个字符来确定。操作码后缀b、w、l分别指示内存引用宽度魏8位字节(byte)、16位字(word)和32位长字(long)。Intel语法则通过在内存操作数前使用前缀byte ptrword ptrdword 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

  • 间接寻址的一般格式,两者区别如下:

    • SecTION:[BASE + INDEX * SCALE + DISP] (Intel格式)
    • SECTION:disp(base, index, scale) (AT&T格式)

    这种寻址方式常常用于在数据结构数组中访问特定元素内的一个字段,base为数组的起始地址,scale为每个数组元素的大小,index为下标。如果数组元素是数据结构,则disp为具体字段在结构中的偏移。

  • AT&T汇编器不提供对多代码段程序的支持,类UNIX操作系统要求所有代码在一个段中

现代的汇编工具吸收了C语言预处理的功能,在汇编之前加上了一趟预处理,而预处理之前的文件则已.S为后缀。此类.S文件也和C程序一样,可以使用#include、#ifdef等等。对于.s文件则不回进行预处理。

AT&T汇编基础

符号、语句、常数

符号是由字符组成的标识符,包括大小写字符集、数字和三个字符_.$。符号不允许用数字字符开始,并且大小写含义不同。

语句以换行符或者行分割字符;作为结束。文件最后语句必须以换行符作为结束

语句由零个或多个标号(Label)开始,后面可以跟随一个确定语句类型的关键符号。标号由符号后面跟随一个冒号:构成。关键符号确定了语句余下部分的语义。如果该关键符号以一个.开始,那么当前语句就是一个汇编命令(或称为伪指令、指示符)。如果关键符号以一个字母开始,那么当前语句就是一条汇编语言指令语句。因此一条语句的通用格式为:

标号: 汇编命令  注释部分(可选)
或
标号: 指令助记符  操作数1, 操作数2     注释部分(可选)

常数是一个数字,可分为字符常数和数字常数两类。字符常数还可分为字符串和单个字符;数字常数分为整数和浮点数。

指令语句、操作数和寻址

一条指令语句可以含有0个或最多3个用逗号分开的操作数。对于具有两个操作数的指令语句,第1个是源操作数,第2个是目的操作数,指令操作结果保存在目的操作数中。

操作数可以是立即数、寄存器或内存。一个间接操作数含有实际操作数的地址值。AT&T语法通过在操作数前加一个*字符来指定一个间接操作数。

  • 立即操作数加$前缀
  • 寄存器名前需要加%前缀
  • 内存操作数由变量名或者含有变量地址的一个寄存器指定。变量名隐含指出了变量的地址,并指示CPU引用该地址处内存的内容

内存引用

mov var, %eax               #把内存地址var处的内容放入寄存器eax中

mov %cs:var, %eax           #把代码段中内存地址var处的内容放入寄存器eax中

movb $0x0a, %es:(%ebx)      #字节值0x0a放入到es段偏移ebx中

movl $var, %eax             #var地址放入eax

movl array(%esi), %eax      #array + esi地址的内容放入到eax

movl (%ebx, %esi, 4), %eax  #ebx + 4 * esi地址内容放入eax

movl array(%ebx, %esi, 4), %eax  #array + ebx + 4 * esi地址内容放入eax

movl -4(%ebp), %eax         #ebp - 4地址内容放入eax

movl foo(, %eax, 5), %eax   #foo + 5 * eax地址内容放入eax

跳转指令

直接跳转和间接跳转,条件跳转只能是直接跳转,对于直接跳转,跳转的目标地址作为指令的一部分直接编码进跳转指令中;间接跳转,跳转的目的位置来自于某个寄存器或某个内存位置中。

jmp *%eax          #间接跳转,eax内容是跳转的目标位置 
jmp *(%eax)        #间接跳转,eax地址内容是跳转的目标位置

汇编命令

  • .align abs-expr1, abs-expr2, abs-expr3

    • 第一个代表对其字节数(2 ^ expr1)
    • abs-expr2代表填充字节值
    • abs-expr3代表对其操作允许跳过的最大字节数,如果超过这个值,对其操作取消
  • .ascii "string"
    从位置计数器当前位置为字符串分配空间并存储字符串。.ascii "Hello World", "My Assembler"

  • .asciz "string"
    该汇编命令与.ascii类似,但是每个字符串后面会自动添加NULL字符

  • .byte expressions
    该汇编命令定义定义0个或多个用逗号分开的自己值。每个表达式的值是一个字节

  • .comm symbol,length
    在bss区中声明一个命名的公共区域。在ld连接过程中,某个目标文件中的一个公共符号会与其他目标文件中同名的公共符号合并。

  • .data subsection
    通知编译器把随后的语句汇编到编号为subsection的data子区中。

  • .global symbol(.globl symbol)
    使得链接器ld能看见符号symbol。如果在文件中定义了symbol,那么他的值能被链接过程中的其它目标文件使用。

  • .org new_lc,fill
    这个汇编命令会把当前区的位置计数器设置为new_lc。fill代表跳过的填充自己数。位置计数器都是同区的。