Investigating The Stack With the Debugger

This section assumes I already covered some basics of GDB earlier in the book, which I plan to do.

Once you have some concept of registers and the stack, it’s time to play. Take our original example and save this as stack.c:

int main()
    int i = 0x11223344;
    char s[4];
    s[0] = 'f';
    s[1] = 'o';
    s[2] = 'o';
    s[3] = '\0';
    return 0;

Compile this with GCC:

gcc -m32 -S stack.c

The -m32 option tells it to generate 32-bit code (you can investigate 64 bit on your own) and the -S option tells GCC to compile to assembly rather than machine code. This generates stack.s which you can look at in a text editor.

Now assemble the code:

gcc -m32 -gstabs -o stack stack.s

Again we need to specify 32 bit, and the -gstabs option tells GCC to include debugging info for GDB. This generates stack, which you can now run in GDB:

gdb stack

Try list main (or simply l main) first, and you’ll see the beginning of main():

(gdb) l main
1       .text
2   .globl _main
3   _main:
4       pushl   %ebp
5       movl    %esp, %ebp
6       subl    $24, %esp

Looks familiar, right? Set a breakpoint at main (break main or b main) then run the program (run or r). Now you can single-step (step or s) and follow along with the program putting stuff on the stack. Once you’ve stepped past the subl ..., %esp instruction, investigate the stack and base pointers:

(gdb) p $esp
$1 = (void *) 0xbffff7a0
(gdb) p $ebp
$2 = (void *) 0xbffff7b8

Note that registers are displayed with a percent sign in front (like %esp) but GDB makes you put a dollar sign in front (like $esp).

On my computer, GCC makes a stack frame of 24 bytes (subl $24, %esp), and I can verify this with GDB:

(gdb) p $ebp - $esp
$3 = 24

Now let’s investigate some items on the stack. Keep stepping until you see the MOV instruction:

7       movl    $287454020, -12(%ebp)

Step one more time to execute the instruction. Since GCC decided to move 0x11223344 to the base pointer minus 12, I can look at that using the x command:

(gdb) x/w $ebp - 12
0xbffff7ac: 0x11223344

Remember, x is used to eXamine the contents of memory. Where p $ebp just prints the value of EBP, x $ebp prints the memory that EBP points to. In this case, I specify x/w to explicitly tell GDB that I want to examine a “word” of memory. I say “word” in quotes because “word” means different things depending on who you ask; in the Intel 8086 universe it means 2 bytes. In GDB universe it means 4 bytes.

Go ahead and step through the program and investigate the other stuff on the stack. We’ll get to a beefier example in just a moment. Before executing the LEAVE instruction, however, examine that integer one more time using ‘x/4b’ just for grins:

(gdb) x/4b $ebp - 12
0xbffff7ac: 0x44    0x33    0x22    0x11

Notice the four bytes appear to be backwards? Mull over that one for a while. We’ll revisit it later.