You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取函数调用时传入的未知数量参数(含栈中剩余参数)?

处理x86-64可变参数的两个关键问题

1. 如何访问栈上传入的未知数量参数?

在x86-64的System V AMD64调用约定下,可变参数的传递规则是固定的:前6个参数靠%rdi、%rsi、%rdx、%rcx、%r8、%r9这6个寄存器传递,剩下的参数会被调用者依次压入栈中(栈向下增长,所以第7个参数的地址最靠近返回地址)。

要访问栈上的这些参数,你需要先在函数内建立好栈帧,然后通过基指针%rbp来定位:

ft_function:
    push %rbp          ; 保存旧的基指针
    movq %rsp, %rbp    ; 让rbp指向当前栈顶,建立栈帧

此时栈帧的布局很清晰:

  • %rbp 指向旧的%rbp值
  • %rbp + 8 是调用者通过call指令压入的返回地址
  • %rbp + 16 就是栈上的第7个参数,%rbp + 24是第8个,以此类推(每个参数占8字节,64位架构下的标准宽度)

如果想把前6个寄存器参数也统一放到栈上方便批量处理,直接在建立栈帧后依次压入即可:

push %rdi  ; 第1个参数
push %rsi  ; 第2个参数
push %rdx  ; 第3个参数
push %rcx  ; 第4个参数
push %r8   ; 第5个参数
push %r9   ; 第6个参数

这样栈顶开始就是第6到第1个参数,而栈上的第7个参数依然在%rbp + 16的位置,互不干扰。

2. 如何确定需要回溯多远才能获取所有参数?

首先得明确:CPU本身不知道你传了多少个参数,必须通过函数约定来确定总数——这就是为什么printf需要格式化字符串,或者有些可变参数函数会把参数个数作为第一个传入参数(比如C里的void func(int arg_count, ...))。你之前想通过%rbp和%rsp的差值来判断是行不通的,因为栈里还会包含函数内部的局部变量,这个差值根本无法直接对应参数数量。

另外你提到的「返回地址和基指针被压在参数之间」是个误解,实际的栈布局顺序是这样的:
调用者在执行call之前,会把第7及以后的参数依次压栈;call指令执行时,会把返回地址压入栈顶;进入你的函数后,push %rbp又会把旧基指针压到栈顶。所以参数的位置是在返回地址的下方(更低的内存地址),基指针和返回地址都在参数的上方,根本不会夹在参数中间。

知道参数总数后,获取所有参数的步骤就很明确了:

  • 先处理前6个寄存器参数:要么直接用寄存器操作,要么压栈统一处理
  • 对于剩下的n-6个参数,从%rbp + 16开始,每次偏移8字节去访问下一个参数,直到取完所有参数为止

举个简单例子,如果总共有10个参数,那栈上的4个参数分别在%rbp+16(第7个)、%rbp+24(第8个)、%rbp+32(第9个)、%rbp+40(第10个)的位置。

内容的提问来源于stack exchange,提问作者grumps

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:20:02