0

我有两个问题。

第一个问题。为什么以下代码实际上可以在 mac 上运行(使用 gcc 编译)?

int main()
{
    int *p;
    *p = 1;
    return 0;
}

反汇编时,行 '*p = 1;' 变成

mov rax, [rbp - 16]
mov qword [rax], 1

第二个问题。什么位于 [rbp - 16]?

在问这个问题时,我将操作数 [rbp - 16] 解释为 [rbp + 16],这显然没有意义。我累了……

你回答我的问题。

4

3 回答 3

3

您的代码具有未定义的行为。这意味着它可以做任何事情。它不必崩溃。

当您的程序启动时,有一些代码在之前执行main()并且使用相同的堆栈。您的盒子上可能发生的情况是,包含的堆栈区域p以前已被另一个函数使用,该函数在那里保留了一个有效的指针。你main()不小心偶然发现了那个指针,取消了它的引用,并且正在破坏其他人的记忆。

gcc我尝试使用并在 OSX 上运行它来编译您的代码,但它确实崩溃了。

于 2013-02-12T10:27:47.870 回答
1

我记得,C 中的变量是由以前的用户留在堆栈上的某个值初始化的——如果你没有明确指定它们的值的话。所以,这个值是绝对随机的,你的代码只是改变了随机内存区域的值。如果你得到空指针,你的程序将失败。

于 2013-02-12T10:27:37.700 回答
0

Others have sufficiently covered the undefined-ness of this behavior. Your specific question appeared to be about understanding the disassembly. Here's a somewhat verbose, but hopefully helpful walkthrough:

First instruction: mov rax, [rbp - 16]

RBP is the "base pointer register." This holds the address in memory of the current stack frame. As a commenter pointed out rbp - 16 is the location, in the current stack frame, of p. It will be an 8 byte pointer. If you declared another local variable int *q; immediately after p it's address would likely be at rbp - 24. RAX is, in this case, a general purpose register. This copies the 8 byte pointer from where it's situated on the stack at rbp - 16 into RAX. As others have pointed out, since you didn't initialize p, the value at rbp - 16 is whatever was left in memory by the last thing to use that memory, or something totally random. The square brackets brackets indicate that the operand rbp - 16 is a pointer, and that the contents of the memory at the address rbp - 16 should be copied, and not the literal result of the expression rbp - 16. You can think of the expression rbp - 16 as having the type int**.

Second instruction: mov qword [rax], 1

QWORD is short for "quad word". Historically, a byte is one byte, a "word" is two bytes, a "long" or "dword" (for 'double word') is four bytes and, naturally, a "quad word" is 8 bytes. This instruction copies a literal 1 (extended to its eight byte form) to the location pointed to by RAX. The square brackets brackets indicate that the operand RAX is a pointer, and that the literal is to be copied into the location pointed to by the operand. If the instruction were mov qword rax, 1 that would copy the literal 1 (in its eight byte form) into RAX.

As others have said, since that pointer is garbage (what ever happened to be in memory) chances are good (but not guaranteed) that this will crash.

于 2013-02-12T12:59:51.210 回答