Chinaunix首页 | 论坛 | 博客
  • 博客访问: 21583
  • 博文数量: 7
  • 博客积分: 267
  • 博客等级: 入伍新兵
  • 技术积分: 110
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-08 12:58
文章分类
文章存档

2012年(7)

我的朋友

分类: LINUX

2012-04-10 20:14:28

GNU as汇编:

  内核中其余所有汇编程序(包括C语言产生的汇编程序)均使用gas编译。

  由于操作系统许多关键代码要求有很高的执行速度和效率,因此在一个操作系统源代码中通常就会包含大约10%左右的起关键作用的汇编语言程序量。

  在编译C语言程序时,GNU gcc编译器会首先输出一个作为中间结果的as汇编语言文件,然后gcc会调用as汇编器把这个临时汇编语言程序编译成目标文件。


编译as汇编语言程序:

  命令行格式:

as [选项] [-o objfile] [srcfile.s ...]

  如果没有指定objfile,那么as会编译输出a.out这个默认目标文件。

  srcfile.s文件名的放置次序与编译结果密切相关。程序的源代码是所有文件按次序组合的结果,每次运行as编译器,它只编译一个源程序。

  如果没有给出srcfile.s,那么as会从标准输入中读取输入文件内容,按Ctrl-D结束输入。


as汇编语法:

  为了与gcc输出汇编程序的兼容性,as编译器使用AT&T系统V的汇编语法。这种语法与Intel汇编程序的语法很不一样:

  1、AT&T语法中立即操作数前面要加上字符"$";寄存器操作数名前要加字符"%";绝对跳转/调用操作数前加"*"。而Intel汇编语法没有这些限制。

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

  3、AT&T语法中内存操作数的长度(宽度)由操作码最后一个字符来确定,操作码后缀"b"、"w"、"l"分别指示内存引用宽度为8位字节(byte)、16位字(word)、32位长字(long)。Intel语法则通过在内存操作数前使用前缀"byte ptr"、"word ptr"、"dword ptr"来达到同样的目的。因此Intel语句中的"mov al, byte ptr foo"对应于AT&T语句"movb $foo, %al"。

  4、AT&T语法中立即形式的远跳转和远调用为"ljmp/lcall $section, $offset",而Intel的是"jmp/call far section:offset"。同样AT&T语法中远返回指令"lret $stack-adjust"对应Intel的"ret far stack-adjust"。

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

汇编程序预处理:

  1、调整并删除多余的空格字符和制表符。

  2、删除所有注释语句并且使用单个空格或一些换行符替换它们。

  3、把字符常数转换为对应的数值。

  该功能不会对宏定义进行处理,也没有处理文件包含的功能。如果需要,可以将文件名改为大写后缀".S",让as使用gcc的CPP预处理功能。

  由于as除了使用C语言的"/*...*/"注释语句以外,还使用"#"作为单行注释开始字符,因此若在汇编之前不对程序执行预处理,那么程序中包含的所有以"#"开头的指示符或命令均会被当做注释部分。

符号、语句和常数:

  符号:由字符组成,包括大小写字符、数字、"_.$"。不允许以数字开头,大小写敏感。

  语句:以换行符或者行分割字符";"作为结束。"\"加上换行符,可以让一个语句多行。

  标号:符号后面跟一个":"。

  关键符号:以"."开始,那么是一个汇编命令(伪指令);以字母开始,是一个汇编指令语句。

  一条语句通用格式:

clip_image001

  常数:一个数字,分为字符常数(字符串和单个字符)和数字常数(整数、大数和浮点数)。

  字符串:用双引号括住,可以用\表示转义字符。反斜杠后是其他字符,那么反斜杠不起作用,as发出警告。

clip_image002

  整数数字常数:

1、以"0b"或"0B"开头的二进制数。

2、以"0"开头的八进制数。

3、以非0数字开始的十进制数。

4、以"0x"或"0X"开始的十六进制数。

负数前面添加"-"。

  大数(Bignum):位数超过32位二进制位的数。

  浮点数:与C语言基本一样,内核很少使用浮点数。

指令语句、操作数与寻址:

  指令:CPU执行的操作,通常指令称为操作码(Opcode)。

  操作数(Operand):指令的操作对象。

  地址:指定数据在内存中的位置。

  指令语句:程序运行时刻执行的一条语句,通常包括4个部分:

1、标号(可选)。

2、操作码(指令助记符)。

3、操作数(由具体指令指定)。

4、注释。

  一条指令语句可以含有0到3个用逗号分开的操作数。对于具有两个操作数的指令语句,第1个是源操作数,第2个是目的操作数。

  操作数可以是立即数、寄存器、内存。一个间接操作数含有实际操作数值的地址值。AT&T语法通过在操作数前加"*"来指定一个间接操作数。只有调转/调用指令才能使用间接操作数。跳转指令说明:

1、立即数前加"$"。

2、寄存器名前加"%"。

3、内存操作数由变量名或者含有变量地址的一个寄存器指定。

指令操作码的命名:

  AT&T语法中,指令操作码名称最后一个字符用来指明操作数的宽度。

  字符"b"、"w"、"l"分别指定byte、word、long类型的操作数。

  如果指令名称没有带这样的字符后缀,并且指令语句中不含操作数,那么as就会根据目的寄存器操作数来尝试确定操作数宽度。例如"mov %ax, %bx"等价于"movw %ax, %bx"。

  AT&T与Intel语法中几乎所有指令操作码的名称都相同。

  例外:符号扩展和零扩展指令需要两个宽度"movs..."和"movz...",从byte到long的符号扩展为"movsbl ..."。

clip_image003

阅读(779) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~