I cannot speak for your machine, but on my machine the C code you provided results in this machine code fragment (found by compiling the program and invoking objdump -D -j .text
on it):
117b: c6 45 f7 64 movb $0x64,-0x9(%rbp)
117f: 48 8d 45 f7 lea -0x9(%rbp),%rax
1183: 48 89 c7 mov %rax,%rdi
1186: e8 be ff ff ff call 1149 <print>
(Keep in mind that passing different options to your compiler or using a different compiler altogether might result in different machine code)
The code stores a byte (movb
) with hex value 0x64 on the stack. 0x64 is the ascii value for the "d" character. Afterwards, it loads the address of that byte on the stack (lea
) to the rax register and copies it to rdi, which is the register used to pass the first argument to functions on Linux, which i use. This way, during the print call in the next instruction the first argument is a pointer to your character on the stack.
Using GDB one can inspect the contents of the stack memory prior to and after executing the particular movb
.
Before:
00:0000│ rsp 0x7fffffffe0b0 ◂— 0x0
01:0008│ 0x7fffffffe0b8 ◂— 0x4ef8437da34e1300
02:0010│ rbp 0x7fffffffe0c0 ◂— 0x1
After:
00:0000│ rsp 0x7fffffffe0b0 ◂— 0x6400000000000000
01:0008│ 0x7fffffffe0b8 ◂— 0x4ef8437da34e1300
02:0010│ rbp 0x7fffffffe0c0 ◂— 0x1
(i have a GDB extension called pwndbg installed, so your output might look differently)
Essentially, it seems that the stack memory that the "d" is written to is all zero before the write. Thanks to this, the very next byte after 0x64 is a null character, which creates an "impromptu" printable string.
As others have said this is not a behavior you can rely on, instead it is merely a coincidence. You should not write code this way when writing programs that are actually supposed to work :) but this is already emphasized enough in other answers. Additionally, because of this being undefined behavior it is actually possible that on your machine the program works for entirely different reasons. To be sure of the answer i recommend you debug your code and inspect what the memory contents look like in your case. To do that you should:
- Compile your program
- Disassemble it, for example using
objdump -D -j .text <your program name>
- Find the assembly responsible for passing "d" to your print function. Hint: it will be somewhere in the main function
- If needed, inspect what exactly is happening with the memory/registers using GDB