Почему сгенерированная сборка перемещает edi в переменную в стеке? - PullRequest
0 голосов
/ 07 апреля 2019

Я новичок в сборке, пытаясь понять objdump следующей функции:

int nothing(int num) {
    return num;
}

Это результат (linux, x86-64, gcc 8):

push   rbp
mov    rbp,rsp
mov    DWORD PTR [rbp-0x4],edi
mov    eax,DWORD PTR [rbp-0x4]
pop    rbp
ret    

Мои вопросы: 1. Откуда взялся edi?Читая некоторые вступительные документы, у меня сложилось впечатление, что [rbp-0x4] будет содержать num.2. Из вышесказанного, очевидно, edi содержит аргумент.Но тогда какую роль играет [rbp-0x4]?Почему бы просто не mov eax, edi?

Спасибо!

1 Ответ

3 голосов
/ 07 апреля 2019
  1. Откуда берется edi?

... Из вышеприведенного, очевидно, edi содержит аргумент.

Этосоглашение о вызовах (для Linux и многих других ОС):

Все языки программирования для этих ОС передают первый параметр в rdi.Результат (возвращаемое значение) передается в rax.

И поскольку ваш компилятор C интерпретирует int как 32 бита, используются только младшие 32 бита rdi и rax, чтоedi и eax.

Языки программирования для Windows передают первый параметр в rcx ...

Но тогда какую роль играет [rbp-0x4]?

Использование rbp имеет в основном исторические причины.В 16-битном коде (как он использовался в ПК 1980-х и 1990-х годов) было невозможно адресовать данные в стеке с помощью регистра sp (что соответствует rsp).Единственный регистр, который позволял легко адресовать значения в стеке, был регистр bp (соответствующий rbp).

И даже в 32- или 64-битном коде сложнее написать компилятор, которыйобращается к локальным переменным (в стеке), используя rsp, а не rbp.

Компилятор генерирует первые 3 инструкции кода ассемблера, прежде чем он узнает, что делается в функции C.Компилятор помещает значение в стек, потому что вы можете сделать что-то вроде address = &num в коде.Это, однако, невозможно, когда num находится в регистре, но только когда num находится в памяти.

Почему бы не просто mov eax, edi?

Если вы скажете компилятору оптимизировать код, он сначала проверит содержимое функции C перед генерацией первой инструкции на ассемблере.Он обнаружит, что не нужно помещать значение в память.

В этом случае код действительно будет выглядеть так:

mov eax, edi
ret
...