`
maosuhan
  • 浏览: 112372 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

c++栈调用的汇编研究

阅读更多

<!-- @page { margin: 0.79in } P { margin-bottom: 0.08in } -->

先写一段程序,用的编辑环境为 Netbeans 6.9 gcc gdb

int main(int argc, char** argv) {

int i=1;

i++;

return (EXIT_SUCCESS);

}

 

编译为汇编指令为

 

!int main(int argc, char** argv) {

main+0: push %ebp

main+1: mov %esp,%ebp

main+3: sub $0x10,%esp

! int i=1;

main()

main+6: movl $0x1,-0x4(%ebp)

! i++;

main+13: addl $0x1,-0x4(%ebp)

! return (EXIT_SUCCESS);

main+17: mov $0x0,%eax

!}

main+22: leave

main+23: ret

 

!应该为注释,标记正在进行到代码的哪一个步骤

 

main+0: push %ebp

ebp是基址指针寄存器。这里应该是说将原来的 ebp压入栈,这里的 ebp应该是作为一个栈的基地址而从栈里面取地址就要用 ebp做基准,所以这里存入上一级栈的 ebp

 

看: main+1: mov %esp,%ebp

这里把 esp的值传给 ebp,也就是说 ebp现在可以当作目前这一级栈的基地址,而因为 esp经常改变,所以要用 ebp来做基址。

 

main+3: sub $0x10,%esp

这里因为有一个局部变量 i,所以要把 esp向上调,不知道 esp是不是就是指栈顶的意思?这里貌似还要 RoundUp变到 16 的倍数,所以总是 0xn0。如果有 5个局部变量,就会移动 x020。(这里还是有问题,见下一个例子)

 

main()

 

main+6: movl $0x1,-0x4(%ebp)

这里可以看到将 1付给 i。这里用到了偏址 4,得到 i的指,这里很奇怪为什么 i在那个位置。注意这里只有当运行到这一个语句的时候才会将 i的值压栈,而 esp会预留全部的局部变量的空间。

 

main+13: addl $0x1,-0x4(%ebp)

这里将 i的值加上 1

 

main+17: mov $0x0,%eax

这里将 0付给 eax寄存器,可见这里 eax是存储返回值的寄存器。

 

看: main+22: leave

main+23: ret

这里应该是函数返回。

 

如果有一个语句为 j=i+j

则对应于汇编为

main+24: mov -0x4(%ebp),%eax// i的值付给 eax

main+27: add %eax,-0x8(%ebp) // eax付给 j。可见这里 eax也是可以作为临时寄存器。

 

 

继续编一段程序:

int add(int i,int p){

int j=i+p;

return j;

}

int main(int argc, char** argv) {

int i=1;

 

i=add(i,8);

 

return (i);

}

 

 

main+0: push %ebp

main+1: mov %esp,%ebp

main+3: sub $0x18,%esp

! int i=1;

main+6: movl $0x1,-0x4(%ebp)

!

! i=add(i,8);

main+13: movl $0x8,0x4(%esp)

main+21: mov -0x4(%ebp),%eax

main+24: mov %eax,(%esp)

main+27: call 0x80483b4 <add>

main()

main+32: mov %eax,-0x4(%ebp)

!

! return (i);

main+35: mov -0x4(%ebp),%eax

!}

main+38: leave

main+39: ret

 

!int add(int i,int p){

add()

add+0: push %ebp

add+1: mov %esp,%ebp

add+3: sub $0x10,%esp

! int j=i+p;

add+6: mov 0xc(%ebp),%eax

add+9: mov 0x8(%ebp),%edx

add+12: lea (%edx,%eax,1),%eax

add+15: mov %eax,-0x4(%ebp)

! return j;

add+18: mov -0x4(%ebp),%eax

!}

add+21: leave

add+22: ret

 

main+13: movl $0x8,0x4(%esp)

main+21: mov -0x4(%ebp),%eax

main+24: mov %eax,(%esp)

这里其实就是把参数压栈,把 8 i压进去。

 

main+27: call 0x80483b4 <add>

这里调用 add函数。

add+0: push %ebp

add+1: mov %esp,%ebp

add+3: sub $0x10,%esp

还是和 main函数开头一样的操作。存储旧的 ebp值压栈。这里刚开头的时候其实 esp的值已经变掉了从 0x560变到了 0x558,这里应该是 call指令完成的。

 

add+6: mov 0xc(%ebp),%eax

add+9: mov 0x8(%ebp),%edx

add+12: lea (%edx,%eax,1),%eax

add+15: mov %eax,-0x4(%ebp)

这里计算那个表达式的值。

最后返回。

 

这里我把栈的图画一下。

 

esp 0x548

 

 

0xbf899554 j

ebp 0xbf899558 0xbf899578(上一级的 ebp )

0xbf89955c 0x8048431(这里己有可能是调用着执行 call时的下一条语句)

esp 0xbf899560 i

0xbf899564 8

 

 

 

0xbf899574 i

esp 0xbf899578 上一级的 ebp

 

但是如果我把 add函数写成这样

int add(int i,int p){

int j=1;

printf("i:%p\n",&i);

printf("p:%p\n",&p);

printf("j:%p\n",&j);

return j;

}

 

结果是:

i:0xbffff550

p:0xbffff554

j:0xbffff53c

 

发现局部变量和函数参数之间有四个空即 16个字节。发现其实 j并不是压在 ebp上一格的,而是 (ebp+12),这个很诡异。所以会出现在这种情况,我原来还以为是局部变量与参数间空 16个字节放各种 pointer以及返回值这些东西呢,这个实在是太诡异了。

 

宗其所述:正常情况下,局部变量与参数间空了 8个字节(linux下)。

分享到:
评论

相关推荐

    C++程序同汇编程序混合调用的源代码

    C++和汇编之间的调用必须遵循相同的约定,包括参数传递方式(寄存器还是栈)以及返回值的处理。 2. **汇编语言语法**:汇编语言的语法因汇编器而异,比如Intel语法和AT&T语法。开发者需要熟悉所使用的汇编器的语法...

    vs2010 C/C++ 调用汇编dll

    在编程世界中,有时我们需要利用低级语言如汇编来实现特定的性能优化或系统级别的操作,然后在高级语言如C/C++项目中调用这些功能。本篇将详细讲解如何在Visual Studio 2010 (VS2010)环境下,创建汇编语言编写的动态...

    C++汇编x64调用asm文件例子

    通过这种方式,你可以在C++项目中直接集成和调用汇编代码,充分利用x64架构的性能优势。记住,虽然汇编语言能提供更高的控制和效率,但它也更难编写和维护,因此应在必要时谨慎使用。对于大多数情况,优化的C++代码...

    C++内联汇编示例

    本工程通过一系列示例,展示了如何在C++程序中使用内联汇编来实现函数调用、参数传递、循环以及条件判断。 首先,我们来看"Less1"这个示例。在这个例子中,开发者可能用内联汇编来演示如何手动管理函数调用的过程。...

    DSP编程技巧之--从C/C++代码调用汇编代码中的函数与变量

    调用汇编全局变量类似于调用函数,需要先在汇编中声明其全局性,然后在C/C++中使用`extern`声明并引用。例如,在汇编中定义全局变量`var`: ```assembly .bss _var,1 .global _var ``` 在C/C++中调用这个变量: `...

    浅析ARM汇编 C语言 C++ 相互调用的方法

    ### 浅析ARM汇编 C语言 C++ 相互调用的方法 #### 一、引言 在嵌入式开发领域,ARM架构因其低功耗、高性能的特点被广泛应用。随着软件开发需求的多样化,不同编程语言间的交互成为了一个重要的技术问题。其中,ARM...

    ARM汇编 C语言 C++ 相互调用

    ARM汇编与C语言、C++相互调用的知识点主要包括以下几个方面: 1. ARM汇编程序与C语言程序之间的相互调用: - 汇编程序访问C语言全局变量需要使用间接调用的方式,即将全局变量的地址载入寄存器中,再使用相应的...

    c++反汇编 内存结构

    c++反汇编 c++反汇编的好教程c++反汇编 c++反汇编的好教程c++反汇编 c++反汇编的好教程

    C++汇编语言编写程序代码

    在C++中,我们可以通过使用预处理器和extern "C"来调用汇编语言代码,这在需要优化特定部分性能或者与底层硬件交互时非常有用。C++的编译器通常会将C++代码转换为汇编语言,然后再进一步翻译成机器码。理解汇编语言...

    c++转汇编的小测试

    例如,C++中的函数调用在汇编中表现为`call`指令,变量分配可能涉及`mov`指令等。通过阅读汇编代码,开发者可以更好地理解内存访问模式、函数调用开销以及循环优化等。 了解C++到汇编的转换有助于优化性能。例如,...

    从汇编看C++系列前4篇

    从汇编角度研究 C++,能看到最彻底最本质的东西,学习效果也最好,也更容易看清C++面向对象的底层实质。因此,从今天起,我会写一个专题系列 《从汇编看 C++》 发布到我的博客里,欢迎收看 目前,我总共写了4篇,...

    C++虚函数调用的反汇编解析

    C++虚函数调用的反汇编解析

    在 Visual C++ 中使用内联汇编

    在Visual C++中使用内联汇编是一种高级编程技术,它允许程序员在C/C++代码中直接嵌入汇编指令,从而实现更底层的控制和优化。以下是对该主题的详细解析,涵盖其优势、使用场景、关键字及具体用法等。 ### 一、内联...

    c++题目以及汇编,面试题目

    请注意,这些题目涉及到的C++和汇编知识只是面试中可能遇到的一部分。在真实的面试中,你可能还需要准备更多关于数据结构、算法、操作系统、网络、设计模式等方面的问题。对于C++,深入理解STL、模板、异常处理、...

    C++与反汇编教程(M了个J李明杰2019版本)-md文件.rar

    本教程的md文件可能包含了多个章节,分别讲解了C++的基本语法、内存管理策略、函数调用的底层细节、对象生命周期以及异常处理等主题,然后逐步深入到反汇编的概念,介绍如何使用反汇编工具,解读汇编代码,以及如何...

    c/c++程序调用 堆栈分析 汇编

    附件中时我对c/c++程序调用中用到的堆栈进行的分析

    汇编及C++混合编程开发Symbian程序

    C++代码可以调用汇编函数,或者在C++函数内部插入汇编段。这样做的好处是可以将性能敏感的部分用汇编编写,而其余逻辑则用C++来实现,以达到性能和可维护性的平衡。 4. **调用约定**:在混合编程中,理解调用约定至...

    70 C++(汇编和C++教程)

    汇编和C++教程 ·数据传送类指令; ·算术运算类指令; ·逻辑运算类指令 ·控制程序转移类指令; ·位(布尔)处理类指令. 用机器码表示的指令格式以8位2进制数(字节)为基础。111条指令中单字节...

Global site tag (gtag.js) - Google Analytics