MSVC环境下X64 prolog和epilog

Prolog&Epilog 这篇博客会简单介绍一下Prolog&Epilog 然后再简单介绍下我对于程序在计算机中到底如何运行的一些理解(因为自己之前也从来没有接触过这些方面的知识,所以如果有讲的不对的地方希望大家能够帮我指正) 1.首先我们认识下什么是Prolog&Epilog 其实就是两段固定的代码, 当编译器对程序进行编译的时候就会生成这两段代码, 然后编译器会在每一个函数的开头塞入Prol... 阅读详情

目录

1. prolog的代码(在MASM中)

2. epilog的代码(在MASM中)


每一个函数需要分配栈空间、进一步调用其函数、保存非易失性寄存器、或者使用异常处理机制,都必须有一段序言代码(prolog),它的地址限制在解开数据(unwind)中描述,unwind数据与相应的函数地址条目相关。更多信息,参见X64异常处理文档。如有必要,prolog会将数据参数寄存器值保存在它的起始地址上(home address)(即,栈的最底下分出的一块地址,用于存放函数参数寄存器值和返回地址,称其为home地址),将非易失性寄存器的值压入栈,为局部变量和临时存储分配固定大小的栈空间,并且在可选地建立一个帧指针。相关的unwind数据必须描述prolog的行为,必要为系统撤消prolog代码的效果提供必要的信息。

假如栈上分配的固定大小超过了一页(即,超过了4096字节),则栈的分配可能会跨越一个虚拟内存的分页,因此,在分配内存之前必须要检查。基于这个目的,系统提供了一个专门的例程供prolog调用,它不会破坏任何参数栈(即,传递寄存器参数所用到的栈,也就是前面提到的home地址,又称影子内存)。

保存非易失性寄存器偏爱的方法是在分配固定栈之前将寄存器值移到栈上。假如固定栈分配在非易失性寄存器值保存之前执行,则最可能要求一个32位的位移去寻址保存寄存器的区域。(据报道,寄存器入栈和出栈一样快,并且在可预见的未来应该保持如此,尽管入栈之间存在隐含的依赖关系。) 非易失性寄存器可以以任何顺序存储。然而,在prolog中第一次使用非易失性寄存器就必须是保存其值。

1. prolog的代码(在MASM中)

典型的prolog代码可以是这样:

mov   [RSP + 8], RCX

push   R15

push   R14

push   R13

sub    RSP, fixed-allocation-size

lea    R13, 128[RSP]

...

prolog将参数寄存器RCX存入到其home位置,存储非易失性寄存器R13-R15到栈中,分配因定大小的栈帧,并建立一个指向128字节固定大小空间的帧指针。使用偏移量以允许使用1字节的偏移寻址固定分配区域的大部分区域。

假如固定分配区域大于等于一页内存,则在修改RSP之前,系统会调用一个帮助函数。这个帮助函数为__chkstk会探测待分配栈的范围,以确保正确地扩充了栈空间。按这种思想,前面的prolog代码可以改写为如下形式:

mov    [RSP + 8], RCX

push   R15

    push   R14

    push   R13

    mov    RAX,  fixed-allocation-size

    call   __chkstk

    sub    RSP, RAX

    lea    R13, 128[RSP]

...

帮助函数__chkstk除了修改寄存器R10、R11和条件代码之外,不会修改别的任何寄存器的值。特别是,它将原样返回RAX,并保持所有非易失性寄存器和参数传递寄存器的值不变。

2. epilog的代码(在MASM中)

epilog存在于每个函数的出口处,然而,通常即只有一个prolog,但即可以有多个epilog。epilog代码将堆栈修剪为其固定分配大小(如有必要),释放固定栈空间,从栈中弹出先前存入栈中的非易失性寄存器的值以恢复其寄存器值,然后再返回。

epilog代码必须遵循一套严格的unwind代码的规则,才能可靠地通过异常和中断unwind。这套规则压缩了所要求的unwind数据的数量,因为,描述每个epilog不需要别的数据。相反,unwind代码可以通过向前扫描代码流来识别epilog,从而确定epilog正在执行。

假如在函数中使用了桢指针,则必须在epilog执行之前将栈修剪为其先前的固定大小。这个动作在技术上不属于epilog的范畴。例如,可以使用下面的epilog代码撤销之前使用的epilog:

lea      RSP, -128[R13]    ; epilogue proper starts here

  add      RSP, fixed-allocation-size

  pop      R13

  pop      R14

  pop      R15

  ret

在实践中,当使用帧指针的时候,在两步动作中,没有很好的理由去调整RSP指针,因此,可以使用下面的epilog代码代替:

lea      RSP, fixed-allocation-size - 128[R13]

    pop      R13

    pop      R14

    pop      R15

ret

这些形式仅仅是epilog的有效形式。必须由

add RSP, constant

或

lea RSP, constant[FPreg]

后接0或更多8字节寄存器弹出值外加一个返回值或者jmp指令构成。(在epilog中,只允许使用jmp语句类的一个子集,该子集仅是具有ModRM内存引用的jmp语句类,其中 ModRM mod字段值为 00)。禁止在ModRM mod字段值为01或10的epilog中使用 jmp语句。有关允许的ModRM引用的更多信息,请参阅AMD x86-64架构程序员手册第 3卷:通用和系统指令中的表 A-15。)不能出现其他代码。特别是,不能在epilog中安排任何内容,包括加载返回值。

当不使用帧指针时,epilog必须使用add RSP,constant来释放分配的固定栈空间。它不可以使用 lea RSP,constant[RSP]代替。由于存在这个限制,因此,当搜寻epilog的时候,unwind可以识别的模式更少。

遵循这些规则允许展开unwind确定当前正在执行epilog,并模拟epilog其余部分的执行,从而允许重新创建调用函数的上下文。

资料来源:

x64 prolog and epilog | Microsoft DocsLearn more about: x64 prolog and epilogicon-default.png?t=M3K6https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog?view=msvc-170

SEH中的prolog和epilog 最初发布在QQ空间,见:SEH中的prolog和epilog,内有贴图。 使用SEH的代码都需要构建栈桢,支持exception处理的栈桢,而重复的代码就应当提炼成函数,微软自然不会例外。为此系统提供了prolog和epilog系列,类似的函数有不少版本,但大同小异。这次不 阅读详情

相关推荐

《R语言实战》第八章之回归分析图形

回归分析图形 回归分析分为简单回归与复杂回归 1 : 简单线性回归即:模型中只包含一个因变量和一个自变量,有时候也会包含多项式, 这个图形描述了身高与体重的线性关系,这也是一个多项式图形 2:当我们的预测变量(自变量)不止一个时,就属于多元线性回归,而且多元线性回归中也可以包含多项式以及交互项 (1)在进行多远回归分析之前可以先描述变量之间的相关关系 上图为一个散点图矩阵,描述了五个变量之间的相关关系,我们可以通过非主对角线的散点图来查看两个变量之间的关系。 多元线性回归简单地就是OLS回归,通过lm和

Strawberry_Ya的博客 1834

Slurm的前处理prolog和后处理epilog

1. Slurm前处理和后处理 Slurm支持大量的prolog和epilog程序。 请注意,出于安全原因,这些程序没有设置搜索路径。 在程序中指定完全限定的路径名或设置“PATH”环境变量。 下面的第一个表格列出了可用于作业分配的prolog和epilog,它们的运行时间和地点。 参数 地点 由...调用 用户 ...

h_m_l的博客 2794

JetBrains Air:多Agent协同的IDE运行时架构解析

IDE智能编程正从单模型增强迈向多Agent协同范式。多Agent架构通过职责分离、上下文精简与运行时隔离,显著提升代码生成稳定性与合规性;其核心依赖轻量级嵌入式运行时(如ARL),支持AST级内存共享、eBPF安全拦截与毫秒级冷启动。该架构天然适配本地化部署、离线开发与高安全合规场景(如PCI-DSS、金融内网),并为Java/Python/TS等语言提供可扩展的规则驱动开发流水线。JetBrains Air正是这一技术路径的工程化落地代表。

weixin_30443075的博客 571

GDB学习总结

GDB十分钟教程 http://blog.youkuaiyun.com/liigo/article/details/582231 本文写给主要工作在Windows操作系统下而又需要开发一些跨平台软件的程序员朋友,以及程序爱好者。 GDB是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具 。 GDB中的命令固然很多,但我们只需掌握其中十

bcbobo21cn的专栏 1233

模拟电子课设-半导体直流稳压电源的设计和测试

1、学习直流稳压电源的设计方法; 2、研究直流稳压电源的设计方案; 3、掌握直流稳压电路的调试及主要指标的测试方法。二、设计要求和技术指标 1、设计要求1)、设计一个能输出5V-12V连续可调的直流稳压电源,或±12V的直流稳压电源; 2)、根据设计要求和技术指标设计好电路,选好元件及参数,要求绘出原理图,并用Protel 99SE/DXP画出印制板图; 3)、在万能板或面包板上制作一台直流稳压电源; 4)、测量直流稳压电源的稳压系数; 5)、测量直流稳压电源的内阻; 6)、拟定测试方案和设计步

GJZGRB的博客 1971

从零构建智能ai语音助手:ESP32s3+Python+大语言模型实战指南

本文详细介绍了基于ESP32S3硬件和Python后端的智能语音助手系统开发指南。系统采用ESP32S3采集语音,通过WebSocket实时传输到Python后端处理,利用大语言模型实现自然语言理解和意图识别,再通过TTS合成语音返回。文章从系统架构、工作流程、技术实现(包括OPUS编码、WebSocket通信、ESP32音频处理)等方面进行了详细讲解,并提供了分阶段学习路线和常见问题解决方案。该项目展示了物联网技术与AI技术的融合应用,相比传统语音系统具有更高的灵活性和智能性,为开发者提供了完整的实现方案

Despacito0o的博客 2630

C/C++ 函数参数和返回值传递机制

原文:C/C++ 函数参数和返回值传递机制 作者:Breaker <breaker.zy_AT_gmail> 说明 C/C++ 函数调用中,参数和返回值传递的机制,包括低级汇编指令和高级 C++ 对象拷贝构造 关键字:参数传递,返回值传递,按值传递 (passed by value),按引用传递 (passed by reference),拷贝构造 相关参考 调用约定 (...

caozuiba 472

YOLOv8改进策略【Conv和Transformer】| CVPR-2023 BiFormer 稀疏自注意力,减少内存占用

本文记录的是利用双级路由注意力机制优化的目标检测网络模型。传统的复杂度高,随着输入空间分辨率增加,计算量呈平方增长,导致严重的可扩展性问题。而本文所使用的在获取全局信息的同时,通过区域到区域路由和令牌到令牌注意力的合理设计,减少了不必要的计算量。BiFormer: Vision Transformer with Bi-Level Routing Attention采用四阶段金字塔结构,与一些先进的视觉Transformer类似。在每个阶段,首先使用重叠的补丁嵌入(在第一阶段)或补丁合并模块(在第二到第四阶段

Limiiiing的博客 614

Android 4.4.2 bluetooth解析(一)

由于开发项目的关系,最近一直在对android4.4的bluedroid

lansefeiyang08的专栏 1万+

Python爬虫教程:抓取纽约时报文章存档

爬虫技术主要用于从网站上抓取并提取数据。HTTP请求:使用requests库发送HTTP请求以获取网页。网页解析:使用或lxml库解析HTML网页。数据存储:将抓取的数据保存为CSV、JSON等格式,或者存储在数据库中。防反爬虫技术:模拟正常的用户请求,避免被反爬虫机制封锁。多线程与异步爬取:提高抓取效率。通过这篇博客,您已经学习了如何使用Python爬取纽约时报的历史文章存档。本文介绍了如何模拟请求头、抓取网页内容、解析HTML并提取数据,最后存储到CSV文件或数据库中。

2201_76125261的博客 593

游戏战斗系统架构设计的演绎之路——从一坨意大利面条到一座精密钟表

摘要:游戏战斗系统架构设计的演进之路 本文系统梳理了游戏战斗系统从早期街机到现代3A大作的架构发展历程。70-80年代的街机游戏采用基础碰撞盒判定(如《街头霸王》);90年代实现动画融合与状态机架构(《最终幻想》《拳皇》);2000年后MMO引入服务器验证与同步技术(《魔兽世界》);3D时代融合物理引擎与智能AI(《GTA5》《只狼》);移动端则发展出轻量化架构与云端判定(《王者荣耀》)。现代战斗系统已实现模块化、数据驱动和热更新,未来趋势是AI裁判与云战斗系统。这一演进过程展现了技术与创意的完美结合,数百

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 801

MSVC平台下X64处理器函数调用规则——底层机制

目录 1. 默认的调用规则 2. 内存边界对齐问题 3. 解开性(Unwindability) 4. 参数传递 5. 可变数量参数的传递 6. 非原型函数 7. 函数返回值 8. 调用函数或被调函数存储寄存器 9. 函数指针 10. 对较旧代码的浮点支持 11. 浮点状态和控制寄存器(Float Point Status and Control Register,简记为FPSCR) 12. 多媒体扩展控制和状态寄存器(Multimedia Extensions Control and

ComputerInBook的专栏 1617

i.MX6ULL驱动开发 | 31 - Linux内核网络设备驱动框架

net_device结构体在内核中指代一个网络设备,定义在,是一个非常大的结构体,包含网络设备的属性描述和操作接口,其中一些关键的成员如下。Linux在轮询处理机制和中断处理机制的基础上,提出了一种高效的网络处理技术NAPI。NAPI的核心思想是不全部采用中断来读取网络数据,而是采用中断来唤醒数据接收服务程序,在接收服务程序中采用poll的方法来轮询处理数据。提高短数据包的接收效率,减少中断处理的时间。...

Mculover666的博客(嵌入式) 1103

MSVC平台下X64 ABI规则

本节描述X64架构(X86架构的64位扩展)的基本应用程序二进制接口(Application Binary Interface,简记为ABI)。这个主题的内容包括函数调用规则、类型分布、栈和寄存器用法、以及其它内容。 1. X64调用规则概述 X64与X86之间重要的两个区别是64位的寻址能力和一套平坦的16个16位通用寄存器。给定扩展的寄存器集,X64使用 __fastcall调用规则和基于RISC(Reduced Instruction Set Computer)的异常处理模型。__fast...

ComputerInBook的专栏 1368

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

VSCode开发C、C++环境搭建系列(三)——基于MSVC搭建

前言:本文为系列文章的第三篇,讲解如何利用Windows C++(MSVC)结合VS Code搭建一个完整的开发环境,前面的两篇文章参考下面: VSCode开发C、C++环境搭建系列(一)——基于Mingw-w64搭建 VSCode开发C、C++环境搭建系列(二)——GCC/G++编译器对头文件、静态库、动态库的搜索路径详解 详细关于MSVC的使用可以参考官方网站: https://d...

MIss-Y的博客 9559

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

用mingw链接msvc生成的库时,无定义chkstk问题的解决

在用mingw链接msvc生成的库时常常产生这样的链接错误: undefined reference to `_chkstk' 这是因为chkstk is a stack-probing thing that MSVC generates whenallocating big stack frames), and that GCC has an equivalent inlibgcc (cal

学习是为了探索这个世界的本质 6008

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

逆向基础(三)

reverse-engineering · 2014/05/15 17:23CHAPER7访问传递参数现在我们来看函数调用者通过栈把参数传递到被调用函数。被调用函数是如何访问这些参数呢?#!cpp #include <stdio.h> int f (int a, int b, int c) { return a*b+c; }; int main() { ...

weixin_33970449的博客 753

MSVC CRT运行库启动代码分析

原文链接:http://www.programlife.net/msvc-crt-startup.html 在程序进入main/WinMain函数之前,需要先进行C运行库的初始化操作,通过在Visual Studio中调试,通过栈回溯可以找到位于crt0.c中的_tmainCRTStartup函数,这个函数负责进行一些初始化操作,_tmainCRTStartup的上一层调用来自kernel32....

weixin_30337251的博客 305

程序员自我修养阅读笔记——运行库

主要关注程序的启动过程。 1 入口函数和程序初始化 1.1 程序真正的入口   通常写代码时,我们认为程序的入口是main函数,但是实际上有一些现象值得我们怀疑该结论是不是正确的。比如全局变量的初始化,C++全局变量构造函数的调用,C++静态对象的构造函数调用。   程序开始运行的入口不是main,在进入main之前程序会先准备好环境运行一些必要的代码才进入main,运行这些代码的函数称为入口函数。入口函数根据平台的不同而不同,其实实际上程序初始化和结束的地方,一个典型的程序的运行步骤如下: 操作系统.

梦的灰色边沿... 6847

C++(MSVC) 下查看call strack trace;查看函数是否被inline

[size=large]最近写C++程序,,各种不知道错误出在哪一行,即使输出了行号,也没用,因为不知道哪一次调用出的错,程序bug处离调用位置很远,要调程序不得不一行行的调![/size] 后来发现个好东西: StackWalker(仅限MSVC): [url]http://www.codeproject.com/Articles/11132/Walking-the-callstack...

LC 330

windows内核开发学习笔记五十:x64调用协定

本篇文章描述x64代码中一个函数(调用方)用来调用另一个函数(被调用方)的标准流程和约定。 调用约定违约 x64应用程序二进制接口(ABI)默认使用四个寄存器的快速调用约定。在调用堆栈上分配空间作为一个影子存储,供调用者保存这些寄存器。 在函数调用的参数和用于这些参数的寄存器之间有严格的一对一对应关系。任何不适合8字节的参数,或者不是1、2、4或8字节的参数,都必须通过引用传递。一个参数永远不会分布在多个寄存器上。 x87寄存器堆栈未被使用。被调用方可能会使用它,但是在函数调用中它是vo

jyl_sh的专栏 1852

x64异常处理

;-------------------------------------------------------------------------------- ;请访问64位汇编语言官方站 [url]Http://Www.X64Asm.Com[/url] ;电子邮件 [email]Jxc25@X64Asm.Com[/email] Tel:130******** ;------------

多媒体编程、网络编程、系统编程、网络安全编程、驱动编程 1898

异常处理 (x64)

异常处理 (x64) Visual Studio 2013 其他版本 此主题尚未评级 - 评价此主题 本节论述 x64 上的结构化异常处理和 C++ 异常处理行为。 为异常处理和调试器支持展开数据 展开过程 语言特定处理程序 MASM 的展开帮助器 C 中的展开

多媒体编程、网络编程、系统编程、网络安全编程、驱动编程 1288

Function Prolog and Epilog

Part1Below is the test code I am using:#include<stdio.h>#include<windows.h> void main(){__try{int i=1;}__except(EXCEPTION_EXECUTE_HANDLER){printf("EXCEPTION_EXECUTE_HANDLER\n");...

weixin_33939380的博客 231
上一篇: MSVC平台下X64 ABI规则
下一篇: C语言数组指针加1的问题
ComputerInBook
博客等级 码龄19年 1168粉丝 464原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值