3.2 GUN as汇编(本文内容大部分引用原文,非原创)


  as86汇编仅仅用于编译内核中的boot/bootsect.s引导扇区程序和实模式下的设置程序boot/setup.s。内核中其余所有汇编语言程序(包括C语言产生的汇编程序)均使用gas来编译,并与C语言程序编译产生的模块链接。

3.2.2 GUN汇编语法与INTEL汇编语法的主要区别:

  *AT&T语法(即GUN汇编语法)中立即操作数前面要加一个字符'$';寄存器操作数前面要加字符百分号'%';绝对跳转/调用(相对于与程序计数器有关的跳转/调用)操作数前面要加星号'*'。而intel汇编语法没有这些限制。

  *AT&T语法与intel语法使用的源和目的操作数次序正好相反。例如:AT&T语句 “addl $4, %eax” 是将4和eax寄存器中的值相加,结果保存在eax寄存器中,而在intel中表示为"add eax, 4"。

  *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"。

  *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读到反斜杠加换行符时,就会忽略掉这两个字符。

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

3.2.3 指令语句、操作数和寻址

是CPU执行的操作,通常指令也称作操作码(Opcode);

是指令操作的对象;

是指定数据在内存中的位置。

指令操作码的命名

、或。通常操作码前缀可以作为一条没有操作数的指令独占一行并且直接位于所影响指令之前,最好与它修饰的指令在同一行上。例如串扫描指令"scas"使用前缀执行重复操作:repne scas %es:(%edi), %al。

用于协助编译器和程序员临时使用名称。在一个程序中共有10个局部符号名("0"..."9")可供重复使用。为了定义一个局部符号,需要写出形如"N:"的标号(N代表任意数字)。若是引用前面最近定义的这个符号,需要写成"Nb";若是引用下一个定义局部符号,则需要写成"Nf"(b-backwards,f-forwards)。局部标号在使用方面没有限制,但是在任何时候只能向前/向后引用最远10个局部标号。

 符号属性

除了名字以外,每个符号都有“值”和“类型”属性。根据输出的格式不同,符号也可以具有辅助属性。如果不定义就使用一个符号,as会假设其所有属性均为0。这就表示该符号是一个外部定义的符号。

符号的值通常是32位的。对于标出text、data、bss或absolute区中的一个位置符号,其值是从区开始处到标号的地址值。对于text、data和bss区,一个符号的值通常会在链接过程中由于ld改变区的基地址而变化,absolute区中的符号的值不会改变。

ld会对未定义的符号的值进行特殊处理。如果未定义的符号的值为0,则表示该符号在汇编源程序中没有定义,ld会尝试根据其他链接的文件来确定它的值。在程序中使用了一个符号但没有对符号进行定义,就会产生这样的符号。如果未定义的符号的值不为0,那么该符号就表示是.comm公共声明的需要保留的公共存储空间字节长度。符号指向该存储空间的第一个地址处。

符号的类型属性含有用于链接器和调试器的重要定位信息、指示符号是外部的标志以及一些其他可选信息。

3.2.6 as汇编命令

汇编命令是指示汇编器操作方式的伪指令。汇编命令用于要求汇编器为变量分配空间、确定程序开始地址、指定当前汇编的区、修改位置计数器的值等。所有汇编命令的名称都以"."开始,其余是字符,并且大小写无关。但是通常都使用小写字符。

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

  .align是存储器对齐汇编命令,用于在当前子区中把位置计数器的值设置(增加)到下一个指定的存储边界处。第一个绝对值表达式abs-expr1指定要求的边界对齐值。对于使用a.out格式目标文件的80x86系统,该表达式的值是位置计数器值增加后其二进制值最右边0值位的个数,即是2的次方值。例如,".align 3"就表示把位置计数器的值增加到8的倍数上。如果位置计数器的值本身就是8的倍数,则无需改变。但是对于使用ELF格式的80x86系统,该表达式的值直接就是要求对齐的字节数。例如,".align 8"就是把位置计数器增加到8的倍数上。

  第二个表达式给出用于对齐而填充的字节值。该表达式可以省略,若省略,填充的字节值是0。第三个可选表达式abs-expr3用于指示对齐操作允许跳过的最大字节数。如果对齐操作要求跳过的字节数大于这个最大值,那么该对齐操作就被取消。

相关内容