RBP 如何指向任意数量的 local_variable 或参数?

问题描述

我是装配新手(NASM)。我知道 RBP 指向函数中的任何参数和局部变量。它是通过简单的偏移量实现的。如果我们想获得第一个变量我们rbp-4,如果我们想获得第一个参数我们添加到 rbp 4。但是如果任何函数可以有任意数量的局部变量或参数,我们怎么能做到这一点?如果我们希望在一个函数中可以有 100 个变量,我们如何通过简单的常量偏移量指向任何变量?

谢谢。对不起我的英语不好。我不是母语人士。

解决方法

在像 C 这样的语言中你不能有可变数量的变量,所以编译器总是知道它把它们放在哪里。因此它知道每个变量的正确常量偏移量。

如果你在谈论像 printf(char *,...) 这样的可变参数函数,那么你有调用约定中关于它们如何布局的规则,你通常会增加一个指针。要按 arg-number 索引,您需要知道所有先前 args 的宽度。它们至少为 8,但根据调用约定可以更宽,而不是在 x86-64 System V 中使用隐藏指针。 printf 具有 long double 的转换等(比 8 个字节更宽),所以它必须支持跟踪哪个 arg 在哪里,以防转换通过数字引用 arg


如果您正在谈论使用堆栈作为堆栈数据结构,推/弹出可能在循环内部,那么您需要保留一个指针以了解您的堆栈数据结构何时为“空”,并且进一步的弹出会吃进入其他本地变量。

将某些局部变量设为可变长度数组会使事情变得更加棘手,例如 C int foo[n],其中 n 是另一个变量。许多 C 编译器通过发明一个指向每个 VLA 的指针来处理它。指针具有已知的固定宽度,因此编译器知道在哪里可以找到它们,并且它们可以被初始化,因为空间是为 VLA 保留的,例如 sub rsp,rax / mov [rbp-16],rsp

,

函数参数和局部变量的寻址取决于所选的 calling convention。您获取我们添加到 rbp 4 的第一个参数肯定是错误的,因为在 64 位模式下(暗示使用 RBPRSP 进行寻址)可以将项目推入堆栈仅 64 位粒度。也许您有 32 位 StandardCall 约定,其中一个函数的典型序言如下所示:

Function: PUSH EBP 
          MOV EBP,ESP 
          SUB ESP,LocalsSize

可以在函数内部使用寄存器 EBP 来寻址无限数量的参数和局部变量(在这个例子中我使用了三个参数和四个 DWORD 局部变量):

Invokation      Stack   Address

PUSH Param3     Param3  EBP+4*4
PUSH Param2     Param2  EBP+3*4
PUSH Param1     Param1  EBP+2*4
CALL Function   return
                 EBP  
                Local1  EBP-1*4
                Local2  EBP-2*4
                Local3  EBP-3*4
                Local4  EBP-4*4

另请参阅此 32bit64bit StdCall 约定示例。