编译as汇编语言程序
as [选项] [-o objfile] [srcfile.s]
其中objfile是as编译输出的目标文件名,srcfile.s是as的输入汇编语言程序名,如果没有 使用输出文件名,那么as会编译输入名称为a.out的默认目标文件
AS汇编语法
为了维持与gcc输出程序的兼容性,as汇编器使用AT&T的汇编语法(下面简称为AT&T语法)。这种语法与Intel汇编程序使用的语法(简称intel)语法很不一样,它们之间的主要区别有一下几点
AT&T 语法中立即操作数前面要加一个字符‘$’;寄存器操作数名前要加字符串百分号‘%’
;绝对跳转/调用(相对于程序计算器有关的跳转/调用)操作数前面要加星号’*’。而intel汇编语法均没有这些限制
AT&T语法与intel语法使用的源和目的操作数次序正好相反,AT&T的源和目的操作数是从左到右’源,目的’.例如Intel的语法‘ add exa,4’,对应 ‘addl $4,%eax‘
AT&T语法中内存操作数的长度(宽度)由操作码最有一个字符来确定,操作码后缀’b’,’w’,和‘l’ 分别指示内存引用宽度为8位字节(byte),16位字节(byte),和32位字节长(long),intel语法则通过在内存操作数前使用前缀 ‘byte prt’,’word ptr’,和’dword ptr’来达到同样目的,因此,intel的语法‘mov al,byte ptr foo’对应AT&T的语法’movb $foo,%al’
AT&T语法中立即形式的远跳转和远调用为‘l jump/call $section,$offset’ ,而intel 的是’jmp/call far section:offset’。
AT&T汇编器不提供对多代码程序端,UNIX类操作系统要求所有代码在一个段中
符号,语句,和常数
符号(Symbol)是由字符串组成的标识符,组成符号的有效数字符取自于大小写字符集,数字和三个字符‘_.$’。符号不允许用数字字符开始,并且大小写含义不同。在as汇编程序中符号没有长度限制,并且符号中所有字符都是有效的,符号使用其他字符(例如空格,换行符)或者文件的开始来界定开始和结束处。
语句(Statement)以换行符或者分割字符(“;”) 作为结束,文件最后语句必须以换行符作为结束,若在一行的最后使用反斜杠‘\’,(在换行符前),那么就可以让一条语句使用多行。当as读取到反斜杠加换行符时,就会忽略掉这两个字符。
语句由零个或多个标号(label)开始,后面可以跟随一个确定语句类型的关键符号。标号由符号后面跟随一个冒号(‘:’) 构成,关键符号确定了语句余下部分的语义。如果该关键符号以一个‘.’开始,那么当前语句就是一个汇编命令(或称为伪指令,指示符。如果关键符号以一个字母开始,那么当前语句就是一条汇编语言指令语句。
常数是一个数字,可分为字符常数和数字常数两类。字符常数还可分为字符串和单个字符;而数字常数可分为整数,大数和浮点数
字符串必须用双引号扩住,并且其中可以使用反斜杠‘\’ 来转义特俗字符。例如‘\\‘ 表示一个反斜杠字符,其中第一个反斜杠是转义指示字符,说明把第二个字符看作一个普通的反斜杠字符
汇编程序中使用单个字符常数时可以写成该字符前加一个单引号,例如“ ‘A ”表示值65,“ ’c ” 表示67
整数数字常数有四种表示方法,即使用‘0b’或‘0B’开始的二进制数(‘0-1’) ,以‘0’开始的八进制数’(0-7)’ ;以非‘0’数字开始的十进制数(‘0-9’)和使用‘0x’或‘0X’开头的十六进制数(0-9a-fA-F)。若要表述负数,只需在前面添加负号‘-’
大数( bignum) 是位数超过32位的二进制的数,其表示方法与整数的相同
指令语句,操作数和寻址
指令(Instructions)是cpu执行的操作,通常指令也称作操作码(Opcode);操作数(Operand)是指令操作的对象;而地址(Address)是指定数据在内存中的位置。指令语句是程序运行时刻执行一条的语句,它通常可包含四个组成部分:
标号(可选)
操作码(指令助记符)
操作数(由具体指令指定)
注释
一条指令语句可以含有0个或最多3个用逗号分开的操作数。对于具体有两个操作数的指令语句,第1个是源操作数,第二个是目的操作数,即指令操作结果保存在第二个操作数中
操作数可以是立即数(即值是常数值的表达式),寄存器(值在cpu的寄存器中)或内存(值在内存中),一个间接操作数(indirect operand)含有实际操作数值的地址值。AT&T语法通过在操作数前面加一个(‘*’)字符来指定一个简洁操作数。只有调转/调用指令才能使用间接操作数。
立即操作数前面需要加一个‘$’字符前缀
寄存器名前需要加一个‘%‘字符前缀
内存操作数由变量名或者含有变量地址的一个寄存器指定。变量名隐式指出了变量地址,并指示cpu引用该地址处内存的内容
指令操作前缀
操作码前缀用与修饰随后的操作码,它们作用于重复字符串的指令,提供区覆盖,执行总线锁定操作,或指定操作数和地址宽度,通常操作码前缀可用于一条没有操作数的指令独占一行并且必须直接位于所影响指令之前,但是最好与它修饰的指令放在同一行上。
内存引用
intel语法的间接内存引用方式,section:[base+index*scale+disp],对应AT&T语法的形式:section:disp(base, index,scale)其中base和index是可选的32位基寄存器和索引寄存器,disp是可选的偏移值。scale是比列因子,取值范围是1,2,4和8。scale其乘上索引index用来计算操作数地址。如果没有指定scale,则scale取默认值1.section为内存操作数指定可选的段寄存器。并且会覆盖操作数使用的当前默认段寄存器,请注意,如果指定的段覆盖寄存器与默认操作的寄存器相同,则as就不会为汇编的指令再输出相同的段前缀;
movl var ,%eax #把内存地址var处的内容放入寄存器%eax中 movl %cs:var,%eax #把代码段中内存地址var处的内容放入%eax中 movl $0x0a,%es:(%ebx) #把字节值0x0a保存到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中,使用默认段%ss movl foo(,%eax,4) %eax #把内存地址foo+eax*4处内容放入%eax中,使用默认段%ds
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 ggchzzz@163.com