gcc 与 汇编

gcc 只支持AT&T格式的汇编。
AT&T 386 汇编与intel格式的差异:
在intel格式中大多使用大写字母,而在AT&T格式中都使用小写字母
在AT&T格式中,寄存器名要加上%号作为前缀,而在intel格式中则不带前缀
在AT&T的386汇编语言中,指令的源操作数与目标操作数的顺序与在intel的386汇编语言中正好相反,
     在intel格式中是目标在前,源在后,而在AT&T格式中则是源在前,目标在后。
在AT&T格式中,访问指令的操作数大小由操作码名称的最后一个字母(也就是操作码的后缀)来决定,
用做操作码后缀的字母有b,w, 和l
而在intel格式中,则是在表示每村单元的操作数前面加上BYTE PTR,  WORD PTR 或DWORD PTR
如在intel 格式中:MOV AL, BYTE PTR FOO
而在AT&T格式中为 moveb FOO, %al
在AT&T格式中,直接操作数要加上$做为前缀,而在intel格式中则不带前缀,所以在intel格式中的PUSH 4
在AT&T格式中就变成了 pushl $4
在AT&T格式中,绝对转移或者调用指令jump/call的操作数要加上*做为前缀,而在intel格式中不带。
远程的转移指令和子程序调用指令的操作码名称,在AT&T格式中为ljump 和lcall 而在intel格式中,则为
JMP FAR 和 CALL FAR 。

间接寻址的一般格式两者区别如下:
section:disp (base, index,scale)
SECTION: [BASE+INDEX*SCALE+DISP]
注意在AT&T格式中隐含了所进行的计算,例如当SECTION 省略,
INDEX 和SCALE 也省略,BASE 为EBP,而DISP 为4时,表示如下:
[ebp-4]          intel格式
-4 (%ebp) AT&T格式
在在AT&T格式中如果只有一项base就可以省略逗号,否则不能省略,所以
(%ebp)就等于 (%ebp,,)进一步相当于(%ebp,0,0)
这种寻址方式常常用于在数据结构数组中访问特定元素内的一个字段,base 为数组的起始地址,sale为
每个数组元素的大小,index为下标,如果数组元素是数据结构,则disp相当于字段在结构中的位移。

gcc 中c 语言代码中嵌入汇编(gcc inline asm):
插入c 代码中的一个汇编语言代码片断可以分成四部分,以:号加以分隔,形式为指令部:输出部:输入部:损坏部
指令部是必须有的,其他部分视具体情况而省略。
在指令部,数字加上前缀%表示需要使用寄存器的样板操作数,可以使用的此类操作数的总数取决于具体cpu中通用寄存器的数量。
指令部用到了几个不同的这种操作数就说明有几个变量需要与寄存器结合。
输出部用以规定对输出变量,即目标操作数如何结合的约束条件,每个这样的条件称为一个约束,必要时,输出部中可以有多个
约束,互相以逗号分割,每个输出约束以=(或+)开头(表示write only),然后是一个字母表示对操作数类型的说明,然后是关于变量结合的约束。
输出部后面是输入部,输入约束的格式与输出约束相似,但不带=号(表示只可读),
约束条件字母:
约束 Input/Output  意义
r  I,O   表示使用一个通用寄存器,由GCC在%eax/%ax/%al, %ebx/%bx/%bl, %ecx/%cx/%cl, %edx/%dx/%dl中选取一个GCC认为合适的。
q  I,O   表示使用一个通用寄存器,和r的意义相同。
a  I,O   表示使用%eax / %ax / %al
b  I,O   表示使用%ebx / %bx / %bl
c  I,O   表示使用%ecx / %cx / %cl
d  I,O   表示使用%edx / %dx / %dl
D  I,O   表示使用%edi / %di
S  I,O   表示使用%esi / %si
f  I,O   表示使用浮点寄存器
t  I,O   表示使用第一个浮点寄存器
u  I,O   表示使用第二个浮点寄存器

示例代码(80386):
static inline int strncmp(const char *cs, const char* ct, size_t count)
{
 register int _res;
 int d0,d1,d2;
__asm__ __volatile__(
1........"1:/tdecl %3/n/t"
2........"js 2f/n/t"
3........"lodsb/n/t"
4........"scasb/n/t"
5........"jne 3f/n/t"
6........"testb %%al,%%al/n/t"
7........"jne 1b/n"
8........"2:/tsbb1 %%eax,%%eax/n/t"
9........"orb $1,%%al/n"
10......."4:"
:"=a" (_res), "=&S" (d0), "&D" (d1),  "=&c" (d2)
:"1" (cs), "2" (ct), "3" (count);
)
return _res;
}
输出部:_res使用寄存器eax,d0放在寄存器esi中,d1放在寄存器edi中 ,d2放在寄存器ecx中。
输出部总共使用四个寄存器%0,%1,%2,%3
输入部:cs使用和d0一样的寄存器esi,ct使用和d1一样的寄存器edi,ct使用和d2一样的寄存器ecx。
指令部:各条指令的用法参考 intel技术手册。

Intel x86 下 gcc汇编结果

06-04

GCC的汇编语言用的是AT&T的语法。rn rn 源文件:test.crn rn#include rn#include rn rnint swap(int *a, int *b)rnrn int c ;rn c = *a; rn *a = *b;rn *b = c;rn return c;rnrn rnint main(int argc, char *argv[])rnrn int a, b, c;rn a = 16; b = 32;rn c = swap(&a, &b);rn return 1;rnrn rn rn rn汇编结果: gcc -S test.crn rn .file "test.c"rn .textrn .align 2rn.globl swaprn .type swap,@functionrnswap:rn pushl %ebprn movl %esp, %ebprn subl $4, %esp 为整型局部变量c 在栈中分配空间rn movl 8(%ebp), %eax 取第一个参数arn movl (%eax), %eax 取a地址里的内容 *arn rnmovl %eax, -4(%ebp) 保存到局部变量c中rnmovl 8(%ebp), %edx 取第一个参数arnmovl 12(%ebp), %eax 取第二个参数 brn movl (%eax), %eax 保存*brn movl %eax, (%edx) 将*b 保存到 a的地址里(*a)rn movl 12(%ebp), %edx 再去参数brn movl -4(%ebp), %eax 将局部变量c的值(先已经是a的值)取出rn movl %eax, (%edx) 将这个指保存到b的地址里(*a)rn movl -4(%ebp), %eax 返回值c保存在eax中rn leave 等同于 movl %ebp, %esp; popl %ebp; rn retrn.Lfe1:rn .size swap,.Lfe1-swaprn .align 2rn.globl mainrn .type main,@functionrnmain:rn pushl %ebprn movl %esp, %ebprn subl $24, %esprn andl $-16, %esprn movl $0, %eaxrn subl %eax, %esprn movl $16, -4(%ebp)rn movl $32, -8(%ebp)rn subl $8, %esprn leal -8(%ebp), %eaxrn pushl %eaxrn leal -4(%ebp), %eaxrn pushl %eaxrn call swaprn addl $16, %esprn movl %eax, -12(%ebp) 将swap的返回值(在eax中),放到局部变量c中rn movl $1, %eax 将eax赋值为返回值 1rn leavern retrn.Lfe2:rn .size main,.Lfe2-mainrn .ident "GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"rn rn8(%ebp)是第一个参数 12(%ebp)是第二个参数rn rn-4(%ebp)是第一个局部变量rn rn函数返回值 保存在eax中rnrn原文地址:[url=http://blog.csdn.net/richardysteven/article/details/4195055][/url]

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试