Reputation: 111
i'm actually new to C and i tried this while debugging a c program using gdb.
Here is my Program
int main(){
int a = 4;
int b = 8;
}
Then i used Gdb to debug the program, step through 2 lines of assembly code which set the value for a
and b
mov DWORD PTR [rbp-0x4],0x4
mov DWORD PTR [rbp-0x8],0x8
The value of rbp is 0x7fffffffde70
Since the int
data type has 4 bytes and the stack grows from high value address to low value address,the address of a
must be 0x7fffffffde70 - 0x4
= 0x7fffffffde6c
and the address of b
must be 0x7fffffffde70 - 8
= 0x7fffffffde68
which returned 4
and 8
as expected.
But when i print the value at the address 0x7fffffffde6b 0x7fffffffde6a 0x7fffffffde69
it print 0x00000400 0x00040000 0x04000000
which seems so weird since a
has value 4
which could be stored by using the first byte only and those 3 addresses should contain 0x0
isn't it?
Upvotes: 0
Views: 673
Reputation: 224335
int
is 32 bits in your C implementation. Using hexadecimal to show all 32 bits used to represent the values, 4 is represented with 0000000416 and 8 is represented with 0000000816.
When an integer value is stored in memory, your C implementation stores it with the lowwest-value byte first, then the next lowest-value byte, then the next lowest, and so on. So, if 0000000416 is stored starting at address 7fffffffde6c16 and 0000000816 is stored at 7fffffffde6816, then the memory contents are:
Address | Contents |
---|---|
7fffffffde6816 | 0816 |
7fffffffde6916 | 0016 |
7fffffffde6a16 | 0016 |
7fffffffde6b16 | 0016 |
7fffffffde6c16 | 0416 |
7fffffffde6d16 | 0016 |
7fffffffde6e16 | 0016 |
7fffffffde6f16 | 0016 |
When you ask the debugger to print a 32-bit integer from the address 7fffffffde6b16, it loads four bytes starting from that address, getting 0016, 0416, 0016, 0016. Since the lowest-value byte is stored first, these form the integer 0000040016.
Similarly, printing a 32-bit integer from 7fffffffde6a16 yields the bytes 0016, 0016, 0416, 0016, making 0004000016, and printing a 32-bit integer from 7fffffffde6916 yields the bytes 0016, 0016, 0016, 0416, making 0400000016.
Note that, while the stack grows “downward” (toward lower addresses) in your system, this applies to how function call stack frames are ordered and how individual “push” and “pop” processor instructions behave. It does not control how a compiler arranges variables within a stack frame. The order in which a compiler places variables within a frame is not required to match the order in which they are declared. Especially when you turn on optimization and the variables have different types, the compiler may put the variables in different orders.
Also, while the debugger may be able to load a 32-bit integer from any address, your system may have alignment rules that require 32-bit integers to be located at multiples of four bytes in ordinary situations. Do not expect a regular program, rather than the debugger, to be able to load a 32-bit integer from unaligned addresses without generating a program fault that interrupts execution.
Upvotes: 1