以前看过一段时间,3天大鱼,2天晒网,现在也忘差不多了,但基本上也都知道什么意思,关于细节在这里写一下.
GNU汇编寻址:
+------------------------------+------------------------------------+
| Intel Code | AT&T Code |
+------------------------------+------------------------------------+
| mov eax,1 | movl $1,%eax |
| mov ebx,0ffh | movl $0xff,%ebx |
| int 80h | int $0x80 |
| mov ebx, eax | movl %eax, %ebx |
| mov eax,[ecx] | movl (%ecx),%eax |
| mov eax,[ebx+3] | movl 3(%ebx),%eax |
| mov eax,[ebx+20h] | movl 0x20(%ebx),%eax |
| add eax,[ebx+ecx*2h] | addl (%ebx,%ecx,0x2),%eax |
| lea eax,[ebx+ecx] | leal (%ebx,%ecx),%eax |
| sub eax,[ebx+ecx*4h-20h] | subl -0x20(%ebx,%ecx,0x4),%eax |
+------------------------------+------------------------------------+
GCC内联汇编:
内联汇编约束的意义,最主要在于帮助编译器来确定操作数的寻址方式.即asm应该在哪里去取这些操作数,或者把结果放到什么地方去.
常用操作数约束:
r: 任意寄存器 若对输入或者输出指定了这个约束条件,那么编译器就会把输入变量存储在一个寄存器中,或者会把输出保存到一个寄存器中去.第3个约束条件表示asm要用到%eax,编译器不应该用eax来存储有用的数据,否则eax里面的数据会被破坏.这里指定了b为输出操作数,但存在寄存器里面.所以,在asm程序段里面,会将b存在寄存器里面,但是在asm之外,编译器会将栈空间里面的b用寄存器里面的值更新.可以看到,在这里,输入和输出编译器使用了想同的寄存器,如果要强制使用不同的寄存器,可以将输出约束写为"=&r",加一个&.
{
int a=10, b;
__asm__ ("movl %1, %%eax\n\t" \
"movl %%eax, %0\n\t" \
:"=r" (b) \ /*output*/
:"r"(a) \ /*input*/
:"%eax" \ /*寄存器修饰*/
);
}
利用gcc -S 编译得到汇编程序如下,可以看的比较清楚:
pushl %ebp #保存ebp
movl %esp, %ebp #新的栈帧
subl $8, %esp #为a,b在栈里面分配8个字节的空间
movl $10, -4(%ebp) #a = 10
movl -4(%ebp), %edx #把a放到寄存器edx里面,r操作数约束的结果
#APP
movl %edx %eax
movl %eax %edx #可见编译器把输出也放在了edx里面
#NO_APP
movl %edx, %eax #多了一句废话
movl %eax, -8(%ebp) #在asm外更新b的值
leave
ret
q(a,b,c,d分别指定):表示寄存器为eax,ebx,ecx,edx之一
m:相应的操作数放在内存单元中
当操作数在内存中时,任何对操作数的操作都直接在内存中生效
S,D:要求使用寄存器esi或者edi
通常在字符串函数中会用到,因为字符串函数的使用频繁,所以在lib中都是使用汇编进行实现.
void strncpy(char *dst,char *src,int count) \
__asm__("cld\n\t" \ /*DF=0, 地址增加*/
"rep\n\t" \ /*将下一条指令执行%ecx次*/
"movsb" \
: \
:"S"(src), \
"D"(dst), \
"c"(count)\
编译后结果:
可以看到这里有对edi,esi的保护,到底是调用者保护寄存器,还是被调用者保护寄存器,这个对不同的寄存器有明确的说明,具体件上一部分.
strncpy:
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %esi
movl 12(%ebp), %esi
movl 8(%ebp), %edi
movl 16(%ebp), %ecx
#APP
cld
rep
movsb
#NO_APP
popl %esi
popl %edi
popl %ebp
ret
);
匹配约束: 在某些情况下,有些变量既要充当输入操作叔,又要充当输出操作数字.
__asm__("incl %1":"=a"(val):"0"(val));
在这个例子中,%eax既用做输入也用做输出,注意在输入位置的"0"表示:与第0个输出变量想同的约束,也就是说,将输出值val也存放在%eax中.
修饰寄存器的使用:
首先需要明确,ESI和EDI是不需要修饰的,因为他们本来就在asm的使用列表中,编译器假定asm一定会使用esi和edi,所以编译器不会把esi和edi用做其他用途.而如果我们使用了一个寄存器,而这个寄存器既不出现在输入列表中,也不出现在输出列表中,我们最好还是修饰一下.
例如:
#define memcpy(dst,src,count) \
__asm__("movl %0 %%ecx"
"up: lodsl\r\n" \ /*将esi里面的值放到eax里面去*/
"stosl\r\n" \
"loop up" \
: \
:"m"(count), \
"S"(src), \
"D"(dst), \
:"eax","ecx" \
);
编译后结果:
memcpy:
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %esi
movl 12(%ebp), %esi
movl 8(%ebp), %edi
#APP
movl 16(%ebp) %ecx
up: lodsl
stosl
loop up
#NO_APP
popl %esi
popl %edi
popl %ebp
ret
注意:%0,%1,%2与输入输出的匹配,按照最后约束条件里面出现的顺序,分别为0,1,2...,比如下程序,如果想
把a,b,c的值付给d,e,f,要这样写:
int main()
{
int a=10,b=12,c=33;
int d=1,e=2,f=3;
__asm__("movl %3, %%eax\n\t" \
"movl %4, %%ebx\n\t" \
"movl %5, %%ecx\n\t" \
"molv %%eax ,%0\n\t" \
"molv %%ebx ,%1\n\t" \
"molv %%ebx ,%2\n\t" \
:"=m"(d),"=m"(e),"=m"(f) \
:"m"(a),"m"(b),"m"(c) \
:"%eax","%ebx","%ecx" \
);
printf("a=%d\n, b=%d\n, c=%d\n, d=%d\n, e=%d\n, f=%d\n",a,b,c,d,e,f);
}
GNU汇编寻址:
+------------------------------+------------------------------------+
| Intel Code | AT&T Code |
+------------------------------+------------------------------------+
| mov eax,1 | movl $1,%eax |
| mov ebx,0ffh | movl $0xff,%ebx |
| int 80h | int $0x80 |
| mov ebx, eax | movl %eax, %ebx |
| mov eax,[ecx] | movl (%ecx),%eax |
| mov eax,[ebx+3] | movl 3(%ebx),%eax |
| mov eax,[ebx+20h] | movl 0x20(%ebx),%eax |
| add eax,[ebx+ecx*2h] | addl (%ebx,%ecx,0x2),%eax |
| lea eax,[ebx+ecx] | leal (%ebx,%ecx),%eax |
| sub eax,[ebx+ecx*4h-20h] | subl -0x20(%ebx,%ecx,0x4),%eax |
+------------------------------+------------------------------------+
GCC内联汇编:
内联汇编约束的意义,最主要在于帮助编译器来确定操作数的寻址方式.即asm应该在哪里去取这些操作数,或者把结果放到什么地方去.
常用操作数约束:
r: 任意寄存器 若对输入或者输出指定了这个约束条件,那么编译器就会把输入变量存储在一个寄存器中,或者会把输出保存到一个寄存器中去.第3个约束条件表示asm要用到%eax,编译器不应该用eax来存储有用的数据,否则eax里面的数据会被破坏.这里指定了b为输出操作数,但存在寄存器里面.所以,在asm程序段里面,会将b存在寄存器里面,但是在asm之外,编译器会将栈空间里面的b用寄存器里面的值更新.可以看到,在这里,输入和输出编译器使用了想同的寄存器,如果要强制使用不同的寄存器,可以将输出约束写为"=&r",加一个&.
{
int a=10, b;
__asm__ ("movl %1, %%eax\n\t" \
"movl %%eax, %0\n\t" \
:"=r" (b) \ /*output*/
:"r"(a) \ /*input*/
:"%eax" \ /*寄存器修饰*/
);
}
利用gcc -S 编译得到汇编程序如下,可以看的比较清楚:
pushl %ebp #保存ebp
movl %esp, %ebp #新的栈帧
subl $8, %esp #为a,b在栈里面分配8个字节的空间
movl $10, -4(%ebp) #a = 10
movl -4(%ebp), %edx #把a放到寄存器edx里面,r操作数约束的结果
#APP
movl %edx %eax
movl %eax %edx #可见编译器把输出也放在了edx里面
#NO_APP
movl %edx, %eax #多了一句废话
movl %eax, -8(%ebp) #在asm外更新b的值
leave
ret
q(a,b,c,d分别指定):表示寄存器为eax,ebx,ecx,edx之一
m:相应的操作数放在内存单元中
当操作数在内存中时,任何对操作数的操作都直接在内存中生效
S,D:要求使用寄存器esi或者edi
通常在字符串函数中会用到,因为字符串函数的使用频繁,所以在lib中都是使用汇编进行实现.
void strncpy(char *dst,char *src,int count) \
__asm__("cld\n\t" \ /*DF=0, 地址增加*/
"rep\n\t" \ /*将下一条指令执行%ecx次*/
"movsb" \
: \
:"S"(src), \
"D"(dst), \
"c"(count)\
编译后结果:
可以看到这里有对edi,esi的保护,到底是调用者保护寄存器,还是被调用者保护寄存器,这个对不同的寄存器有明确的说明,具体件上一部分.
strncpy:
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %esi
movl 12(%ebp), %esi
movl 8(%ebp), %edi
movl 16(%ebp), %ecx
#APP
cld
rep
movsb
#NO_APP
popl %esi
popl %edi
popl %ebp
ret
);
匹配约束: 在某些情况下,有些变量既要充当输入操作叔,又要充当输出操作数字.
__asm__("incl %1":"=a"(val):"0"(val));
在这个例子中,%eax既用做输入也用做输出,注意在输入位置的"0"表示:与第0个输出变量想同的约束,也就是说,将输出值val也存放在%eax中.
修饰寄存器的使用:
首先需要明确,ESI和EDI是不需要修饰的,因为他们本来就在asm的使用列表中,编译器假定asm一定会使用esi和edi,所以编译器不会把esi和edi用做其他用途.而如果我们使用了一个寄存器,而这个寄存器既不出现在输入列表中,也不出现在输出列表中,我们最好还是修饰一下.
例如:
#define memcpy(dst,src,count) \
__asm__("movl %0 %%ecx"
"up: lodsl\r\n" \ /*将esi里面的值放到eax里面去*/
"stosl\r\n" \
"loop up" \
: \
:"m"(count), \
"S"(src), \
"D"(dst), \
:"eax","ecx" \
);
编译后结果:
memcpy:
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %esi
movl 12(%ebp), %esi
movl 8(%ebp), %edi
#APP
movl 16(%ebp) %ecx
up: lodsl
stosl
loop up
#NO_APP
popl %esi
popl %edi
popl %ebp
ret
注意:%0,%1,%2与输入输出的匹配,按照最后约束条件里面出现的顺序,分别为0,1,2...,比如下程序,如果想
把a,b,c的值付给d,e,f,要这样写:
int main()
{
int a=10,b=12,c=33;
int d=1,e=2,f=3;
__asm__("movl %3, %%eax\n\t" \
"movl %4, %%ebx\n\t" \
"movl %5, %%ecx\n\t" \
"molv %%eax ,%0\n\t" \
"molv %%ebx ,%1\n\t" \
"molv %%ebx ,%2\n\t" \
:"=m"(d),"=m"(e),"=m"(f) \
:"m"(a),"m"(b),"m"(c) \
:"%eax","%ebx","%ecx" \
);
printf("a=%d\n, b=%d\n, c=%d\n, d=%d\n, e=%d\n, f=%d\n",a,b,c,d,e,f);
}
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/59615/showart_465060.html