Doomztrom
Doomztrom

Reputation: 13

intel x86 - why does -4(%ebp) refers to nothing?

In many examples when I compile a c-function (such as the sorting algorithm shell sort) the stackaddress (i gues it is called?) ebp-4 / -4(%ebp) / [ebp]-4 or whatever, which, as I understand, is usually used for the first local variable, is not used in my case.

So I was wondering if someone knows what it is used for, as it is not used for any local variables, or anything else for that matter.

Furthermore, 20 is subtracted from the stack pointer to allocate stack space for the locale variables - but then a value is still saved to -24(%ebp) - how is that possible when there is only made room until -20??

the c-function lookes like this:

void shellsort(int a[], unsigned int n) {
    unsigned int gap, i, j;
for (gap = n / 2; gap > 0; gap = gap == 2 ? 1 : 5 * gap / 11) {
        for (i = gap; i < n; i++) {
            int tmp = a[i];
            for (j = i; j >= gap && tmp < a[j - gap]; j -= gap)
                a[j] = a[j - gap];
            a[j] = tmp;
        }
    }
}

And this is my stack using the gcc -S 32-bit Ubuntu

 12(%ebp)  = n
 8(%ebp)   = a[]
 -8(%ebp)  = tmp
 -12(%ebp) = j
 -16(%ebp) = i
 -20(%ebp) = gap
 -24(%ebp) = (gap * 4) + gap

Thanks in advance :)

Upvotes: 1

Views: 4912

Answers (2)

Sparky
Sparky

Reputation: 14057

There are two parts to your question.

The first as I understand it has to do with what [EBP-4] is used for. For that, I recommend you read a summary of the x86 stack frame at What is stack frame in assembly?.

To properly answer the whole 20/24 part of your question, we need to look at the disassembled code. The following is an extract from the disassembly of the C code you provided.

.LFB0:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp           /* (1) */
        .cfi_def_cfa_register 5
        pushl   %ebx                 /* (2) */
        subl    $20, %esp            /* (3) */
        movl    12(%ebp), %eax
        shrl    %eax
        movl    %eax, -20(%ebp)
        jmp     .L2
        .cfi_offset 3, -12

I have identified the three (3) key lines in the disassembled output above.

At (1), the base pointer is being set to the stack pointer. As per the information supplied in the link earlier, this is just part of setting up the stack frame.

At (2), we are saving EBX (a non-volatile register) to the stack. This automatically updates ESP (but not EBP), subtracting four from its current value. Note that after this operation, EBP = ESP + 4.

At (3), we are subtracting 20 from ESP. After this operation, EBP = ESP + 24.

That is why it is safe to access [EBP-20].

Hope this helps.

Upvotes: 1

Bryan Olivier
Bryan Olivier

Reputation: 5307

On the x86 ebp is typically used as the frame pointer and esp is the stack pointer. Around the frame pointer the frame pointer of the caller and the return address are saved. That could explain the gap. In my assembly actually -4(%ebp) is used, so maybe we are looking at a different ABI, but there should always be a gap for the stack administration.

About the -20 subtracted from the stack pointer and still access -24(%ebp): there is probably a push after the movl %esp, %ebp in your assembly, which would account for an additional 4 bytes.

Upvotes: 1

Related Questions