...
/Memory Pointers Example: Memory Layout
Memory Pointers Example: Memory Layout
Learn about memory layout and pointers with the help of an example.
Memory pointers in the C/C++ language
We have the following data declaration and definition in the C/C++ language:
int a, b;int *pa, *pb = &b;
Memory pointers in the assembly language
The example code we’ll look at in this lesson corresponds to the following pseudocode and assembly language:
Source code
The source code of memory pointers is as follows:
.dataa: .int 0b: .int 0pa: .quad 0pb: .quad b.text.global _startmain:_start:adr x0, aadr x1, pastr x0, [x1]adr x0, paldr x0, [x0]mov w2, #1str w2, [x0]adr x1, pbldr x1, [x1]str w2, [x1]ldr w2, [x0]ldr w3, [x1]add w3, w3, w2str w3, [x1]mov x0, #0mov w8, #93svc #0
Memory pointers in the GDB disassembly
The code example of memory pointers is described in detail below.
Compile and execute GDB commands
We compile and link the course code, and load the executable into GDB. We get the following output:
as MemoryPointers.asm -o MemoryPointers.old MemoryPointers.o -o MemoryPointersgdb ./MemoryPointers
Note: You can practice all the commands in the coding playground provided at the end of the lesson.
Now, we are in GDB environment:
We then put a breakpoint on the main
function and run
the program until GDB reaches at this point:
break main
A breakpoint is shown below:
Breakpoint 1 at 0x4000b0(gdb)
Now, run
the program:
set disable-randomization offrun
The output after execution is given below:
Starting program: /Chapters/Chapter7/MemoryPointersBreakpoint 1, 0x00000000004000b0 in _start ()(gdb)
Now, we disassemble the main
function:
disass main
The output is given below:
Dump of assembler code for function _start:=> 0x00000000004000b0 <+0>: adr x0, 0x4100f00x00000000004000b4 <+4>: adr x1, 0x4100f80x00000000004000b8 <+8>: str x0, [x1]0x00000000004000bc <+12>: adr x0, 0x4100f80x00000000004000c0 <+16>: ldr x0, [x0]0x00000000004000c4 <+20>: mov w2, #0x1 // #10x00000000004000c8 <+24>: str w2, [x0]0x00000000004000cc <+28>: adr x1, 0x4101000x00000000004000d0 <+32>: ldr x1, [x1]0x00000000004000d4 <+36>: str w2, [x1]0x00000000004000d8 <+40>: ldr w2, [x0]0x00000000004000dc <+44>: ldr w3, [x1]0x00000000004000e0 <+48>: add w3, w3, w20x00000000004000e4 <+52>: str w3, [x1]0x00000000004000e8 <+56>: mov x0, #0x3 // #30x00000000004000ec <+60>: lsl x2, x1, x0End of assembler dump.(gdb)
We then clear x0
– x3
registers to set up a memory layout that is easy to follow:
set $x0 = 0set $x1 = 0set $x2 = 0set $x3 = 0info registers x0 x1 x2 x3
We get the following output:
x0 0x0 0x1 0x0 0x2 0x0 0x3 0x0 0(gdb)
We also instruct GDB to automatically display the current instruction to be executed, the values of registers x0
– x3
, and the contents of variables a
, b
, pa
, pb
:
(gdb) display/i $pc1: x/i $pc=> 0x4000b0 <_start>: adr x0, 0x4100f0(gdb) display/x $x02: /x $x0 = 0x0(gdb) display/x $x13: /x $x1 = 0x0(gdb) display/x $x24: /x $x2 = 0x0(gdb) display/x $x35: /x $x3 = 0x0(gdb) display/x (int)a6: /x (int)a = 0x0(gdb) display/x (int)b7: /x (int)b = 0x0(gdb) display/x (long)pa8: /x (long)pa = 0x0(gdb) display/x (long)pb9: /x (long)pb = 0x4100f4(gdb)
We see that the pb
variable contains the address 0x4100f4
. We then check the addresses of (variables) memory locations a
, b
, pa
, pb
:
(gdb) print &a$1 = (<data variable, no debug info> *) 0x4100f0(gdb) print &b$2 = (<data variable, no debug info> *) 0x4100f4(gdb) print &pa$3 = (<data variable, no debug info> *) 0x4100f8(gdb) print &pb$4 = (<data variable, no debug info> *) 0x410100(gdb)
We also check the value stored at the address 0x4100f4
(value of pb
that is the address of ...