gcc 内嵌汇编的学习笔记 IV

来源:互联网 发布:知行网络 编辑:程序博客网 时间:2024/06/05 11:22

             gcc 内嵌汇编的学习笔记 IV
                             --函数调用
  作者:ShellEx. 
  ShellEx.cn && blog.csdn.net/shellex 版权所有
 没有经验,还是通过反汇编出来的代码来学习。先写一个简单的函数
调用的C++ code Sample:

#include <stdio.h>
int Add(int a, int b) {
 return a + b;
}
int main() {
 int in1 = 0,in2 = 0, out =0 ;
 printf("PLZ input 2 Number:(x1, x2) /n");
 scanf("%d, %d", &in1, &in2);
 out = Add(in1, in2);
 printf("out = %d",out);
 return 0;
}
///////////////////////////////////////////////////////////////
察看了得出的汇编代码,有几个发现:
i. 对于不同的编译方法(用纯C,C++)得出的函数名符号是不同的。这一
 点大家早就知道了。因为这是很多C++编译器实现函数重载的基础。
 对于g++,函数标示会变成形如"__Z3Addii"这样的东西。前缀不知道
 是虾米东西,但是后缀是参数列表的参数类型名缩写。
ii. 编译器会在汇编代码文件里面加入新标示用于标示函数:
 .globl _Add
  .def _Add; .scl 2; .type 32; .endef
 _Add:
  pushl %ebp
  movl %esp, %ebp
  movl 12(%ebp), %eax
  addl 8(%ebp), %eax
  popl %ebp
  ret
 如果函数是static的那么就是这样:
  .def _Add; .scl 3; .type 32; .endef
 _Add:
  pushl %ebp
  movl %esp, %ebp
  movl 12(%ebp), %eax
  addl 8(%ebp), %eax
  popl %ebp
  ret 

接着我看看调用函数Add的汇编代码:
 movl -8(%ebp), %eax
 movl %eax, 4(%esp)
 movl -4(%ebp), %eax
 movl %eax, (%esp)
 call _Add
 movl %eax, -12(%ebp)
没有传说中的压栈操作。但是效果是一样的。因为%esp保存着栈顶指针。
相当于: 
 movl -8(%ebp), %eax
 push %eax
 movl -4(%ebp), %eax
 push %eax
 call _Add
 movl %eax, -12(%ebp)
从右往左依次把参数压栈。call _Add后,可以看到结果被放在eax里面。
我记得VC好像就用push的多,而gcc则总是默认用mov。(Borland好像也
喜欢用mov),记不清了。

接着写一段汇编调用C函数的代码:

#include <stdio.h>
int Add(int a, int b) {
 return a + b;
}
int main() {
 int in1 = 0,in2 = 0, out =0 ;
 printf("PLZ input 2 Number:(x1, x2) /n");
 scanf("%d, %d", &in1, &in2);
 int (*pf)(int,int) = Add;
 asm volatile(
  "nop #FunTest  /n/t"  
  "mov  %3, 4(%%esp) /n/t"
  "mov  %2, (%%esp)  /n/t"
  "call *%0    /n/t"
  "mov  %%eax, %1  /n/t"
  :"+r"(pf),"+r"(out)
  :"r"(in1),"r"(in2)
  :"esp","eax"
 );
 //OllyDbg
 printf("out = %d/n",out); 
 return 0;
}
///////////////////////////////////////////////////////////////
在 AT&T 汇编格式中,绝对转移和调用指令(jump/call)的操作数前要
加上*作为前缀,所以我在%0前加了*。而intel汇编是不需要的。在调用
函数时,我用了函数指针,因为直接用函数名会报错。当然,其实这样
写也可以:
 asm volatile(
  "nop #FunTest  /n/t"  
  "mov  %2, 4(%%esp) /n/t"
  "mov  %1, (%%esp)  /n/t"
  "call _Add   /n/t"
  "mov  %%eax, %0  /n/t"
  :"+r"(out)
  :"r"(in1),"r"(in2)
  :"esp","eax"
 );
但是这样写的前提是你知道生成的函数标识是什么才行。。。
PS:发现一点小问题,有时在gcc 中生成不了的内嵌汇编代码模板在g++
里面可以通过,直到用as编译时才会报错,原因不明。比如说如果在调
用函数时不用函数指针pf而用直接用函数名Add倒入汇编模板,就会出现
这样的问题。
 
  ShellEx.cn && blog.csdn.net/shellex 版权所有
 

原创粉丝点击