at&t 汇编语法

1:寄存器引用引用寄存器要在寄存器号前加%,如 mov % eax, % ebx

2: 操作数顺序操作数排列是从源(左)到目的(右),如mov % eax(源), % ebx(目的)

3: 常数/立即数的格式 使用立即数,要在数前面加 $, 如 mov , % ebx          符号常数直接引用 如 mov value , % ebx (value是一常数,已在前面定义)引用符号地址在符号前加 $, 如 mov $value, % ebx (是将value的地址放到ebx中)
 

4:操作数的长度     操作数的长度用加在指令后的符号表示b(byte), w(word), l(long) 如 movw %ax,%bx


5:寻址方式    内存寻址可以用section:disp(base, index, scale) 表示,计算方法是 base + index*scale + disp, section在实模式下有用,保护模式下用线性地址,不用section。
例如:call *SYMBOL_NAME(sys_call_table)(,% eax,4),这是entry.S中的一句,对应应该是% eax*4 + sys_call_table, 在sys_call_table中找到相应系统调用的地址。
 

6、大部分指令的操作码都与Intel指令相同,只有下面几个是例外:
       movsSD       // movsx ,短到长,高位补符号位        movzSD       // movzx ,短到长,高位补0这里,S 是代表源操作数长度的后缀,D 是代表目的操作数长度的后缀。 movswl %ax, %ecx    // movsx ecx, ax         cbtw             // cbw ,将AL中的一个字节扩充为一个字(AX),AH是AL的符号位     cwtl             // cwde    ,将AX中的一个字扩充为一个双字(EAX),EAX的高位是AX的符号位           cwtd             // cwd    ,将AX中的一个字扩充为两个字(DX:AX)        cltd             // cdq ,将EAX中的一个双字扩充为两个双字


7、 操作码的前缀(如rep)要单独写一行,不要和它修饰的指令(如movsb、stosb)写在同一行上;

8、 内存间接寻址的格式不同      disp(base, index, scale)【at&t】     [base + index*scale + disp]【intel】                                         
                                           movl    4(%ebp), %eax               // mov eax, [ebp+4]                                                                                        addl    (%eax,%eax,4), %ecx         // add ecx, [eax + eax*4]                                                                                                                 movb    $4, %fs:(%eax)              // mov fs:eax, 4
movl    _array(,%eax,4), %eax       // mov eax, [4*eax + array]

9、 局部标号可以用数字,而且可以重复。在以这些标号为目的的转移指令上,标号要带上后缀,b表示向前,f表示向后。绝对跳转/调用指令中的内存操作数必须以'*'为前缀,否则gas总是认为是相对跳转/调用指令,而且gas汇编程序自动对跳转指令进行优化,总是使用尽可能小的跳转偏移量。如果8比特的偏移量无法满足要求的话,as会使用一个32位的偏移量,as汇编程序暂时还不支持16位的跳转偏移量,所以对跳转指令使用'addr16'前缀是无效的。还有一些跳转指令只支持8位的跳转偏移量,这些指令是:'jcxz','jecxz','loop','loopz','loope','loopnz''loopne'                    如果你在汇编中使用了这些指令,用gas的汇编可能会出错,因为gcc在编译过程中不产生这些指令,所以在c语言中不必担心这些问题。
 

10、 实模式下的语法与Intel指令语法基本相同;可以用上述格式的汇编单独写程序(有许多宏定义和它特有的文件格式),而后用gcc/gas将其汇编成目标代码。在linux中,这种形式的代码主要集中在启动部分。

11、还有一个比较特别的,就是gcc可以编译嵌入在c语言中的汇编段落。在Linux代码中很多地方都使用了这种形式的汇编语言,嵌入汇编程序的格式如下:

10、还有一个比较特别的,就是gcc可以编译嵌入在c语言中的汇编段落。在Linux代码中很多地方都使用了这种形式的汇编语言,嵌入汇编程序的格式如下:
__asm__ __volatile__ (
asm statements
: outputs
: inputs
: registers-modified
);
asm statements是一组AT&T格式的汇编语言语句,每个语句一行,由/n分隔各行。所有的语句都被包裹在一对双引号内。其中使用的寄存器前面要加两个%%做前缀;转移指令多是局部转移,因此多使用数字标号。
inputs指明程序的输入参数,每个输入参数都括在一对圆括号内,各参数用逗号分开。每个参数前加一个用双引号括起来的标志,告诉编译器把该参数装入到何处。可用的标志有:“g”:让编译器决定如何装入它;“a”:装入到ax/eax;“b”:装入到bx/ebx;“c”:装入到cx/ecx;“d”:装入到dx/edx;“D”:装入到di/edi;“S”:装入到si/esi;“q”:a、b、c、d寄存器等;“r”:任一通用寄存器;“i”:整立即数;“p”:有效内存地址;“=”:输出;“+”:既是输入又是输出;“&”:改变其值之前写;“%”:与下一个操作数之间可互换;“#”:忽略其后的字符,直到逗号;“*”:当优先选择寄存器时,忽略下面的字符;“0~9”:指定一个操作数,它既做输入又做输出。通常用“g”。
outputs指明程序的输出位置,通常是变量。每个输出变量都括在一对圆括号内,各个输出变量间用逗号隔开。每个输出变量前加一个标志,告诉编译器从何处输出。可用的标志与输入参数用的标志相同,只是前面加“=”。如“=g”。输出操作数必须是左值,而且必须是只写的。如果一个操作数即做输出又做输入,那么必须将它们分开:一个只写操作数,一个输入操作数。输入操作数前加一个数字限制(0~9),指出输出操作数的序号,告诉编译器它们必须在同一个物理位置。两个操作数可以是同一个表达式,也可以是不同的表达式。
registers-modified告诉编译器程序中将要修改的寄存器。每个寄存器都用双引号括起来,并用逗号隔开。如“ax”。如果汇编程序中引用了某个特定的硬件寄存器,就应该在此处列出这些寄存器,以告诉编译器这些寄存器的值被改变了。如果汇编程序中用某种不可预测的方式修改了内存,应该在此处加上“memory”。这样以来,在整个汇编程序中,编译器就不会把它的值缓存在寄存器中了。
__volatile__是可选的,它防止编译器修改该段汇编语句(重排序、重组、删除等)。
输入参数和输出变量按顺序编号,先输出后输入,编号从0开始。程序中用编号代表输入参数和输出变量(加%做前缀)。
输入、输出、寄存器部分都可有可无。如有,顺序不能变;如无,应保留“:”,除非不引起二意性。

 

看一个在C语言中使用at&t的嵌入汇编程序的例子,c语言中的3个int变量,一般会是三个内存地址。每个操作数的长度则要根据操作系统和编译器来决定,一般32位操作系统为32位,则每个操作数占用4个字节:
int i=0, j=1, k=0;
__asm__ __volatile__("
    pushl %%eax/n                 //asm statement
    movl %1, %%eax/n              //asm statement
    addl %2, %%eax/n              //asm statement
    movl %%eax, %0/n              //...
    popl %%eax"                   //...
: "=g" (k)                     //outputs                                                     
: "g" (i), "g" (j)             //inputs
: "ax", "memory"               //registers modified
);     
按照参数编号原则输出参数参数k为%0,输入参数i和j依次为%1和%2。值得注意的是输出和输入标志都使用了"g",所以我们不必关心这些参数究竟是使用了寄存器还是内存操作数,编译器自己会决定。







    









 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值