IA32体系结构8(x86过程调用)

2024-02-21 23:32

本文主要是介绍IA32体系结构8(x86过程调用),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

直观感受及疑问

正常情况下,CPU执行指令都是一条条顺序往下执行。所谓过程调用,就是CPU停止执行下一条指令,转而去执行其它地方的指令。当这些指令执行完毕之后,CPU回到之前暂停的下一条指令,重新开始执行。有点类似C语言的“函数调用”。那么,我们有几个问题需要弄清楚:

1.我们的指令中,如何跳转到过程调用指令,又如何回来?

2.跳过去又回来,CPU是如何记住之前的执行位置的?

3.如果过程程序需要参数,如何传递,有了返回值,如何传递?

了解堆栈

在回答上述问题之前,有一个非常重要的结构需要了解,那就是堆栈-stack。

堆栈是一段连续的内存位置,由栈选择符SS和栈指针ESP指定。如果是32位保护模式,SS指向一个数据段描述符,这个数据段描述符用于堆栈,就必须是可读可写的。ESP指向栈顶数据的最低字节地址。x86的堆栈是一种满递减堆栈,从高地址向低地址扩展,ESP指向栈顶可用的元素。当push入栈时,ESP先递减,然后再把数据拷贝到ESP开始的地址处。pop则相反,先拷贝数据,再递增ESP。

堆栈的数量只受物理内存和线性地址空间的限制,但是任意时刻,只能操作使用一个堆栈,这个堆栈叫做当前堆栈,由SS来指定。

堆栈的push和pop操作,默认需要字节对齐,16位或者32位。这个由堆栈描述符里面的D标志决定。如果设置为16位,则push和pop一次操作2字节。32位则操作4字节。

另外,还有一个堆栈基址寄存器EBP,用来方便过程调用的参数传递和建立局部变量。使用的时候,默认指向SS指向的数据段。一般在被调用程序里面,直接拷贝ESP到EBP保存起来,指向一个独立的“栈帧”。

返回指令指针(return instruction pointer)

跳到调用过程第一条指令之前,CALL指令会将EIP寄存器的值push到当前堆栈保存起来。此时,这个地址叫做返回指令指针。一旦从过程返回,RET指令会将这个地址弹出到EIP,从而恢复程序的执行。

使用CALL和RET进行过程调用

近过程调用

近跳转过程如下:

1.push当前的EIP到堆栈

2.加载调用过程偏移到EIP

3.开始执行过程调用代码

近返回过程如下:

1.pop栈顶元素到EIP寄存器

2.如果ret指令带有可选的n参数,则递增栈指针的值(n),以此释放栈中的参数

3.恢复调用过程代码的执行

远过程调用

远跳转过程如下:

1.push当前的CS寄存器到堆栈

2.push当前的EIP寄存器到堆栈

3.加载过程代码的段选择子到CS寄存器

4.加载过程代码的指令偏移到EIP寄存器

5.开始过程代码的执行

远返回过程如下:

1.pop栈顶数据到EIP寄存器

2.pop栈顶数据到CS寄存器(之前的栈顶数据已经弹出到EIP)

3.如果RET指令带有n参数。递增栈指针n字节,用以释放栈中的参数

4.恢复原先程序的执行

参数传递

参数传递三种方式:

1.通过通用寄存器(把参数放在通过寄存器,然后执行程序,之后将返回值放到通过寄存器)

2.通过参数列表(参数存放在特定数据段,用一指针指定,放入通用寄存器)

3.通过堆栈(参数压入堆栈,通过栈帧基址寄存器来定位参数位置)

linux内核主要使用了方式1和方式3,方式1多见于系统调用int 0x80。其中堆栈传递方式比较经典,其栈帧结构完美解决了传参数量和局部变量数量的问题。具体参考《linux内核完全注释》3.4节。在执行过程调用的时候,cpu不自动保存通用寄存器、段寄存器、EFLAGS等内容,如果需要使用这些状态值,保存的责任在于调用者。

不同特权级过程调用

不同的特权级之间的过程调用,遵循特殊设计。IA架构分0/1/2/3这四种特权级,0最高特权级,3最低特权级。较低的特权级可以通过“门”来调用较高特权级上的过程代码。否则,CPU会抛出一般保护异常。

CALL指令中提供的段选择符指向一个特殊的数据结构-调用门描述符(call gate descriptor)。这个调用门描述符包含:

1.访问权限信息

2.调用过程的代码段选择符

3.调用过程的代码在段中的偏移

不同特权级的过程调用,处理器会执行堆栈切换。每个特权级,都有自己的堆栈。对于多特权级来说,特权级3的堆栈选择符和堆栈指针使用SS和ESP,特权级0/1/2的堆栈选择符和栈指针保存在任务状态段(TSS)里面。切换特权级时,对应的堆栈选择符和栈指针会被自动传送到SS和ESP,这对调用者来说,是透明的。

(注意:linux内核中没有使用调用门,一下内容仅做了解)

当发起特权级更高的调用,处理器处理过程如下:

1.执行访问权限检查

2.临时保存(内部)SS, ESP, CS和EIP寄存器的内容

3.从TSS中加载相应特权级(要转到的调用代码特权级)的堆栈选择符和栈指针到SS和ESP,然后切换到新的堆栈

4.push之前临时保存的调用者的SS和ESP到新堆栈(被调用者的堆栈)

5.从调用者堆栈复制参数到新堆栈(调用门描述符里面确定的多少参数需要拷贝到新堆栈)

6.push之前临时保存的调用者的CS和EIP到新栈

7.分别加载新代码的段选择符和调用门里面的新指令指针到CS和EIP

8.以新的特权级开始执行过程调用

从特权级调用返回,处理器执行过程如下:

1.执行特权级检查

2.加载CS和EIP寄存器为调用之前的值

3.如果RET有n参数,则递增栈指针n字节,弹出数据

4.加载SS和ESP寄存器为调用之前的值

5.如果RET有n参数,递增栈指针

6.恢复执行原先的代码

这篇关于IA32体系结构8(x86过程调用)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/733439

相关文章

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

Solr 使用Facet分组过程中与分词的矛盾解决办法

对于一般查询而言  ,  分词和存储都是必要的  .  比如  CPU  类型  ”Intel  酷睿  2  双核  P7570”,  拆分成  ”Intel”,”  酷睿  ”,”P7570”  这样一些关键字并分别索引  ,  可能提供更好的搜索体验  .  但是如果将  CPU  作为 Facet  字段  ,  最好不进行分词  .  这样就造成了矛盾  ,  解决方法

【LabVIEW学习篇 - 21】:DLL与API的调用

文章目录 DLL与API调用DLLAPIDLL的调用 DLL与API调用 LabVIEW虽然已经足够强大,但不同的语言在不同领域都有着自己的优势,为了强强联合,LabVIEW提供了强大的外部程序接口能力,包括DLL、CIN(C语言接口)、ActiveX、.NET、MATLAB等等。通过DLL可以使用户很方便地调用C、C++、C#、VB等编程语言写的程序以及windows自带的大

Python:豆瓣电影商业数据分析-爬取全数据【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】

**爬取豆瓣电影信息,分析近年电影行业的发展情况** 本文是完整的数据分析展现,代码有完整版,包含豆瓣电影爬取的具体方式【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】   最近MBA在学习《商业数据分析》,大实训作业给了数据要进行数据分析,所以先拿豆瓣电影练练手,网络上爬取豆瓣电影TOP250较多,但对于豆瓣电影全数据的爬取教程很少,所以我自己做一版。 目

NGINX轻松管理10万长连接 --- 基于2GB内存的CentOS 6.5 x86-64

转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=190176&id=4234854 一 前言 当管理大量连接时,特别是只有少量活跃连接,NGINX有比较好的CPU和RAM利用率,如今是多终端保持在线的时代,更能让NGINX发挥这个优点。本文做一个简单测试,NGINX在一个普通PC虚拟机上维护100k的HTTP

string字符会调用new分配堆内存吗

gcc的string默认大小是32个字节,字符串小于等于15直接保存在栈上,超过之后才会使用new分配。