Функция сборки Целочисленная Локальная переменная - PullRequest
2 голосов
/ 13 января 2011

Я пытаюсь выучить базовую сборку. Я написал простую программу на C для перевода в сборку:

void myFunc(int x, int y) {
    int z;
}

int main() {
    myFunc(20, 10);
    return 0;
}

Это то, что я думал, что правильный перевод функции будет:

.text
.globl _start
.type myFunc, @function

myFunc:
    pushl %ebp        #Push old ebp register on to stack
    movl %esp, %ebp   #Move esp into ebp so we can reference vars
    sub $4, %esp      #Subtract 4 bytes from esp to make room for 'z' var
    movl $2, -4(%ebp) #Move value 2 into 'z'
    movl %ebp, %esp   #Restore esp
    popl %ebp         #Set ebp to 0?
    ret               #Restore eip and jump to next instruction

_start:
    pushl $10        #Push 10 onto stack for 'y' var
    pushl $20        #Push 20 onto stack for 'x' var
    call myFunc      #Jump to myFunc (this pushes ret onto stack)
    add $8, %esp     #Restore esp to where it was before

    movl $1, %eax    #Exit syscall
    movl $0, %ebx    #Return 0
    int $0x80        #Interrupt

Просто чтобы дважды проверить это, я запустил его в GDB и был смущен результатами:

(gdb) disas myFunc
Dump of assembler code for function myFunc:
0x08048374 <myFunc+0>:  push   ebp
0x08048375 <myFunc+1>:  mov    ebp,esp
0x08048377 <myFunc+3>:  sub    esp,0x10
0x0804837a <myFunc+6>:  leave
0x0804837b <myFunc+7>:  ret    
End of assembler dump.

Почему в 0x08048377 gcc вычел из стека 0x10 (16 байтов), когда целое число имеет длину 4 байта?

Кроме того, инструкция по отпуску эквивалентна следующей?

    movl %ebp, %esp   #Restore esp
    popl %ebp         #Set ebp to 0?

Использование:

gcc version 4.3.2 (Debian 4.3.2-1.1)
GNU gdb 6.8-debian

Ответы [ 2 ]

7 голосов
/ 13 января 2011

В зависимости от платформы, GCC может выбирать различные выравнивания стека; это может быть отменено, но это может замедлить работу программы или привести к ее аварийному завершению. Значение по умолчанию -mpreferred-stack-boundary=4 сохраняет стек в соответствии с 16-байтовыми адресами. Предполагая, что указатель стека уже правильно выровнен в начале функции, он останется выровненным после sub %esp, $10.

leave - это макроинструкция x86, эквивалентная mov %ebp, %esp; pop %ebp.

4 голосов
/ 13 января 2011

Ваш GDB настроен на печать Intel вместо синтаксиса сборки AT & T - отключите его, пока он не смутил вас больше, чем уже есть.

Указатель стека (%esp) требуется всегда выровнять по 16-байтовой границе. Это, вероятно, откуда приходит sub esp,0x10. (Это не нужно, но GCC исторически плохо замечал, что настройки стека не нужны.) Кроме того, ваша функция не делает ничего интересного, поэтому тело было оптимизировано. Вы должны были скомпилировать этот код:

int myFunc(int x, int y)
{
    return x + y;
}

int main(void)
{
    return myFunc(20, 30);
}

Это создаст ассемблер, который будет проще сопоставить с исходным C. GCC будет по-прежнему разрешено производить

main:
    movl $50,%eax
    ret

и ничего больше, но, вероятно, этого не произойдет, если вы не используете -O3 -fwhole-program; -)

...