王朝网络
分享
 
 
 

at&a语法和intel语法

王朝other·作者佚名  2006-05-17
宽屏版  字体: |||超大  

学习linux内核少不了要读at&t的汇编,这个对大多数使用intel汇编的人是一个不幸的消息,要另起炉灶。什么?你不是学得intel汇编?你是不是中国学生?记得我们有门课是学<intel 8086/8088汇编语言>,学得挺感兴趣,窃以为这个就是学电脑的最高境界。当时怎么也没人说这个是intel汇编语言格式,还有个什么at&t格式..

不扯远了,这两者之间还是有章可循的,我觉得要注意的是转移指令,这个要仔细琢磨一下才看的明白。内存间接寻址的格式看起来也比较费劲,其他的东西是到是可以看一次就明白的。如果您有耐心,希望查看更权威的资料建议您查阅as.info和gcc.info,实际上,严格是说,gas只是众多遵循at&t格式汇编程序中的一个实现特例,而你寻找的汇编语言规则,只与你使用的汇编程序和编译器有关。

1、 指令操作数的顺序是先源后目的,与Intel指令的先目的后源的顺序相反;

2、 寄存器操作数总是以'%'作为前缀。

3、 立即数前加前缀$;

4、 操作码加后缀以指明操作数的长度,这些后缀有b(8位)、w(16位)、l(32位);

例:

AT&T Intel

moww %bx, %ax // mov ax, bx

xorl %eax, %eax // xor eax, eax

movw $1, %ax // mov ax,1

movb X, %ah // mov ah, byte ptr X

movw X, %ax // mov ax, word ptr X

movl X, %eax // mov eax, X

如果操作码中没有后缀来指定操作数的长度,并且该指令中没有内存操作数,gas会

根据指令中指定的寄存器操作数补上相应的后缀字符。所以,下面两个指令是等价的(这是Gas的特性,而真正的AT&T的Unix汇编程序会将将没有字长后缀的指令的操作数字长全部当作32位):

在linux中,因为是使用gas进行汇编的,故此

mov %ax,%bx

等价于

movw %ax,%bx

5、 大部分指令的操作码都与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)

// DX是AX的符号位

cltd // cdq ,将EAX中的一个双字扩充为两个双字

// (EDX:EAX),EDX是EAX的符号位

lcall $S,$O // call far S:O

ljmp $S,$O // jmp far S:O

lret $V // ret far V

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

7、 内存间接寻址的格式不同

AT&T Intel

disp(base, index, scale) [base + index*scale + disp]

例:

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]

movw _array(%ebx,%eax,4), %cx // mov cx, [ebx + 4*eax + array])

8、 局部标号可以用数字,而且可以重复。在以这些标号为目的的转移指令上,标号要带上后缀,b表示向前,f表示向后。

例:

orw %bx,%bx

jz 1f

1:

movl $0x101000,%eax

movl %eax,%cr3 /* set the page table pointer.. */

movl %cr0,%eax

orl $0x80000000,%eax

movl %eax,%cr0 /* ..and set paging (PG) bit */

jmp 1f /* flush the prefetch-queue */

1:

movl $1f,%eax

jmp *%eax /* make sure eip is relocated */

1:

绝对跳转/调用指令中的内存操作数必须以'*'为前缀,否则gas总是认为是相对跳转/调用指令,而且gas汇编程序自动对跳转指令进行优化,总是使用尽可能小的跳转偏移量。如果8比特的偏移量无法满足要求的话,as会使用一个32位的偏移量,as汇编程序暂时还不支持16位的跳转偏移量,所以对跳转指令使用'addr16'前缀是无效的。还有一些跳转指令只支持8位的跳转偏移量,这些指令是:

'jcxz','jecxz','loop','loopz','loope','loopnz''loopne'

如果你在汇编中使用了这些指令,用gas的汇编可能会出错,因为gcc在编译过程中不产生这些指令,所以在c语言中不必担心这些问题。

9、 实模式下的语法与Intel指令语法基本相同;可以用上述格式的汇编单独写程序(有许多宏定义和它特有的文件格式),而后用gcc/gas将其汇编成目标代码。在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",所以我们不必关心这些参数究竟是使用了寄存器还是内存操作数,编译器自己会决定。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有