CPU如何知道任意变量的地址?

How does a CPU know the address of any variable?

本文关键字:地址 变量 任意 何知道 CPU      更新时间:2023-10-16

说你喜欢:

void something()
{
   int* number = new int(16);
   int* sixteen = number;
}

CPU如何知道我要分配给16的地址?

谢谢

示例代码中没有魔法。以下面的代码片段为例:

int x = 5;
int y = x;

你的指针代码是完全相同的-计算机不需要知道任何神奇的信息,它只是复制number中的任何内容到sixteen

关于你下面的评论:

但是它如何知道x或y在内存中的位置。如果我要把x复制到y中,它怎么知道这两个在哪里呢

实际上,在现在的大多数机器上,可能都不在内存中,它们将在寄存器中。但是如果它们在内存中,那么是的,编译器将在必要时发出跟踪所有这些地址的代码。在这种情况下,它们位于堆栈上,因此机器码将访问堆栈指针寄存器,并使用一些编译器决定的偏移量对其解引用,这些偏移量指向每个特定变量的存储。

这里有一个例子。这个简单的函数:

int f(void)
{
  int x = 5;
  int y = x;
  return y;
}

当使用clang编译且未进行优化时,在我的机器上给出以下输出:

_f:
 pushq  %rbp               ; save caller's base pointer
 movq   %rsp,%rbp          ; copy stack pointer into base pointer
 movl   $5,0xfc(%rbp)      ; store constant 5 to stack at rbp-4
 movl   0xfc(%rbp),%eax    ; copy value at rbp-4 to register eax
 movl   %eax,0xf8(%rbp)    ; copy value from eax to stack at rbp-8
 movl   0xf8(%rbp),%eax    ; copy value off stack to return value register eax
 popq   %rbp               ; restore caller's base pointer
 ret                       ; return from function

我添加了一些注释来解释生成的每一行代码的作用。重要的是要看到堆栈上有两个变量-一个在0xf8(%rbp)(或rbp-8更清楚)和一个在0xfc(%rbp)(或rbp-4)。基本算法就像原始代码所显示的那样-常数5rbp-4处被保存到x中,然后该值在rbp-8处被复制到y中。

你可能会问:"但是堆栈从哪里来呢?"不过,这个问题的答案取决于操作系统和编译器。这些都是在调用程序的main函数之前设置的,与此同时,您的操作系统需要进行其他运行时设置。

CPU知道,因为你的程序告诉它。这里的魔力在于编译器。首先,我在Visual Studio 2010中构建了这个程序。

这是它生成的反汇编(在DEBUG模式下):

void something()
{
003A13C0  push        ebp  
003A13C1  mov         ebp,esp  
003A13C3  sub         esp,0E8h  
003A13C9  push        ebx  
003A13CA  push        esi  
003A13CB  push        edi  
003A13CC  lea         edi,[ebp-0E8h]  
003A13D2  mov         ecx,3Ah  
003A13D7  mov         eax,0CCCCCCCCh  
003A13DC  rep stos    dword ptr es:[edi]  
   int* number = new int(16);
003A13DE  push        4  
003A13E0  call        operator new (3A1186h)  

在调用operator new之后,EAX = 00097C58,这是内存管理器决定给我这个程序运行的地址。这是当您取消引用号码时将使用的地址。

003A13E5  add         esp,4  
003A13E8  mov         dword ptr [ebp-0E0h],eax  
003A13EE  cmp         dword ptr [ebp-0E0h],0  
003A13F5  je          something+51h (3A1411h)  
003A13F7  mov         eax,dword ptr [ebp-0E0h]  
003A13FD  mov         dword ptr [eax],10h  
003A1403  mov         ecx,dword ptr [ebp-0E0h]  
003A1409  mov         dword ptr [ebp-0E8h],ecx  
003A140F  jmp         something+5Bh (3A141Bh)  
003A1411  mov         dword ptr [ebp-0E8h],0  
003A141B  mov         edx,dword ptr [ebp-0E8h]  
003A1421  mov         dword ptr [number],edx  
   int* sixteen = number;
003A1424  mov         eax,dword ptr [number]  
003A1427  mov         dword ptr [sixteen],eax  

这里你只是要确保16和number是相同的值。所以现在它们指向同一个地址。

}

您可以通过在Locals调试窗口中检查它们来验证:

+       number  0x00097c58  int *
+       sixteen 0x00097c58  int *

您可以做这个实验并逐步进行拆卸。