gcc编译c语言中内嵌汇编

时间:2021-04-15 04:02:53

--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 <# WebPartBody #>x0h, %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    <# WebPartBody #>x4,%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 <# WebPartBody #>x4, %%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    <# WebPartBody #>x4,%esp
   6:   83 ec 04                sub    <# WebPartBody #>x4,%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 
 


作者Blog:http://blog.csdn.net/fifan/