是否有可能在一个函数中获取由 return 值初始化的变量的内存地址?

Is it possible within a function to get the memory address of the variable initialized by the return value?

我一直在研究 C 中的内联汇编以及调用堆栈的工作原理,但我一直无法弄清楚是否有可能检索请求 return 函数的值,来自函数内部。

int hypothetical_func(){

    /*...
    .. some assembly to get the address of 'int a' from the call stack?
    ...*/

    return 5;
}

int main(){
    int a = hypothetical_func();
}

这可能吗?

没有。 int 在寄存器 中被 return 编辑,被调用者不参与调用者在它 return 之后对该寄存器所做的操作。它可能永远不会存储在内存中。

如果 return 类型不是 int,而是大到足以让调用约定 return 按值编辑它,那么 hypothetical_func 将具有一个输出地址。 (或者一个假设的(可怕的)调用约定可能 return 甚至 int 通过隐藏指针而不是寄存器。假设机器是像所有真实 CPU 一样的寄存器机器。)

但这可能只是一个临时的 return 值,而不是赋值的实际 LHS。(或初始化,这与同一件事足够接近在 C 中,如果不是 C++)。特别是如果任务是全局的或其他的。请参阅 了解 *out = foo(); 的情况,其中 T *out 是函数参数。证明 if/when 可以安全地将函数 arg 作为 foo().

的 return 值对象传递是非常重要的

有些编译器甚至不尝试优化,只是在堆栈上为 return 值临时创建 space,然后从那里复制到最终对象。

正如@prl 指出的那样,return 值甚至可能 不是 变量的初始值设定项。例如printf("%d\n", foo()); 只是将 return 值传递给函数 arg。 foo();丢弃return值,不在任何地方分配它。(但如果调用约定指定函数returns通过隐藏指针,调用者 必须 传递一个指向足够 scratch space 的指针。被调用者仍将写入它的 return 值,并且不需要从错误的指针发生段错误或覆盖别的东西。那是与 C 抽象机的操作分开的 asm / 调用约定细节。或者我猜你可以说 return-value 对象仍然存在,它只是没有分配到任何地方。)


加上 内联 程序集,您甚至无法访问 。除非你算上编写一个 __attribute__((naked)) 函数,你仍然在 asm 语句中编写整个函数,并且编译器除了函数名称的名称重整之外不处理任何东西。没有序言或结语,也没有使用 C 变量为 args 和你 return 抽象出调用约定。 (/抱怨 C 编译器无法创建 return 多个寄存器中的多个独立值的函数,就像在手写 asm 中那样。)

但是即使使用手写的 asm,也没有办法在 x86 和 ARM 等普通 ISA 上对普通调用约定执行此操作。 int 的 return 值对象只是一个寄存器。

这在任何实际意义上都是不可能的。 return 值可能没有赋值给变量,如果赋值,则变量可能没有内存地址。即使这两种情况都不是,并且 return 值已分配给内存中的变量,该变量的地址对函数不可用。

解决这个问题的一种不切实际的方法(例如,如果需要调试)是从堆栈中获取 return 地址并反汇编指令以寻找写入 return 值寄存器的指令到记忆中。这样的指令(如果存在)通常会在 return 点之后的几条指令内。

如果 int a = hypothetical_func(); 在另一个函数中,它应该在该函数的栈帧上,因此使用 backtrace() 您可以找到该函数的栈帧并找到该变量。

更多特别信息: https://www.linuxjournal.com/article/6391