gcc编译c语言中内嵌汇编
--AT&T and Intel 汇编语法对照
寄存器命名:
AT&T: %eax
Intel: eax
AT&T 语法源地址在左侧,目的地址在右侧与Intel 方式语法相反
将eax值传入ebx
AT&T: movl %eax, %ebx
Intel: mov ebx, eax
AT&T 语法在立即数前有前缀$.
AT&T: movl $0x0h, %eax
Intel: mov eax,0x0h
AT&T 语法在操作符后跟表示操作数类型的后缀b,w,l分别表示字节,字,双字,相当于伪操作符ptr,如果不加的话GAS会guess
AT&T: movw %ax, %bx
Intel: mov bx, ax
内存寻址方式
AT&T: immed32(basepointer,indexpointer,indexscale)
Intel: [basepointer + indexpointer*indexscale + immed32]
地址计算公式为:
immed32 + basepointer + indexpointer * indexscale
直接寻址
AT&T: _a
Intel: [_a]
间接寻址
AT&T: (%eax)
Intel: [eax]
相对寻址
AT&T: _variable(%eax)
Intel: [eax + _variable]
AT&T: _array(,%eax,4)
Intel: [eax*4 + array]
C 代码: *(p+1) p定义为char *
AT&T: 1(%eax) where eax has the value of p
Intel: [eax + 1]
结构体数组寻址,结构体长度为8,下标存于eax,结构体内偏移地址存于ebx,_array为结构体数组首地址
AT&T: _array(%ebx,%eax,8)
Intel: [ebx + eax*8 + _array]
函数内部实现交换
1、输入与输出变量相同
汇编代码部分标准的交换实现,输入部分用0寄存器表示"=r"(a)中所指定的寄存器即输入与输出变量相同
int main()
{ 804842c: mov 0xfffffff4(%ebp),%ecx
int a = 10, b = 0; 804842f: mov 0xfffffff0(%ebp),%edx
printf("before swap: a = %2d, b = %2d/n", a , b); 8048432: mov %ecx,%ebx
__asm__("nop; 8048434: mov %edx,%esi
movl %0, %%eax; 8048436: nop
movl %1, %0; 8048437: mov %ebx,%eax
movl %%eax, %1; 8048439: mov %esi,%ebx
nop;" 804843b: mov %eax,%esi
: 804843d: nop
"=r"(a), "=r"(b) 804843e: mov %ebx,%edx
: 8048440: mov %esi,%ecx
"0"(a), "1"(b) 8048442: mov %edx,%eax
: 8048444: mov %eax,0xfffffff4(%ebp)
"%eax" 8048447: mov %ecx,%eax
); 8048449: mov %eax,0xfffffff0(%ebp)
printf("after swap: a = %2d, b = %2d/n", a, b);
return 0;
}
2、输入与输出用不同的寄存器,&表示输入输出需要分配不同的寄存器
int main()
{
int a = 10, b = 0;
printf("before swap: a = %2d, b = %2d/n", a, b); 804842b: mov 0xfffffff8(%ebp),%edx
__asm__("nop; 804842e: mov 0xfffffff4(%ebp),%eax
movl %2, %1; 8048431: nop
movl %3, %0; 8048432: mov %edx,%ebx
nop;" 8048434: mov %eax,%ecx
: 8048436: nop
"=&r"(a), "=&r"(b) 8048437: mov %ecx,%eax
: 8048439: mov %ebx,%edx
"r"(a), "r"(b) 804843b: mov %eax,%eax
); 804843d: mov %eax,0xfffffff8(%ebp)
printf("after swap: a = %2d, b = %2d/n", a , b); 8048440: mov %edx,%eax
return 0; 8048442: mov %eax,0xfffffff4(%ebp)
}
3、交换函数,需要间接寻址
#include <stdio.h>
void swap(int* x, int* y) 08048400 <swap>:
{ 8048400: push %ebp
__asm__("nop; 8048401: mov %esp,%ebp
movl (%0), %%eax; 8048403: push %ebx
movl (%1), %%ebx; 8048404: mov 0x8(%ebp),%ecx
movl %%ebx, (%0); 8048407: mov 0xc(%ebp),%edx
movl %%eax, (%1); 804840a: nop
nop;" 804840b: mov (%ecx),%eax
: 804840d: mov (%edx),%ebx
: 804840f: mov %ebx,(%ecx)
"r"(x),"r"(y) 8048411: mov %eax,(%edx)
: 8048413: nop
"eax", "ebx", "memory" 8048414: mov (%esp,1),%ebx ;ebx还原
); 8048417: leave ;movl %ebp, %esp; pop ebp
} 8048418: ret
8048419: lea 0x0(%esi),%esi
int main()
{
int a = 10, b = 0;
printf("before swap: a = %2d, b = %2d/n", a, b);
swap(&a, &b);
printf("after swap: a = %2d, b = %2d/n", a, b);
return 0;
}
4、从汇编代码中分离函数
1> 获得汇编代码
这里用加法函数,源代码为:
int sum(int a, int b)
{
int c = a + b;
return c;
}
对应的汇编代码为
Disassembly of section .text:
00000000 <sum>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 04 sub $0x4,%esp
6: 8b 45 0c mov 0xc(%ebp),%eax
9: 03 45 08 add 0x8(%ebp),%eax
c: 89 45 fc mov %eax,0xfffffffc(%ebp)
f: 8b 45 fc mov 0xfffffffc(%ebp),%eax
12: 89 c0 mov %eax,%eax
14: c9 leave
15: c3 ret
16: 89 f6 mov %esi,%esi
2> 编写内嵌汇编语言函数
分析:为函数构建运行时堆栈情况即可使其顺利运行,由于编译器在函数执行开始和结束时会增加
routine begin:
push %ebp; mov %esp, %ebp
routine end:
leave; ret
将上面的0, 1, 14, 15去掉,返回参数放在eax中将输出部分设置为"=a"(r) 用eax寄存器 r 为需要的return type
步骤:
i 定义return_type r 变量
ii 去掉push %ebp; mov %esp, %ebp; leave; ret
iii 输出部分为:"=a"(r):
$ vi sumassemble.c
int sum(int a, int b)
{
int r;
__asm__("sub $0x4, %%esp;
movl 0xc(%%ebp), %%eax;
addl 0x8(%%ebp), %%eax;
movl %%eax, 0xfffffffc(%%ebp);
movl 0xfffffffc(%%ebp), %%eax;
movl %%eax, %%eax;"
:
"=a"(r)
);
return r;
}
Disassembly of section .text:
00000000 <sum>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 04 sub $0x4,%esp
6: 83 ec 04 sub $0x4,%esp
9: 8b 45 0c mov 0xc(%ebp),%eax
c: 03 45 08 add 0x8(%ebp),%eax
f: 89 45 fc mov %eax,0xfffffffc(%ebp)
12: 8b 45 fc mov 0xfffffffc(%ebp),%eax
15: 89 c0 mov %eax,%eax
17: 89 c0 mov %eax,%eax
19: 89 45 fc mov %eax,0xfffffffc(%ebp)
1c: 8b 45 fc mov 0xfffffffc(%ebp),%eax
1f: 89 c0 mov %eax,%eax
21: c9 leave
22: c3 ret
23: 90 nop
3> 编译可执行程序
$ vi summain.c
extern int sum(int ,int);
int main()
{
int x = sum(1,2);
printf("x = %d/n", x);
return 0;
}
$ cc -o sum_main sum_main.c sum_assemble.c
$ ./sum_main