Linux/Unix平台X64函数调用约定

C/C++固定地址函数调用:原理、场景与安全实践 函数指针是C/C++编程中的核心概念,它存储了函数的入口地址,是实现回调、动态行为和多态的基础。其工作原理在于将函数名转换为内存中的具体地址,通过地址间接调用代码,这为程序带来了极大的灵活性。在系统编程、插件架构、性能优化等领域,直接操作函数地址的技术价值凸显,它允许开发者绕过常规的链接过程,实现动态库的手动加载、特定函数的直接跳转或与二进制接口交互。尤其是在需要与缺乏头文件的第三方库、系统底层API或动态生成的代码(如Shellcode)打交道时,这种对内存布局和调用约定的深入控制变得至关重要。本文聚焦于 阅读详情

目录

1. System V AMD64 ABI约定

2. System V AMD64 ABI的栈帧结构


X64调用约定利用寄存器来传递部分函数参数,不规范的函数调用规则逐渐减少。现主要有两种比较通用的函数调用规则。一种是Microsoft X64函数调用约定,参见以下链接:MSVC平台下X64处理器函数调用规则——底层机制_ComputerInBook的博客-优快云博客目录1. 默认的调用规则2. 内存边界对齐问题3. 解开性(Unwindability)4. 参数传递5. 可变数量参数的传递6. 非原型函数7. 函数返回值8. 调用函数或被调函数存储寄存器9. 函数指针10. 对较旧代码的浮点支持11. 浮点状态和控制寄存器(Float Point Status and Control Register,简记为FPSCR)12. 多媒体扩展控制和状态寄存器(Multimedia Extensions Control andhttps://blog.youkuaiyun.com/ComputerInBook/article/details/124342574

另一种是System V AMD64 函数调用约定(即Application Binary Interface,简记为ABI)。这里主要讲System V AMD64约定的规则。

遵循System V AMD64 ABI约定的操作系统平台主要有:Solaris, Linux, FreeBSD, macOS,等等。是很多Unix和类Unix操作系统事实上的ABI标准。OpenVMS的X64 ABI调用约定基于System V ABI调用标准,并做了一些后向兼容的扩展。

1. System V AMD64 ABI约定

    前6个整数参数(整型参数或指针参数)使用RDI, RSI, RDX, RCX, R8, R9这6个寄存器传递(在嵌套函数的情况下,R10 用作静态链指针);XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 和 XMM7用于传递前8个浮点参数。超出规定寄存器个数的参数采用内存栈传递。整数返回值最多64位,存储在RAX中以返回;如果返回值达到128位,存储在RAX和RDX中以返回。类似地,64位浮点值放在寄存器XMM0以返回,128位浮点值放在寄存器XMM0和XMM1以返回。如果存在更宽位的值,使用YMM寄存器和ZMM寄存器传递参数及返回值。用于传递参数的寄存器如下图:

参数类型

寄存器

整数参数 1-6

RDI, RSI, RDX, RCX, R8, R9

浮点参数 1-8

XMM0 - XMM7

超出部分的参数

内存栈

静态链指针

R10

如果被调函数期望使用寄存器RBX, RSP, RBP, and R12–R15(称为易失性寄存器),则在返回被调函数之前,必须恢复它们在使用之前的值;如果调用函数期望恢复所有其它寄存器调用前的值,则在使用之前必须先保存这些寄存器的值。

   对于叶函数(leaf-node function,即,没有进一步函数其它调用的函数),在栈指针之下保留了128字节的空间。这段空间称为红色区域(red zone)。这块区域不能被任何信号或中断处理器占用。因此,编译器可以使用这块区域来保存局部变量。编译器通过使用这块区域来忽略函数开头的一些指令(调整寄存器RSP,RBP)。然而,其它函数可以占用这块区域,因此,这块区域应当仅用于叶函数。gcc和clang使用-mno-red-zone标识来禁止对红色区域的优化。

    对于被调函数是可变参数函数(variadic function)的情况,以向量寄存器传递浮点参数的数量必须由调用函数在寄存 器AL寄存器中指定。

    与Microsoft调用不同的是,系统并没有提供影子内存(shadow space),而是,在函数入口点,返回地址在栈上紧邻第7个整型函数参数。

    栈空间采用16字节边界对齐方式。在栈之下保留有128字节的红色区域。内核接口使用RDI, RSI, RDX, R10, R8 和R9寄存器。在C++类函数中,this是第一个参数。

2. System V AMD64 ABI的栈帧结构

    除了寄存器之外,每个函数在运时栈上都拥有一个函数栈帧。这个栈帧的方向为从高地址向低地址向下递减。下图为栈帧结构:

位置

内容

栈帧

8n+16(%rbp)

内存参数8字节n

      ...

内存参数8字节0

高地址

8(%rbp)

0(%rbp)

-8(%rbp)

0(%rbp)

-128(%rbp)

返回地址

当前地址

前一个%rbp值

未指定

...

变量大小

红色区域

 在输入参数和末尾,将按16字节边界对齐(如果使用在栈上传递__m256大小的整数,则采用32字节的边界对齐方式)。换句话说,当控制权交给函数入口头的时候,(%rsp+8)的值总是16(32)的倍数。栈指针%rsp总是指向最新分配的栈的底端。%rsp指向的位置以外的 128 字节区域被认为是保留的,不应被信号或中断处理程序修改。因此,函数可以使用此区域存储局部变量。特别是,叶函数使用这个区域作为其整个栈帧,而不是作为序言和结语的代码去调整栈桢。

C/C++编译移植与C#跨平台实现:核心技术差异与实战选型指南 跨平台开发是软件工程中的核心挑战,其本质在于如何让同一套代码在不同操作系统和硬件架构上运行。从技术原理上看,主要存在两种实现路径:一种是通过编译器将源代码直接编译为特定平台的原生机器码,另一种是借助中间语言和运行时环境实现“一次编写,到处运行”。前者以C/C++为代表,依赖源码级兼容和条件编译,通过GCC、Clang、MSVC等工具链生成高性能二进制文件,但需要开发者手动处理平台API差异。后者以C#和.NET平台为典型,代码被编译为中间语言(IL),由.NET运行时(如.NET Core)的JIT编译器动 阅读详情

相关推荐

从二进制到Flag:x64 ELF逆向工程实战与CTF解题全流程解析

逆向工程是理解程序内部逻辑、分析软件行为的关键技术,广泛应用于安全研究、漏洞分析和CTF竞赛。其核心原理在于通过静态与动态分析相结合的方法,将机器码还原为可理解的逻辑。这项技术的价值在于能够深入剖析软件工作机制,发现潜在漏洞或验证程序安全性。在应用场景上,它不仅是安全研究人员的必备技能,也是开发者进行代码审计和性能分析的有效手段。本文聚焦于x64架构的ELF可执行文件,详细阐述了从初始信息收集、使用IDA Pro进行静态反汇编,到利用GDB进行动态调试跟踪的完整实战路径。通过结合具体案例,文章深入探讨了如何

weixin_33778544的博客 291

linux C语言编程 - 设置函数调用约定

linux C语言编程 函数 调用约定 stdcall cdecl

wjg220000的博客 396

OpenClaw全平台部署深度指南:Rust跨平台CLI实战

CLI(命令行界面)是现代AI工作流自动化的核心载体,其跨平台一致性直接决定运维效率与系统稳定性。本文围绕Rust构建的CLI工具OpenClaw,解析其如何通过编译目标控制、文件系统抽象与进程管理统一,在Windows、Linux、macOS三大平台实现‘一份配置、一次部署、全域生效’的技术闭环。重点涵盖SHA256校验保障分发可信性、环境变量契约规避路径冲突、systemd/launchd/winsw服务化封装等工程实践要点,并深入剖析PowerShell执行策略、macOS Gatekeeper拦截、

weixin_34199405的博客 377

AMD64/X86-64 ABI (System V Application Binary Interface)

X86-64/AMD64 ABI

zhangxiang0503的博客 2288

分清C#语言与.NET平台:跨平台开发的认知基石

编程语言是语法契约,平台是运行时生态——这是理解现代跨平台开发的起点。C#作为一门语言,其代码通过编译生成中间语言(IL),真正决定执行能力的是底层平台实现(如CoreCLR、Mono)和目标配置(如iOS AOT限制)。这种语言与平台的解耦,赋予了.NET跨平台能力的技术合理性,也解释了为何同一段C#代码在Windows、Linux或iOS上行为迥异。它支撑起Xamarin、.NET MAUI等框架的工程实践,更直接影响API兼容性、P/Invoke可用性及反射支持等关键决策。掌握这一分层模型,是构建可移

diaozhiwa5526的博客 393

C++协程库实现:从函数调用栈到异步调度的核心原理与实践

在并发编程领域,协程作为一种轻量级的用户态线程,能够显著提升高并发场景下的程序性能与开发体验。其核心原理在于通过保存和恢复执行上下文(包括栈指针、指令指针等寄存器状态),实现在用户态的任务切换,避免了传统线程切换带来的内核态开销。这一机制的技术价值在于能够以同步的代码风格编写异步逻辑,极大简化了高并发网络编程的复杂度。在应用场景上,协程常与I/O多路复用(如epoll)结合,构建高效的事件驱动架构,广泛应用于网络服务器、游戏引擎等需要处理大量并发连接的领域。本文聚焦于构建C++协程库所需的关键前置知识,深入

weixin_30681121的博客 401

x86_64汇编之五:System V AMD64调用约定下的函数调用

之前提到了,System V AMD64调用约定是x86_64 Linux系统上使用最广泛的调用约定,gcc/g++等编译器都默认使用该调用约定。 凡是遵循System V AMD64调用约定的汇编代码,都有一定的固定模式,比如函数开头做哪些处理,函数末尾做哪些处理等等。遵循该约定的函数一般是如下的模式。 Caller的操作 在调用callee之前,通常有以下操作: 步骤1:设置参数到寄存器/栈中 mov xxx, %rdi # 第一个参数 mov xxx, %rsi # 第二个参数 mov xxx,

qq_29328443的博客 3023

System V Application Binary Interface - AMD64 Architecture

System V Application Binary Interface - AMD64 Architecture Processor Supplement-abi

x86_64汇编之四:函数调用、调用约定

一、栈 栈一般从高地址往低地址生长,每个函数都在栈空间中对应一个栈帧。关于栈帧有两个重要的指针——栈基址指针BP和栈顶指针SP。其中,除了在函数的开头和结尾(后面会讲到),BP指针一般是固定不变的,通常以它为基准来寻址参数和局部变量,例如将第一个参数放入栈中的汇编代码可以是movq %rdi, -8(%rbp)。 和栈相关的两个指令是push和pop。在x86_64架构的计算机上,push operand指令的作用是: 将栈顶指针rsp减去8(即8字节) 然后将目标操作数放入更新后的rsp所指向的地址

qq_29328443的博客 1万+

SpringBoot+Git+Jenkins+K8s容器化部署

SpringBoot+Git+Jenkins+K8s容器一套部署流程

可乐加.糖 471

小米路由器安装Misstar tools 和MIXBOX

1.该教程适用于如下路由器: 小米路由器1代硬盘版(R1D) 小米路由器mini(R1CM) 全新小米路由器硬盘版(R2D) 小米路由器3(R3) 小米路由器3G(R3G) 小米路由器Pro(R3P) 小米路由器HD(R3D) 2.Misstar2.0在线安装 方法如下: 1.根据路由器对应文件解压文件,把解压目录(比如小米3路由器为R3)和offline_install.sh到U盘根目录,并插入路由器 2.ssh登录后,cd到U盘的目录,比如小米3路...

wybarcelona的博客 2万+

Linux 下的 x64 调用约定

linux x64 调用约定 __fastcall

xkdlzy的专栏 3788

从‘眼花缭乱’到‘心中有数’:rs-fMRI统计分析全流程避坑指南(附DPABI操作截图)

本文详细解析了rs-fMRI统计分析的全流程,从质量控制到统计模型选择,再到多重比较校正和结果解读。特别针对DPABI软件操作中的常见陷阱提供实用指南,帮助研究者避免FDR和GRF校正等关键环节的错误,实现从数据混乱到清晰分析的转变。

weixin_33686714的博客 398

x64架构下Linux系统函数调用

call指令会将当前指令寄存器中的内容(即这条call指令下一条指令的地址,也就是函数执行完的返回地址)入栈,然后跳到函数对应的地址开始执行。ret指令用于从子函数中返回,ret指令会先弹出当前栈顶的数据,这个数据就是先前调用这个函数的call指令压入的“下一条指令的地址”,然后跳转到这个地址执行。ret指令用于从子函数中返回,ret指令会先弹出当前栈顶的数据,这个数据就是先前调用这个函数的call指令压入的“下一条指令的地址”,然后跳转到这个地址执行。pop指令将数据出栈并写入寄存器。

qq_38350702的博客 479

深交所 vs 上交所:Level-2实时数据推送规则详解与策略适配指南

本文深度解析沪深Level-2实时数据推送规则的关键差异,包括逐笔成交、逐笔委托和10档行情接口的处理逻辑。针对高频交易策略,详细对比上交所与深交所在数据推送机制、时间戳处理及委托队列解析等方面的差异,并提供具体的策略适配方案和性能优化建议,帮助量化投资者提升跨市场交易稳定性。

weixin_27310417的博客 1165

996引擎 - 读写变量性能测试

单轮100万次读写,取3轮平均耗时(毫秒),有效读取率均为100%,数值越小性能越优。

灵台方寸山斜月三星洞 244

x64不同平台的调用约定

x64的ABI在Unix(Linux,Mac OS)上和Windows上是不同的,调用约定有区别。wikipedia上对调用约定的解释调用约定的不同(寄存器传参部分)

u011553241的博客 1143

Linux系列:SecurtCRT中的密码如何找回

【代码】Linux系列:SecurtCRT中的密码如何找回。

NIO4444 1086

一百八十七

一、 函数调用相关指令 关于栈可以看下我之前的这篇文章x86 CPU与IA-32架构 在开始函数调用约定之前我们需要先了解一下几个相关的指令 1.1 push pushq 立即数 # q/l是后缀,表示操作对象的大小 pushl 寄存器 push指令将数据压栈。具体就是将esp(stack pointer)寄存器减去压栈数据的大小,再将数据存储到esp寄存器所指向的地址。 1.2 pop popq 寄存器 popl 寄存器 pop指令将数据出栈并写入寄存器。具体就是将数据从esp寄存器所指向的地址加载到指令

ouhou999的博客 228

ShardingSphere 5.3 系列Spring 配置升级指南 | Spring Cloud 47

在 `5.3.0` 版本以前,`ShardingSphere-JDBC` 同时支持 `Java API`、`YAML`、`Spring Boot Starter` 和 `Spring Namespace` 等配置方式。 - 当新增或更新 API 时,需要调整多项配置文件,工作量大 - 社区需要维护多重配置文档和示例 - `Spring Bean` 生命周期管理容易受到项目其他依赖的影响,比如 `PostProcessor` 无法正常执行 - `Spring Boot Starter` 和 `Spring N

gmHappy 2万+

Python计算时间差的方法

使用datetime模块是Python内置的方法,使用timedelta对象可以更精确地计算时间差,而使用dateutil库则提供了更为灵活和方便的操作方式。我们可以使用datetime模块中的datetime类来表示一个具体的日期和时间,并进行相应的运算。在Python中,我们经常需要计算日期和时间之间的差异,例如计算两个日期之间的天数、小时数、分钟数等。Python提供了多种方法来计算时间差,下面我们将介绍其中的几种常用方法,并附上相应的源代码。在上面的代码中,我们使用了dateutil库中的。

学习使你进步。 2086

Unix和Linux平台上大文件的拆分和合并

    昨天下载Solaris时候,发现文件是拆分过的两部分,然后官方有文件合并的介绍,原文如下:================================================一.iso拆分文件的下载由于SAID的iso文件的大小在2GB以上,而某些常用的下载工具(诸如FlashGet、NetAnt、 IE浏览器等)无法下载超过2GB的文件,所以将SAID的iso文件拆分成若干个...

燕子钨 415

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

JavaCEF跨平台构建部署终极实战:嵌入式浏览器三平台一键分发完整指南

JavaCEF(Java Chromium Embedded Framework)让你用纯 Java 代码在桌面应用中嵌入 Chromium 内核浏览器,并保持 Windows、Linux、macOS 三平台行为一致。本文不走"按平台逐章讲解"的老路,而是围绕新手最容易踩的 5 个坑展开,以"避开每个坑"为线索,带你从环境准备一路走到三平台构建、打包与验证,读完即可完成一次真实的跨平台部署闭环。?

gitblog_00344的博客 921

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

一文吃透 java-cef 的跨平台构建部署:Windows、Linux、macOS 三端从零发布实战

java-cef(Java Chromium Embedded Framework,简称 JCEF)能把完整的 Chromium 浏览器内核嵌入 Java 桌面程序,让同一套 Web 界面在 Windows、Linux、macOS 三端原生运行。本文以"给运维团队打造一个内嵌 Web 界面的控制台客户端"为贯穿示例,带你走完从环境准备、三平台构建到打包发布的完整跨平台构建部署流程,读完即可照做。

gitblog_01013的博客 1151

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

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

深入解析C程序机器表示:从编译链接到函数调用栈与逆向分析

程序的机器表示是计算机科学的核心概念,它描述了高级语言代码如何被翻译成CPU可直接执行的二进制指令。其基本原理涉及编译器将源代码转换为汇编指令,再经由汇编器和链接器生成可执行文件,最终在内存中形成特定的数据与指令布局。理解机器表示的技术价值在于,它不仅是程序运行的基石,更是进行性能优化、漏洞分析和系统调试的关键。例如,在软件安全领域,分析缓冲区溢出等漏洞必须深入理解栈内存布局;在逆向工程中,解读二进制程序的行为也依赖于对函数调用约定和内存结构的掌握。本文聚焦于C语言程序的机器表示,特别是函数调用栈的详细机制

weixin_33709219的博客 347

跨平台C++开发实战:架构设计、工具链与平台适配全解析

跨平台开发是软件工程中的核心挑战之一,其本质在于通过统一的技术方案解决不同操作系统、硬件架构和系统API之间的差异。从原理层面看,这通常涉及构建平台抽象层(PAL)来封装平台特定实现,使业务逻辑与底层细节解耦。在技术价值上,跨平台方案能显著提升代码复用率、降低维护成本,并确保应用在多种环境下行为一致。常见的应用场景包括游戏引擎、工业控制软件、音视频处理和高频交易系统等对性能和可控性要求极高的领域。本文基于CMake构建系统和现代C++标准,深入探讨了如何通过条件编译、抽象接口以及持续集成等工程实践,构建健壮

weixin_30596023的博客 488
上一篇: 为什么要学习汇编语言
下一篇: 64位汇编语言中的符号位扩展说明
ComputerInBook
博客等级 码龄19年 1168粉丝 464原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值