Это не отвечает в общем случае. Это зависит от целевой платформы. Если вы хотите проверить сборку, вы можете сделать это с параметром -S
с помощью gcc
. Когда я сделал это с вашим кодом, он дал мне следующее:
/tmp$ cat main.s
.file "main.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $3, -4(%rbp)
addl $1, -4(%rbp)
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 9.2.1-8) 9.2.1 20190909"
.section .note.GNU-stack,"",@progbits
Краткое краткое объяснение того, что здесь происходит. Сначала мы нажимаем значение стека указателя. Это так, чтобы мы могли вернуться позже.
.cfi_startproc
pushq %rbp
Затем мы устанавливаем кадр стека с этим кодом. Это соответствует объявлению переменных.
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
Тогда мы имеем это. Комментарии мои.
movl $3, -4(%rbp) # i = 3;
addl $1, -4(%rbp) # i = i + 1;
Наконец, мы возвращаемся из основной функции
movl $0, %eax # Store 0 in the "return register"
popq %rbp # Restore stackpointer
.cfi_def_cfa 7, 8
ret # return
Обратите внимание, что между строками нет связи 1-1. Даже для очень простых линий.
Обратите также внимание, что C накладывает требование на наблюдаемое поведение программы, а не на сгенерированную сборку. Так, например, компилятор может удалить все тело для главной функции, потому что переменная i
не используется видимым образом. И это будет, если вы используете оптимизацию. Когда я перекомпилировал ваш код с помощью -O3
, я получил это вместо:
/tmp/$ cat main.s
.file "main.c"
.text
.section .text.startup,"ax",@progbits
.p2align 4
.globl main
.type main, @function
main:
.LFB11:
.cfi_startproc
xorl %eax, %eax
ret
.cfi_endproc
.LFE11:
.size main, .-main
.ident "GCC: (Debian 9.2.1-8) 9.2.1 20190909"
.section .note.GNU-stack,"",@progbits
Обратите внимание, сколько было удалено из main. Интересно, что movl $0, %eax
изменилось на xorl %eax, %eax
. Если вы думаете об этом, то совершенно очевидно, что это операция «установка нуля». Можно разумно спорить, почему кто-то может писать такие вещи. Ну, оптимизатор, конечно, не оптимизировать для удобства чтения. Есть несколько причин, почему это лучше. Вы можете прочитать о них здесь: Как лучше всего установить регистр в ноль в сборке x86: xor, mov или и?