说我在C语言中有一个简单的系统:
#include <cstddef>
typedef struct Point {
Point *a;
Point *b;
int x;
int y;
} Point;
int main() {
Point p1 = {NULL, NULL, 3, 5};
return 0;
}
Godbolt编译为:
main:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-32], 0
mov QWORD PTR [rbp-24], 0
mov DWORD PTR [rbp-16], 3
mov DWORD PTR [rbp-12], 5
mov eax, 0
pop rbp
ret
更进一步,我们有:
int main() {
Point v = {NULL, NULL, 3, 5};
Point m = {NULL, NULL, 7, 9};
Point s = {&v, &s, 11, 12};
return 0;
}
编译为:
main:
push rbp ; save the base pointer to the stack.
mov rbp, rsp ; put the previous stack pointer into the base pointer.
mov QWORD PTR [rbp-32], 0
mov QWORD PTR [rbp-24], 0
mov DWORD PTR [rbp-16], 3
mov DWORD PTR [rbp-12], 5
mov QWORD PTR [rbp-64], 0
mov QWORD PTR [rbp-56], 0
mov DWORD PTR [rbp-48], 7
mov DWORD PTR [rbp-44], 9
mov QWORD PTR [rbp-96], 0
mov QWORD PTR [rbp-88], 0
mov QWORD PTR [rbp-80], 0
mov DWORD PTR [rbp-80], 11
mov DWORD PTR [rbp-76], 12
lea rax, [rbp-32]
mov QWORD PTR [rbp-96], rax
lea rax, [rbp-96]
mov QWORD PTR [rbp-88], rax
mov eax, 0
pop rbp
ret
我还不能确切地告诉发生了什么,但是this helps(有点)。能否解释一下上一个示例中发生了什么?我不太了解基本指针是什么,我知道堆栈指针是什么。我不确定QWORD PTR [...]
的作用,但是它是四字大小和指针/地址。但是为什么要从QWORD PTR [...]
中选择那些特定的偏移量呢?我不明白为什么选择了它。
然后第二部分是rbp
。似乎正在处理我lea rax, [rbp-32]
所做的部分。
所以我的问题是:
lea rax, [rbp-32]
的偏移量?我很纳闷,因为我想把头放在如何在装配中创建树的周围。在函数式编程或JavaScript中,您有{&v, &s}
。首先传递deepest函数的值,然后最后传递参数的值rbp
的值。但是我很难想象它在装配中的外观。
[更具体地说,我试图在程序集中创建像简单的键/值存储区一样,以更深入地了解如何在此较低级别创建“对象”。使用JavaScript很容易:
a(b(c(), d(), e(f(g(), h()), ...)))
但是这是因为a
在内存中已经存在somewhere。我的问题是,是否应该在键值存储中预先创建此direct?还是始终在内存中的任意空闲位置创建它(例如db[key] = value
的偏移量),然后再将它们移到正确的位置(或将它们指向正确的位置)?我一直认为我应该直接在树枝上创建树叶节点,就像我(在视觉上)在树枝上粘贴树叶一样。但是叶子已经存在!它在分支上之前在哪里存在?它可以存在于分支before上吗?我感到困惑。
所以,从叶子开始。
value
将其粘贴在分支上。
rbp
首先在哪里创建叶子?这就是我试图通过装配示例看到的。
大多数编译器将堆栈用于局部变量。
堆栈上的空间通常由两个指针管理:堆栈指针;和一个“基本”指针,指向堆栈上“已分配”内存的基础。
同样要注意的是,几乎所有系统上的堆栈都增长了[[downward,这就是为什么基指针(生成的代码中的寄存器🍁
)有负偏移的原因。
基本指针---> + --------------------- +|变量空间|| ... || ... || ... |堆栈指针-> + --------------------- +