ATT 汇编语法

在研华的pc104上使用看门狗要使用汇编。使用汇编来修改CMOS里面的参数。也就是内联汇编。
linux下gcc只支持ATT汇编。所以这儿有必要将ATT语法学习学习。以后需要的时候翻出来温习温习。

1,操作数的长度
         操作数的长度用加在指令后的符号表示 b(byte, 8-bit), w(word, 16-bits), l(long, 32-
bits),如“movb %al, %bl”,“movw %ax, %bx”,“movl %eax, %ebx ”。
        如果没有指定操作数长度的话,编译器将按照目标操作数的长度来设置。比如指令 
“mov %ax, %bx”,由于目标操作数 bx 的长度为 word,那么编译器将把此指令等同于
“ movw %ax, %bx”。同样道理,指令“mov $4, %ebx”等同于指令“movl $4, %ebx”,“push
%al” 等同于“pushb %al”。对于没有指定操作数长度,但编译器又无法猜测的指令,编
译器将会报错,比如指令“push $4

2. 立即数
使用立即数,要在数前面加符号$, 如“movl $0x04, %ebx”
或者:
para = 0x04
movl $para, %ebx

3.寄存器引用
引用寄存器要在寄存器号前加百分号%,如“movl %eax, %ebx”。
80386 有如下寄存器:
8 个 32-bit t通用寄存器 %eax,%ebx,%ecx,%edx,%edi,%esi,%ebp,%esp;
8 个 16-bit 通用寄存器,它们事实上是上面 8 个 32-bit 寄存器的低 16 位:%ax,%bx,
%cx,%dx,%di,%si,%bp,%sp;
8 个 8-bit 通用寄存器:%ah,%al,%bh,%bl,%ch,%cl,%dh,%dl。它们事实上是
寄存器%ax,%bx,%cx,%dx 的高 8 位和低 8 位;

但有的有特殊的用途:AX为累加器,CX为计数器,BX,BP为基址寄存器,SI,DI为变址寄存器,BP还可以是基指针,SP为堆栈指针。

6 个段寄存器:%cs(code),%ds(data),%ss(stack), %es,%fs,%gs;
3 个控制寄存器:%cr0,%cr2,%cr3;
6 个 debug 寄存器:%db0,%db1,%db2,%db3,%db6,%db7;
2 个测试寄存器:%tr6,%tr7;
8 个浮点寄存器栈:%st(0),%st(1),%st(2),%st(3),%st(4),%st(5),%st(6),
%st(7).

4. 操作数顺序
操作数排列是从源(左)到目的(右),如“movl %eax(源), %ebx(目的)”

5, 符号常数
符号常数直接引用 如
value: .long 0x12a3f2de
movl value , %ebx
指令执行的结果是将常数 0x12a3f2de 装入寄存器 ebx。
引用符号地址在符号前加符号$, 如“movl $value, % ebx”则是将符号 value 的地址装入
寄存器 ebx。

6. 内存引用
Intel 语法的间接内存引用的格式为:
section:[base+index*scale+displacement]
而在 AT&T 语法中对应的形式为:
section:displacement(base,index,scale)
其 中 , base 和 index 是 任 意 的 32-bit base 和 index 寄 存 器 。 scale 可 以 取 值
1,2,4,8。如果不指定 scale 值,则默认值为 1。section 可以指定任意的段寄存器作
为段前 缀,默认的段寄存器在不同的情况下不一样。如果你在指令中指定了默认的段前缀
则编译器在目标代码中不会产生此段前缀代码。
下面是一些例子:
-4(%ebp) : base=%ebp , displacement=-4 , section 没 有 指 定 , 由 于 base
=%ebp,所以默认的 section=%ss,index,scale 没有指定,则 index 为 0。
foo(,%eax,4):index=%eax,scale=4,displacement=foo。其它域没有指定。这
里默认的 section=%ds。
foo(,1):这个表达式引用的是指针 foo 指向的地址所存放的值。注意这个表达式中没有
base 和 index,并且只有一个逗号,这是一种异常语法,但却合法。
%gs:foo:这个表达式引用的是放置于%gs 段里变量 foo 的值。
如果 call 和 jump 操作在操作数前指定前缀“ *”,则表示是一个绝对地址调用/跳转,也就
是说 jmp/call 指令指定的是一个绝对地址。如果没有指定"*",则操作数是一个相对地址。
任何指令如果其操作数是一个内存操作,则指令必须指定它的操作尺寸
(byte,word,long),也就是说必须带有指令后缀(b,w,l)。


1,内联汇编。
   两种内联汇编的格式。
         一、基本内联汇编的格式是
__asm__ __volatile__("Instruction List");
        二、带有 C/C++表达式的内联汇编格式为:
__asm__ __volatile__("Instruction List" : Output : Input : Clobber/Modify);

规则:
1,这 4 个部分都不是必须的,任何一个部分都可以为空。
2,如 果 Clobber/Modify 为 空 , 则 其 前 面 的 冒 号 (:) 必 须 省 略 。 比 如 __asm__("mov %
     %eax, %%ebx" : "=b"(foo) : "a"(inp) : ) 就 是 非 法 的 写 法 ; 而 __asm__("mov %
      %eax, %%ebx" : "=b"(foo) : "a"(inp) )则是正确的。
3,"Instruction List"中的寄存器写法要遵守相关规定,比如寄存器前必须使用两个百分号(%%),
      而不是像基本汇编格式一样在寄存器前只使用一个百分号(%)。比如 __asm__( " mov %%eax, %%ebx" : : );
      __asm__( " mov %%eax, %%ebx" : ) 和 __asm__( " mov %eax, %ebx" ) 都 是 正 确 的 写 法 , 而
      __asm__( " mov %eax, %ebx" : : );__asm__( " mov %eax, %ebx" : )和__asm__(
     " mov %%eax, %%ebx" )都是错误的写法。
4,区分一个内联汇编是基本格式的还是带有 C/C++表达式格式的,其规则在于在"Instruction List"后
     是否有冒号(:)的存在,如果没有则是基本格式的,否则,则是带有 C/C++表达式格式的。
5,ouput:
           例子:

int func(void)
{
 int b = -1;
 __asm__ __volatile__(
  "movl $2,%%eax"
  :"=a"(b)
 );
 printf("--------------->%d\n",b);
 return 0;
}

我们可以很清楚得看到这个输出操作由两部分组成:括号括住 的部分 (b)和引号引
住的部分"=a"。这两部分都是每一个输出操作必不可少的。其中括号里面的是c/c++
表达式,而且只能是左值表达式。而右值来自于引用部分。引号中的内容,被称作
“操作约束”(Operation Constraint),在这个例子中操作约束为"=a",它包含两个约束:
等号(=)和字母 a,其中等号(=)说明括号中左值表达式b是一个 Write-Only 的,只能够
被作为当前内联汇编的输入,而不能作为输入。而字母 a 是寄存器 EAX / AX / AL 的
简写,说明 cr0 的值要从 eax 寄存器中获取,也就是说b = eax。
6,input.
     理解了output,再来理解input很容易。
__asm__("movl %0, %%db7" : : "a" (cpu->db7));
括号里面的是c/c++表达式,可以是左值,也可以是右值。
引号里面的是寄存器。寄存器作为左值。

转自:http://blog.163.com/zhe_wang_2009/blog/static/1722821212012116996711/

时间: 2024-10-10 06:55:16

ATT 汇编语法的相关文章

ATT汇编简介

前言:汇编语言,对下取决于体系结构:对上取决于汇编器.在linux下,GCC编译出来的汇编默认为ATT语法的汇编,本文主要介绍ATT汇编:操作数长度.立即数表示方法,寄存器引用,操作数顺序,符号常量,内存引用等. 1,操作数的长度 操作数的长度用加在指令后的符号表示 b(byte, 8-bit), w(word, 16-bits), l(long, 32-bits),如"movb %al, %bl","movw %ax, %bx","movl %eax,

GCC内嵌AT&T汇编语法

一 基本语法 1 寄存器引用 引用寄存器要在寄存器号前加百分号%,如"movl %eax, %ebx". 80386有如下寄存器: 1.8个32-bit寄存器 %eax,%ebx,%ecx,%edx,%edi,%esi,%ebp,%esp: 2.8个16-bit寄存器,它们事实上是上面8个32-bit寄存器的低16位:%ax,%bx,%cx,%dx,%di,%si,%bp,%sp: 3.8个8-bit寄存器:%ah,%al,%bh,%bl,%ch,%cl,%dh,%dl.它们事实上是寄

AT&T汇编和Intel汇编语法主要区别

AT&T使用$表示立即操作数,而Intel的立即操作数是不需要界定的.因此,使用AT&T语法引用十进制值4时,使用$4,使用Intel语法时只需使用4.   AT&T在寄存器名称前加上前缀%,而Intel不这样做.因此,使用AT&T语法引用EAX寄存器写为%eax.   AT&T语法处理源和目标操作数时使用相反的顺序.把十进制值4传送给EAX寄存器,AT&T的语法是movl $4, %eax,而Intel语法是mov eax, 4.   AT&T语法

Linux下的AT&T语法(即GNU as 汇编语法)入门

http://blogold.chinaunix.net/u3/105209/showart_2085748.html 学习这么长时间,一直在C语言这一层面上钻研和打拼,日积月累,很多关于C的疑惑在书本和资料中都难以找到答案.程序员是追求完美的一个种群,其头 脑中哪怕是存在一点点的思维黑洞都会让其坐卧不宁.不久前在itput论坛上偶得<Computer Systems A Programmer's Perspective>(以下称CS.APP)这本经典好书,遂连夜拜读以求解惑.虽说书中没有能正

GNU风格 ARM汇编语法指南

汇编源程序一般用于系统最基本的初始化:初始化堆栈指针.设置页表.操作 ARM的协处理器等.这些初始化工作完成后就可以跳转到C代码main函数中执行. 1.  GNU汇编语言语句格式 任何Linux汇编行都是如下结构:[<label>:][<instruction or directive or pseudo-instruction>} @comment l         instruction为指令 l         directive为伪操作 l         pseudo

Linux下AT&amp;T汇编语法格式与Intel汇编语法格式异同

由于绝大多数的国内程序员以前只接触过Intel格式的汇编语言,很少或几乎没有接触过AT&T汇编语言,虽然这些汇编代码都是Intel风格的.但在Unix和Linux系统中,更多采用的还是AT&T格式,两者在语法格式上有着很大的不同,其实完全可以使用原来汇编的思路解决问题,只要掌握下面两者的不同: 一.在AT&T汇编格式中,寄存器名要加上' %'作为前缀:而在Intel汇编格式中,寄存器名不需要加前缀.例如: AT&T格式 Intel格式 pushl %eax push eax

GNU ARM汇编语法

http://wenku.baidu.com/view/812a698c84868762caaed55d.html?re=view ARM汇编源程序有两种风格: ARM官方推荐的风格,所有的指令都大写.常用在windows下的IDE中. GNU风格的汇编风格,所有的指令都小写.常用在与Linux相关的工具中. 注释符号: GNU arm汇编所采用的注释符号是@符号,同样c语言中的 // 和 /* */ 两种类型的注释方法在GNU arm汇编中也被支持. 宏定义: 在GNU arm汇编程序中可以使

arm汇编语法Demo

/************************************************************************* > File Name: inout.c > Author: zshh0604 > Mail: [email protected] > Created Time: Wed 10 Dec 2014 02:47:50 PM **********************************************************

ATT汇编与Intel汇编的区别,摘自《深入分析linux内核源码》一书

2.6.1 AT&T与Intel汇编语言的比较 我们知道,Linux是Unix家族的一员,尽管Linux的历史不长,但与其相关的很多事情都发源于Unix.就Linux所使用的386汇编语言而言,它也是起源于Unix.Unix最初是为PDP-11开发的,曾先后被移植到VAX及68000系列的处理器上,这些处理器上的汇编语言都采用的是AT&T的指令格式.当Unix被移植到i386时,自然也就采用了AT&T的汇编语言格式,而不是Intel的格式.尽管这两种汇编语言在语法上有一定的差异,但