gpt4 book ai didi

c++ - Lambdas 作为环境的闭包。 RIP寄存器的关键作用

转载 作者:行者123 更新时间:2023-11-30 02:28:21 24 4
gpt4 key购买 nike

我查看了以下代码的汇编程序输出,我惊呆了:

int x=0, y=0; // global
// r1, r2 are ints, local.
std::thread t([&x, &y, &r1, &r2](){
x = 1;
r1 = y;
});

!std::thread t([&x, &y, &r1, &r2](){
<lambda()>::operator()(void) const+0: push %rbp
<lambda()>::operator()(void) const+1: mov %rsp,%rbp
<lambda()>::operator()(void) const+4: mov %rdi,-0x8(%rbp)
<lambda()>::operator()(void) const+18: mov -0x8(%rbp),%rax
<lambda()>::operator()(void) const+22: mov (%rax),%rax
! x = 1;
<lambda()>::operator()(void) const()
<lambda()>::operator()(void) const+8: movl $0x1,0x205362(%rip) # 0x6062ac <x>
! r1 = y;
<lambda()>::operator()(void) const+25: mov 0x205359(%rip),%edx # 0x6062b0 <y>
<lambda()>::operator()(void) const+31: mov %edx,(%rax)
!
!});
<lambda()>::operator()(void) const+33: nop
<lambda()>::operator()(void) const+34: pop %rbp
<lambda()>::operator()(void) const+35: retq

为什么确定x,y地址与RIP有关。 RIP 是一个指令指针,所以它看起来很疯狂。特别是,我从未见过这样的事情。 (也许我还没有看到很多东西 :))。

我想到的唯一解释是,lambda 是一个闭包,从特定位置获取环境变量与 RIP 有一些共同之处。

最佳答案

代码在运行时不会移动,一旦代码部分被加载,例程就不会被复制或移动。
静态数据在其部分加载后也占用相同的地址。
因此,一条指令和一个静态变量之间的距离在编译时是已知的,并且它在模块基址的重定位下是不变的(因为指令和数据都被翻译了相同的量)。

所以RIP-relative addressing不仅不疯狂,而且一直是一个很早就缺失的特性。
虽然在 32 位代码中,像 mov eax, [var] 这样的指令是无害的,但在没有 RIP 相对寻址的 64 位代码中,它需要 9 个字节,1 个用于操作码,8 个用于立即数。使用 RIP 相对寻址时,立即数仍然是 32 位。


C++ lamdbas 是函数对象的语法糖,其中捕获的变量成为实例变量。
通过引用捕获的变量作为指针/引用处理。
全局变量在捕获时不需要任何特殊处理,因为它们已经可以访问。

您正确地注意到 xy 分别作为 0x205362(%rip)0x205359(%rip).
因为它们是全局的,所以它们的地址在运行时是固定的,并且使用相对于 RIP 的寻址来访问它们。

但是你忘了检查本地捕获变量r1是如何被访问的。
它存储在 (%rax) 中,rax 之前加载为(优化)movq (%rdi), %rax
%rdi是方法operator()的第一个参数,所以是this,刚才说的指令加载第一个实例变量到rax 然后使用该值访问 r1
简单地说,它是指向 r1 的指针(或更好的引用),因为 r1 存在于堆栈中,其地址在运行时是动态的(它取决于堆栈)。

因此 lambda 同时使用间接寻址和 RIP 相对寻址,从而与 RIP 相对寻址在某种程度上是特殊的假设相矛盾。


请注意,捕获机制不会延长捕获变量的生命周期(就像在 ECMAScript 中一样),因此在 std::thread 的 lambda 中通过引用捕获局部变量几乎总是不好的想法。

关于c++ - Lambdas 作为环境的闭包。 RIP寄存器的关键作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40841057/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com