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, %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 位;
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++表达式,可以是左值,也可以是右值。
引号里面的是寄存器。寄存器作为左值。
ATT 汇编语法的更多相关文章
- GNU for x86汇编语法
作者:冯老师,华清远见嵌入式学院讲师. 译自“Using as The GNU Assembler January 1994”. 参考Tornado随机文档“GNU Toolkit User's Gu ...
- AT&T 和 Intel 汇编语法的主要区别
转自AT&T 和 Intel 汇编语法的主要区别 作为一个爱折腾的大好青年,补番之余还要补一些 Linux 下的基础,比如 GDB 的正确使用方法.但无论是看 gdb 还是 gcc -S 里的 ...
- linux-0.11 内核源码学习笔记一(嵌入式汇编语法及使用)
linux内核源码虽然是用C写的,不过其中有很多用嵌入式汇编直接操作底层硬件的“宏函数”,要想顺利的理解内核理论和具体实现逻辑,学会看嵌入式汇编是必修课,下面内容是学习过程中的笔记:当做回顾时的参考. ...
- [中英对照]INTEL与AT&T汇编语法对比
本文首先对文章Intel and AT&T Syntax做一个中英文对照翻译,然后给出一个简单的例子,再用gdb反汇编后,对INTEL与AT&T的汇编语法进行对照从而加深理解. Int ...
- 4.简单的 GNU 汇编语法
芯片启动时很多设备没有初始化,需要汇编语言进行准备. 简单的GNU汇编语法: 1 label: instruction @ comment label :标号,类似于外号,为所在位置做标号,可以通过这 ...
- GNU风格 ARM汇编语法指南
汇编源程序一般用于系统最基本的初始化:初始化堆栈指针.设置页表.操作 ARM的协处理器等.这些初始化工作完成后就可以跳转到C代码main函数中执行. 1. GNU汇编语言语句格式 任何Linux汇编 ...
- GNU风格 汇编语法总结(转)
转载自:http://blog.sina.com.cn/s/blog_78d30f6b0101713r.html 汇编源程序一般用于系统最基本的初始化:初始化堆栈指针.设置页表.操作 ARM的协处理器 ...
- ARM linux常用汇编语法
汇编语言每行的语法: lable: instruction ; comment 段操作: .section 格式: .section 段名 [标志] [标志]可以 ...
- GNU风格 ARM汇编语法5
. GNU汇编程序中的常数 <>十进制数以非0数字开头,如:123和9876: <>二进制数以0b开头,其中字母也可以为大写: <>八进制数以0开始,如:,: &l ...
随机推荐
- Oracle多个服务各代表什么作用(转)
在Windows 操作系统下安装Oracle 9i时会安装很多服务——并且其中一些配置为在Windows 启动时启动.在Oracle 运行在Windows 下时,它会消耗很多资源,并且有些服务可能我们 ...
- C++的那些事:流与IO类
1.流的概念 "流"就是"流动",是物质从一处向另一处流动的过程,比如我们能感知到的水流.C++的流是指信息从外部输入设备(如键盘和磁盘)向计算机内部(即内存) ...
- SU suspecfk命令学习
用suplane生成平面,并查看其FK谱, 水平反射界面经FK变换后,波数为0, 正好处于临界,乃奎斯特频率, 有空间假频, Over,不足之处,欢迎批评指正.
- Visual Studio提示Bonjour backend初始化失败
Visual Studio提示Bonjour backend初始化失败 错误信息:The Bonjour backend failed to initialize, automatic Mac Bui ...
- 水题 Codeforces Round #302 (Div. 2) A Set of Strings
题目传送门 /* 题意:一个字符串分割成k段,每段开头字母不相同 水题:记录每个字母出现的次数,每一次分割把首字母的次数降为0,最后一段直接全部输出 */ #include <cstdio> ...
- 实践1-qq邮箱主页
纯html的网页 采用table分割板块进行布局 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...
- POJ3250 Bad Hair Day(单调栈)
题目大概就是给一个序列,问每个数右边有几个连续且小于该数的数. 用单调递减栈搞搞就是了. #include<cstdio> #include<cstring> using na ...
- POJ2407 Relatives(欧拉函数)
题目问有多少个小于n的正整数与n互质. 这个可以用容斥原理来解HDU4135.事实上这道题就是求欧拉函数$φ(n)$. $$φ(n)=n(1-1/p_1)(1-1/p_2)\dots(1-1/p_m) ...
- BZOJ3867 : Nice boat
每个点最多被修改$O(\log n)$次,线段树记录区间最值暴力更新. #include<cstdio> #define N 262145 int T,n,m,i,op,c,d,p,s[N ...
- BZOJ4012 [HNOI2015]开店
Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...