Что делают инструкции mov %edi и mov %rsi?

Я написал базовую программу C, которая определяет целочисленную переменную x, устанавливает ее в ноль и возвращает значение этой переменной:

#include <stdio.h>

int main(int argc, char **argv) {
    int x;
    x = 0;
    return x;
}

когда я сбрасываю объектный код с помощью objdump (скомпилированный на Linux X86-64 с gcc):

0x0000000000400474 <main+0>:    push   %rbp
0x0000000000400475 <main+1>:    mov    %rsp,%rbp
0x0000000000400478 <main+4>:    mov    %edi,-0x14(%rbp)
0x000000000040047b <main+7>:    mov    %rsi,-0x20(%rbp)
0x000000000040047f <main+11>:   movl   x0,-0x4(%rbp)
0x0000000000400486 <main+18>:   mov    -0x4(%rbp),%eax
0x0000000000400489 <main+21>:   leaveq 
0x000000000040048a <main+22>:   retq

Я вижу пролог функции, но прежде чем мы установим x в 0 по адресу 0x000000000040047f есть две инструкции, которые перемещают %edi и %rsi в стек. Для чего это?

кроме того, в отличие от того, где мы установили x в 0, mov инструкция, как показано в синтаксисе GAS, не имеет суффикса.

если суффикс не указан, и для инструкции нет операндов памяти, GAS выводит размер операнда из размера операнда регистра назначения.

в этом случае -0x14(%rsbp) и -0x20(%rbp) оба операнда памяти и каковы их размеры? Поскольку %edi является 32-битным регистром, 32 бита перемещаются в -0x14(%rsbp) в то время как %rsi является 64-битным регистром, 64 бита перемещаются в %rsi,-0x20(%rbp)?

2 ответов


в этом простом случае, почему бы вам не задать ваш компилятор напрямую? Для GCC, clang и ICC есть .

main:
    pushq   %rbp    #
    movq    %rsp, %rbp  #,
    movl    %edi, -20(%rbp) # argc, argc
    movq    %rsi, -32(%rbp) # argv, argv
    movl    , -4(%rbp)    #, x
    movl    -4(%rbp), %eax  # x, D.2607
    popq    %rbp    #
    ret

Итак, да, они спасают argv и argv в стек, используя" старый " метод указателя кадра, так как новые архитектуры позволяют вычитать/добавить из / в указатель стека напрямую, таким образом, опуская указатель кадра (-fomit-frame-pointer).


цель регистров ESI & EDI?

основываясь на этом и контексте, я не эксперт, но я предполагаю, что они захватывают main() параметры ввода. EDI принимает стандартную ширину, которая будет соответствовать int argc, тогда как RSI занимает много времени, что соответствует char **argv указатель.