是否可以在函数中获取由返回值初始化的变量的内存地址? [英] Is it possible within a function to get the memory address of the variable initialized by the return value?

查看:63
本文介绍了是否可以在函数中获取由返回值初始化的变量的内存地址?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究 C 中的内联汇编以及调用堆栈的工作原理,但我一直无法弄清楚是否可以检索请求函数返回值的变量的地址,从函数内.

I have been doing some research into inline assembly in C and how the call stack works but I have been unable to figure out if it's at all possible to retrieve the address of a variable that is requesting the return value of a function, from WITHIN the function.

int hypothetical_func(){

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

    return 5;
}

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

这可能吗?

推荐答案

NO.int 在寄存器中返回,被调用者不参与调用者在返回后对该寄存器所做的事情.它可能永远不会存储在内存中.

NO. int is returned in a register, and the callee has no involvement in what the caller does with that register after it returns. It might never be stored in memory.

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

If the return-type wasn't int, but instead something large enough that the calling convention returned it by value, then hypothetical_func would have an address for an output. (Or a hypothetical (terrible) calling convention might return even int via hidden pointer instead of a register. Assuming the machine is a register machine like all real CPUs.)

但这可能只是一个临时的返回值,而不是赋值的实际 LHS.(或者初始化,如果不是 C++,它与 C 中的相同内容足够接近).特别是如果分配是全局或其他东西.请参阅什么阻止使用函数参数作为隐藏指针? 对于 *out = foo(); 的情况,其中 T *out 是一个函数参数.证明是否/何时可以安全地将该函数 arg 作为 foo() 的返回值对象传递是非常重要的.

But that might just be a return-value temporary, not the actual LHS of an assignment. (Or initialization, which is close enough to the same thing in C, if not C++). Especially if the assignment is to a global or something. See What prevents the usage of a function argument as hidden pointer? for the case of *out = foo(); where T *out is a function arg. It's highly non-trivial to prove if/when it's safe to pass that function arg along as the return-value object for foo().

有些编译器甚至不尝试优化,只是在堆栈上为返回值临时腾出空间,然后从那里复制到最终对象中.

And some compilers don't even try to optimize, and just make space on the stack for the return-value temporary and copy from there into the final object.

而且正如@prl 指出的那样,返回值甚至可能不是 变量的初始值设定项.例如printf("%d\n", foo()); 只是将返回值传递给函数 arg.或者 foo(); 丢弃返回值,而不是在任何地方分配它.(但如果调用约定指定函数通过隐藏指针返回,则调用方必须 传递一个指向足够暂存空间的指针.被调用者仍将写入其返回值,并且不需要从坏指针中进行段错误或覆盖其他内容.这是一个与操作分离的 asm/调用约定细节C抽象机.或者我猜你可以说返回值对象仍然存在,只是没有在任何地方分配.)

And as @prl points out, the return-value might not even be the initializer for a variable. e.g. printf("%d\n", foo()); just passes on the return value to a function arg. Or foo(); discards the return value, not assigning it anywhere. (But if the calling convention specifies that the function returns by hidden pointer, the caller must pass a pointer to enough scratch space. The callee is still going to write its return value and needs to not segfault from a bad pointer or overwrite something else. That's an asm / calling-convention detail separate from the operation of the C abstract machine. Or I guess you could say the return-value object still exists, it's just not assigned anywhere.)

加上内联程序集,您甚至无法访问.除非你计算编写一个 __attribute__((naked)) 函数,你仍然在 asm 语句中编写整个函数,并且编译器除了函数名称的名称修改之外不处理任何事情.没有序言或结尾,也没有抽象出带有 C 变量的调用约定,用于 args 和您返回.(/抱怨 C 编译器无法创建在多个寄存器中返回多个单独值的函数,就像您在手写 asm 中所做的那样.)

Plus with inline assembly, you don't even have access to that. Unless you count writing a __attribute__((naked)) function where you still write the whole function inside an asm statement, and the compiler doesn't handle anything except the name-mangling of the function name. No prologue or epilogue, or abstracting away the calling convention with C variables for args and one that you return. (/grumble that C compilers can't create functions that return multiple separate values in multiple registers like you can in hand-written asm.)

但即使使用手写的 asm,对于 x86 和 ARM 等普通 ISA 上的普通调用约定,也无法做到这一点.int 的返回值对象只是一个寄存器.

But even with hand-written asm, there's no way to do this for normal calling conventions on normal ISAs like x86 and ARM. The return-value object for int is just a register.

这篇关于是否可以在函数中获取由返回值初始化的变量的内存地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆