CPU指令解析及函数调用机制

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
云解析DNS,个人版 1个月
简介: CPU指令解析及函数调用机制

一、CPU指令解析


最常用的mov指令


       指令中最常使用的是对寄存器和内存进行数据存储的 mov 指定数据的存储地和读出源。操作数中可以指定寄存器、常数、标签(附加在地址前),以及用方括号([ ])围起来的这些内容。如果指定了没有用([ ])方括号围起来的内容,就表示对该值进行处理;如果指定了用方括号围起来的内容,方括号的值则会被解释为内存地址,然后就会对该内存地址对应的值进行读写操作。让我们对上面的代码片段进行说明指令,mov指令的两个操作数,分别用来


mov
ebp,espeax,dword ptr [ebp+8]


  mov ebp,esp中,esp 寄存器中的值被直接存储在了ebp中,也就是说,如果esp 寄存器的值是100的话那么 ebp 寄存器的值也是100.


       而在 mov eax,dword ptr [ebp+8]这条指令中,ebp寄存器的值+8后会被解析称为内存地址。如果 ebp


       寄存器的值是100的话,那么eax寄存器的值就是100+8的地址的值。dword ptr 也叫做double word pointer 简单解释一下就是从指定的内存地址中读出4字节的数据


对栈进行push和pop


       程序运行时,会在内存上申请分配一个称为栈的数据空间。栈(stack)的特性是后入先出,数据在存储时是从内存的下层(大的地址编号)逐渐往上层(小的地址编号)累积,读出时则是按照从上往下进行读取的。


栈的模型:



   栈的存储临时数据的区域,它的特点是通过 push 指令和pop指令进行数据的存储和读出。向栈中存储数据称为 入栈 ,从栈中读出数据称为 出栈 ,32位 x86 系列的CPU中,进行1次push或者pop,即可处理32位(4字节)的数据


二、函数的调用机制


       下面我们一起来分析一下函数的调用机制,我们以上面的C语言编写的代码为例。首先,让我们从MyFunc 函数调用 AddNum 函数的汇编语言部分开始,来对函数的调用机制进行说明。栈在函数的调用中发挥了巨大的作用,下面是经过处理后的MyFunc函数的汇编处理内容


_MyFunc    proc    near                            
 push       ebp     ; 将ebp寄存器的值存入栈中         (1)
 mov        ebp,esp ; 将esp寄存器的值存入ebp寄存器中  (2)
 push       456     ; 将456入栈                      (3)
 push       123     ; 将123入栈                      (4)
 call       _AddNum ; 调用 AddNum 函数               (5)
 add        esp,8   ; esp寄存器的值 + 8              (6)
 pop        ebp     ; 读出栈中的数值存入esp寄存器中    (7)
 ret                ; 结束 MyFunc 函数,返回到调用源   (8)
_MyFunc    ebp 


   代码解释中的(1)、(2)、(7)、(8)的处理适用于C语言中的所有函数,我们会在后面展示 AddNum函数处理内容时进行说明。这里希望大家先关注(3)-(6)这一部分,这对了解函数调用机制至关重要。


       (3)和(4)表示的是将传递给AddNum函数的参数通过push入栈。在C语言源代码中,虽然记述为函数AddNum(123, 456),但入栈时则会先按照456, 123这样的顺序。也就是位于后面的数值先入栈。这是C语言的规定。(5)表示的call 指令,会把程序流程跳转到AddNum函数指令的地址处。在汇编语言中,函数名 表示的就是函数所在的内存地址。AddNum 函数处理完毕后,程序流程必须要返回到编号(6)这一行。call 指令运行后,call 指令的下一行(也就指的是(6)这一行)的内存地址(调用函数完毕后要返回的内存地址)会自动的push入栈。该值会在AddNum函数处理的最后通过ret指令pop出栈,然后程序会返回到(6)这一行。


       (6)部分会把栈中存储的两个参数(456和123)进行销毁处理。虽然通过两次的pop指令也可以实现,不过采用esp 寄存器+8的方式会更有效率(处理1次即可)。对栈进行数值的输入和输出时,数值的单位是4字节。因此,通过在负责栈地址管理的esp 寄存器中加上4的2倍8,就可以达到和运行两次 pop命令同样的效果。虽然内存中的数据实际上还残留着,但只要把esp 寄存器的值更新为数据存储地址前面的数据位置,该数据也就相当于销毁了


我在编译 Sample4.c 文件时,出现了下图的这条消息


D: \C> bcc32-c-S Sample4.cBorland C++ 5. 5. 1 for Win32 Copyright <c> 1993.2000
BorlandSample4.c:Warning W8004 Sample4.c 10: 'c' is assigned a value that is 
never used in function MyFunc


上面的意思是指c的值在MyFunc定义了但是一直未被使用,这其实是一项编译器优化的功能,由于存储AddNum函数返回值的变量c在没有被用到,因此编译器就认为 该变量没有意义,进而也就没有生成与之对应的汇编语言代码


下图是调用AddNum这一函数前后栈内存的变化:


目录
相关文章
|
25天前
|
Java 数据库连接 开发者
Java中的异常处理机制深度解析
【8月更文挑战第13天】本文旨在深入探讨Java编程语言中一个至关重要的组成部分——异常处理机制。我们将从基本概念入手,逐步展开讨论异常处理在Java语言设计中的角色和重要性,以及如何正确利用这一机制来提高代码的健壮性和可维护性。文章将通过分析异常处理的最佳实践,揭示如何在复杂的应用程序中有效地管理和处理错误情况。
|
22天前
|
存储 SQL 关系型数据库
深入解析MySQL事务机制和锁机制
深入解析MySQL事务机制和锁机制
|
22天前
|
存储 缓存 NoSQL
深入解析Memcached:内部机制、存储结构及在大数据中的应用
深入解析Memcached:内部机制、存储结构及在大数据中的应用
|
30天前
|
Java 开发者
深入解析Java中的异常处理机制
在Java的世界中,异常处理是维护程序健壮性的基石之一。本文将通过实例演示和理论分析相结合的方式,探讨Java异常处理机制的工作原理及其最佳实践。我们将从异常的基本概念出发,逐步深入到异常类的层次结构、捕获异常的策略以及自定义异常的使用场景,旨在为读者提供一个全面而深入的视角来理解和应用Java中的异常处理。
18 2
|
14天前
|
负载均衡 监控 网络协议
|
17天前
|
自然语言处理 计算机视觉 Python
VisProg解析:根据自然语言指令解决复杂视觉任务
VisProg是一个神经符号系统,能够根据自然语言指令生成并执行Python程序来解决复杂的视觉任务,提供可解释的解决方案。
24 0
|
22天前
|
存储 监控 算法
深入解析JVM内部结构及GC机制的实战应用
深入解析JVM内部结构及GC机制的实战应用
|
2月前
|
Java
Java中的异常处理机制深度解析
本文旨在深入探讨Java语言中异常处理的机制,从基础概念到高级应用,全面剖析try-catch-finally语句、自定义异常以及异常链追踪等核心内容。通过实例演示和代码分析,揭示异常处理在Java程序设计中的重要性和应用技巧,帮助读者构建更为健壮和易于维护的程序。
|
2月前
|
调度
【浅入浅出】Qt多线程机制解析:提升程序响应性与并发处理能力
在学习QT线程的时候我们首先要知道的是QT的主线程,也叫GUI线程,意如其名,也就是我们程序的最主要的一个线程,主要负责初始化界面并监听事件循环,并根据事件处理做出界面上的反馈。但是当我们只限于在一个主线程上书写逻辑时碰到了需要一直等待的事件该怎么办?它的加载必定会带着主界面的卡顿,这时候我们就要去使用多线程。
104 6
|
2月前
|
Java 程序员 测试技术
解析Java中的反射机制及其应用场景
解析Java中的反射机制及其应用场景

推荐镜像

更多
下一篇
DDNS