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.