C语言传参寄存器压栈流程总结

news2025/4/17 6:17:04

相关
《Linux函数调用栈的实现原理(X86)》

总结

rsp向低地址生长(栈顶),rbp记录旧值(栈底)。

  1. intel x86测试,六个和六个以内的参数用寄存器传递。
  2. 8个参数场景,6个用寄存器传递,2个用栈帧传递:
    • 调用者caller使用rsp指针准备参数,先让rsp向低地址生长一段空间,然后用rsp+偏移的方式准备调用。
    • 被调用者callee使用rbp指针接受参数,rsp先生长到callee的frame,然后rbp指向rsp,然后rbp-偏移的方式将参数写入callee的栈帧。注意这里写入的只有从寄存器里面读出来的参数。
  3. 被调用者callee如果需要使用寄存器传递的参数,使用rbp-偏移量的方式寻找local变量。
  4. 被调用者callee如果需要使用栈帧传递的变量,使用rbp+偏移量,寻找调用者放在栈帧中的变量。

在这里插入图片描述

前言

C语言传参使用寄存器+压栈的方式,这里对传参的细节流程做一些分析记录。

《Modern Compiler Implementation in C》中提到:

在这里插入图片描述

分析过程

示例代码:gcc -O0 t.c -o t -g

void foo(int a, int b, long c, long d, int e, int f, int g, long h) {
    int bar[4];
}

int main(void) {
    foo(1, 2, 3, 4, 5, 6, 7, 8);
}

main函数disassemble

main

(gdb) disassemble /m main
Dump of assembler code for function main:
5	int main(void) {
   0x0000000000400509 <+0>:	push   %rbp
   0x000000000040050a <+1>:	mov    %rsp,%rbp
   0x000000000040050d <+4>:	sub    $0x10,%rsp

6	    foo(1, 2, 3, 4, 5, 6, 7, 8);
   0x0000000000400511 <+8>:		movq   $0x8,0x8(%rsp)   // movq 8字节
   0x000000000040051a <+17>:	movl   $0x7,(%rsp)      // movl 4四字节
   0x0000000000400521 <+24>:	mov    $0x6,%r9d
   0x0000000000400527 <+30>:	mov    $0x5,%r8d
   0x000000000040052d <+36>:	mov    $0x4,%ecx
   0x0000000000400532 <+41>:	mov    $0x3,%edx
   0x0000000000400537 <+46>:	mov    $0x2,%esi
   0x000000000040053c <+51>:	mov    $0x1,%edi
   0x0000000000400541 <+56>:	callq  0x4004ed <foo>

7	}
   0x0000000000400546 <+61>:	leaveq
   0x0000000000400547 <+62>:	retq

End of assembler dump.

stack frame初始状态

high address
-------------------- <- rbp

   frame (main)

-------------------- <- rsp
low address

旧的rbp保存起来,进入新函数main。

push %rbp
mov %rsp,%rbp

high address
-------------------- <- 

   frame (main)

-------------------- <- rsp / rbp
low address

注意这里rsp向下继续生长了16字节,用来放调用foo函数的入参。

sub $0x10,%rsp

high address
-------------------- <- 

   frame (main)

-------------------- <- rbp

  分配16字节,准备放参数

-------------------- <- rsp
low address

8个字节放参数8
4个字节放参数7

movq $0x8,0x8(%rsp)
movl $0x7,(%rsp)

high address
-------------------- <- 

   frame (main)

-------------------- <- rbp
   8 Byte            << 写入第8个参数
   4 Byte            << 写入第7个参数
-------------------- <- rsp
low address

mov $0x6,%r9d
mov $0x5,%r8d
mov $0x4,%ecx
mov $0x3,%edx
mov $0x2,%esi
mov $0x1,%edi

写入1-6参数到寄存器

注意e开头的寄存器是32位的,因为参数是int四字节够用。是拿64位寄存器用了一半。
注意r开头的寄存器是64位的,因为参数是long八字节,用完整的寄存器。

callq 0x4004ed

0x4004ed是低地址存放代码段的
callq的过程,会把rsp向下继续生长一段空间,



high address
-------------------- <- 

   frame (main)

-------------------- <-
   8 Byte            << 写入第8个参数
   4 Byte            << 写入第7个参数
-------------------- <- rbp

callq后rsp向低地址移动

-------------------- <- rsp

low address

foo函数disassemble

(gdb) disassemble /m foo
Dump of assembler code for function foo:
1	void foo(int a, int b, long c, long d, int e, int f, int g, long h) {
   0x00000000004004ed <+0>:	push   %rbp
   0x00000000004004ee <+1>:	mov    %rsp,%rbp
   0x00000000004004f1 <+4>:	mov    %edi,-0x14(%rbp)
   0x00000000004004f4 <+7>:	mov    %esi,-0x18(%rbp)
   0x00000000004004f7 <+10>:	mov    %rdx,-0x20(%rbp)
   0x00000000004004fb <+14>:	mov    %rcx,-0x28(%rbp)
   0x00000000004004ff <+18>:	mov    %r8d,-0x2c(%rbp)
   0x0000000000400503 <+22>:	mov    %r9d,-0x30(%rbp)

2	    int bar[4];
3	}
   0x0000000000400507 <+26>:	pop    %rbp
   0x0000000000400508 <+27>:	retq

End of assembler dump.

push %rbp
mov %rsp,%rbp

旧的rbp保存起来,进入新函数main,rbp指向新的栈顶(低地址)。

注意这里只存了6个参数,但是函数有8个入参,原因是有两个入参main函数已经放好了。

mov %edi,-0x14(%rbp)
mov %esi,-0x18(%rbp)
mov %rdx,-0x20(%rbp)
mov %rcx,-0x28(%rbp)
mov %r8d,-0x2c(%rbp)
mov %r9d,-0x30(%rbp)


high address
-------------------- <- 

   frame (main)

-------------------- <-
   8 Byte            << 写入第8个参数
   4 Byte            << 写入第7个参数
-------------------- <- 

callq后rsp向低地址移动

-------------------- <- rsp / rbp
写入参数1
写入参数2
写入参数3
写入参数4
写入参数5
写入参数6
--------------------
low address

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2330507.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C盘清理——快速处理

C盘清理 | 快速处理 软件&#xff1a;小番茄C盘清理 https://ccleancdn.xkbrowser.com/cleanmaster/FanQieClean_13054_st.exe 前言&#xff1a;为什么需要专业的C盘清理工具&#xff1f; 作为一位长期与Windows系统打交道的技术博主&#xff0c;我深知C盘空间不足带来的痛苦…

前端服务配置详解:从入门到实战

前端服务配置详解&#xff1a;从入门到实战 一、环境配置文件&#xff08;.env&#xff09; 1.1 基础结构 在项目根目录创建 .env 文件&#xff1a; # 开发环境 VUE_APP_API_BASE_URL http://localhost:3000/api VUE_APP_VERSION 1.0.0# 生产环境&#xff08;.env.produc…

历年跨链合约恶意交易详解(四)——Chainswap20210711

漏洞合约函数 function receive(uint256 fromChainId, address to, uint256 nonce, uint256 volume, Signature[] memory signatures) virtual external payable {_chargeFee();require(received[fromChainId][to][nonce] 0, withdrawn already);uint N signatures.length;r…

Python基于OpenCV和SVM实现中文车牌识别系统GUI界面

说明&#xff1a;这是一个系统实战项目&#xff0c;如需项目代码可以直接到文章最后关注获取。 项目背景 随着智能交通系统和智慧城市的发展&#xff0c;车牌识别技术在车辆管理、交通监控、停车场收费等领域发挥着重要作用。传统的车牌识别系统主要针对英文和数字的识别&…

有瓶颈设备的多级生产计划问题:基于Matlab的深度解析与实践

内容摘要 本文围绕有瓶颈设备的多级生产计划问题展开&#xff0c;通过实例详细阐述问题背景、建立数学模型&#xff0c;并用Matlab代码进行求解。旨在帮助读者理解该问题的本质&#xff0c;掌握利用Matlab解决此类生产计划优化问题的方法&#xff0c;为企业在实际生产中合理规…

网络性能优化参数关系解读 | TCP Nagle / TCP_NODELAY / TCP_QUICKACK / TCP_CORK

注&#xff1a;本文为 “网路性能优化” 相关文章合辑。 未整理去重。 如有内容异常&#xff0c;请看原文。 TCP_NODELAY 详解 lenky0401 发表于 2012-08-25 16:40 在网络拥塞控制领域&#xff0c;Nagle 算法&#xff08;Nagle algorithm&#xff09;是一个非常著名的算法&…

如何将内网的IP地址映射到外网?详细方法与步骤解析

01 为什么需要将内网IP映射到外网 在当今数字化时代&#xff0c;远程访问内网资源已成为许多企业和个人的刚需。将内网IP地址映射到外网的主要目的是允许外部网络访问内网中的特定服务&#xff0c;比如Web服务器、远程桌面、文件共享等应用场景。无论是企业需要远程办公访问内…

HTTP 响应头 Strict-Transport-Security 缺失漏洞

HTTP 响应头 Strict-Transport-Security 缺失漏洞 这个漏洞就是说明网站的HTTP响应头中没有设置Strict-Transport-Security&#xff0c;没有设置则可以通过将https自己手动改成htttp的方式进行访问。不安全 解决方法 1.nginx配置 nginx中增加如下配置&#xff1a; location / …

【SPSS/EXCEl】主成分分析构建__综合评价指数

学习过程中实验操作的记录 1.数据准备和标准化&#xff1a; (1)区分正负相关性:判断每个因子是正向指标还是负向指标,计算每个的最大值和最小值 (2) 标准化: Min-Max标准化 Min-Max标准化&#xff08;最大最小值法&#xff09;&#xff1a; 将数据映射到指定的区间&#xff…

电池分选机:新能源时代的品质守护者|深圳比斯特自动化

在这个新能源蓬勃发展的时代&#xff0c;电池作为能量的存储与释放单元&#xff0c;其性能与质量直接关系到整个系统的稳定运行与效率提升。而电池分选机&#xff0c;作为电池生产流程中的关键一环&#xff0c;正扮演着品质守护者的角色&#xff0c;为新能源产业的高质量发展保…

STM32江科大----IIC

声明&#xff1a;本人跟随b站江科大学习&#xff0c;本文章是观看完视频后的一些个人总结和经验分享&#xff0c;也同时为了方便日后的复习&#xff0c;如果有错误请各位大佬指出&#xff0c;如果对你有帮助可以点个赞小小鼓励一下&#xff0c;本文章建议配合原视频使用❤️ 如…

顺序表——C语言实现

目录 一、线性表 二、顺序表 1.实现动态顺序表 SeqList.h SeqList.c Test.c 问题 经验&#xff1a;free 出问题&#xff0c;2种可能性 解决问题 &#xff08;2&#xff09;尾删 &#xff08;3&#xff09;头插&#xff0c;头删 &#xff08;4&#xff09;在 pos 位…

LTSPICE仿真电路:(二十六)跨阻放大器简单仿真

1.前言 由于有个机会刚好了解了下跨阻&#xff0c;简单做个这个仿真&#xff0c;实际上跨阻放大器应该要复杂的多&#xff0c;由于跨阻放大器实际上是将电流转换为电压&#xff0c;最需要注意的参数肯定是运放的偏置电流 2.跨阻放大器仿真 这篇是纯记录 这是一个将0-50uA电流…

特辣的海藻!15

题 1.迷宫 - 蓝桥云课 2.外卖店优先级 - 蓝桥云课 3.后缀表达式 - 蓝桥云课 题 1.迷宫 - 蓝桥云课 import java.util.*;public class Main {static class Node {int x;int y;String str;public Node(int x, int y, String str) {this.x x;this.y y;this.str str;} …

算法-- js排序

汇总 注&#xff1a;以下log n 是 O(log2n) 注&#xff1a;快速排序实际应用中通常最优&#xff0c;但需避免最坏情况。 1 快速排序 [快速排序的思路] 分区&#xff1a;从数组中任意选择一个“基准”&#xff0c;所有比基准小的元素放在基准前面&#xff0c;比基准大的元素…

stm32week10

stm32学习 七.CAN 7.STM32 CAN外设 标识符过滤器&#xff1a; 每个过滤器的核心由两个32位寄存器组成&#xff1a;R1[31:0]和R2[31:0] FSCx&#xff1a;位宽设置&#xff0c;置0为16位&#xff0c;置1为32位 FBMx&#xff1a;模式设置&#xff0c;置0为屏蔽模式&#xff0c;…

看雪 get_pwn3(2016 CCTF 中的 pwn3)

get_pwn3(2016 CCTF 中的 pwn3) 格式化字符串漏洞 get_pwn3(2016 CCTF 中的 pwn3) (1) motalymotaly-VMware-Virtual-Platform:~/桌面$ file pwn3 pwn3: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, …

python全栈-JavaScript

python全栈-js 文章目录 js基础变量与常量JavaScript引入到HTML文件中JavaScript注释与常见输出方式 数据类型typeof 显示数据类型算数运算符之加法运算符运算符之算术运算符运算符之赋值运算符运算符之比较运算符运算符之布尔运算符运算符之位运算符运算符优先级类型转换 控制…

操作系统概述(3)

批处理系统 1.单道批处理系统 单道批处理系统是成批地处理作用&#xff0c;并且始终只有一道作业在内存中的系统。优点&#xff1a;提高系统资源的利用率和系统吞吐量。缺点&#xff1a;系统中的资源得不到充分利用。 2.多道批处理系统 引入多道程序设计技术&#xff0c;是…

SolidWorks2025三维计算机辅助设计(3D CAD)软件超详细图文安装教程(2025最新版保姆级教程)

目录 前言 一、SolidWorks下载 二、SolidWorks安装 三、启动SolidWorks 前言 SolidWorks 是一款由法国达索系统&#xff08;Dassault Systmes&#xff09;公司开发的三维计算机辅助设计&#xff08;3D CAD&#xff09;软件&#xff0c;广泛用于机械设计、工程仿真和产品开…