<!--
@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++和汇编之间的调用必须遵循相同的约定,包括参数传递方式(寄存器还是栈)以及返回值的处理。 2. **汇编语言语法**:汇编语言的语法因汇编器而异,比如Intel语法和AT&T语法。开发者需要熟悉所使用的汇编器的语法...
在编程世界中,有时我们需要利用低级语言如汇编来实现特定的性能优化或系统级别的操作,然后在高级语言如C/C++项目中调用这些功能。本篇将详细讲解如何在Visual Studio 2010 (VS2010)环境下,创建汇编语言编写的动态...
通过这种方式,你可以在C++项目中直接集成和调用汇编代码,充分利用x64架构的性能优势。记住,虽然汇编语言能提供更高的控制和效率,但它也更难编写和维护,因此应在必要时谨慎使用。对于大多数情况,优化的C++代码...
本工程通过一系列示例,展示了如何在C++程序中使用内联汇编来实现函数调用、参数传递、循环以及条件判断。 首先,我们来看"Less1"这个示例。在这个例子中,开发者可能用内联汇编来演示如何手动管理函数调用的过程。...
调用汇编全局变量类似于调用函数,需要先在汇编中声明其全局性,然后在C/C++中使用`extern`声明并引用。例如,在汇编中定义全局变量`var`: ```assembly .bss _var,1 .global _var ``` 在C/C++中调用这个变量: `...
### 浅析ARM汇编 C语言 C++ 相互调用的方法 #### 一、引言 在嵌入式开发领域,ARM架构因其低功耗、高性能的特点被广泛应用。随着软件开发需求的多样化,不同编程语言间的交互成为了一个重要的技术问题。其中,ARM...
ARM汇编与C语言、C++相互调用的知识点主要包括以下几个方面: 1. ARM汇编程序与C语言程序之间的相互调用: - 汇编程序访问C语言全局变量需要使用间接调用的方式,即将全局变量的地址载入寄存器中,再使用相应的...
c++反汇编 c++反汇编的好教程c++反汇编 c++反汇编的好教程c++反汇编 c++反汇编的好教程
在C++中,我们可以通过使用预处理器和extern "C"来调用汇编语言代码,这在需要优化特定部分性能或者与底层硬件交互时非常有用。C++的编译器通常会将C++代码转换为汇编语言,然后再进一步翻译成机器码。理解汇编语言...
例如,C++中的函数调用在汇编中表现为`call`指令,变量分配可能涉及`mov`指令等。通过阅读汇编代码,开发者可以更好地理解内存访问模式、函数调用开销以及循环优化等。 了解C++到汇编的转换有助于优化性能。例如,...
从汇编角度研究 C++,能看到最彻底最本质的东西,学习效果也最好,也更容易看清C++面向对象的底层实质。因此,从今天起,我会写一个专题系列 《从汇编看 C++》 发布到我的博客里,欢迎收看 目前,我总共写了4篇,...
C++虚函数调用的反汇编解析
在Visual C++中使用内联汇编是一种高级编程技术,它允许程序员在C/C++代码中直接嵌入汇编指令,从而实现更底层的控制和优化。以下是对该主题的详细解析,涵盖其优势、使用场景、关键字及具体用法等。 ### 一、内联...
请注意,这些题目涉及到的C++和汇编知识只是面试中可能遇到的一部分。在真实的面试中,你可能还需要准备更多关于数据结构、算法、操作系统、网络、设计模式等方面的问题。对于C++,深入理解STL、模板、异常处理、...
本教程的md文件可能包含了多个章节,分别讲解了C++的基本语法、内存管理策略、函数调用的底层细节、对象生命周期以及异常处理等主题,然后逐步深入到反汇编的概念,介绍如何使用反汇编工具,解读汇编代码,以及如何...
附件中时我对c/c++程序调用中用到的堆栈进行的分析
C++代码可以调用汇编函数,或者在C++函数内部插入汇编段。这样做的好处是可以将性能敏感的部分用汇编编写,而其余逻辑则用C++来实现,以达到性能和可维护性的平衡。 4. **调用约定**:在混合编程中,理解调用约定至...
汇编和C++教程 ·数据传送类指令; ·算术运算类指令; ·逻辑运算类指令 ·控制程序转移类指令; ·位(布尔)处理类指令. 用机器码表示的指令格式以8位2进制数(字节)为基础。111条指令中单字节...