Добрый день. Есть исходник file.c: main(){} компилю gcc -S file.c открываю листинг file.s _main: pushl %ebp movl %esp, %ebp subl $8, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax movl %eax, -4(%ebp) movl -4(%ebp), %eax call __alloca call ___main leave ret Откуда столько кода, и что он означает, это что то вроде шапки, но что она делает? =============================================================== компилю с оптимизацией gcc -S -O3 file.c _main: pushl %ebp movl $16, %eax movl %esp, %ebp subl $8, %esp andl $-16, %esp call __alloca call ___main leave ret Все равно много кода, что вырезала оптимизация, почему не все? З.Ы. Как оформить ассемблерную вставку для gcc? __asm{inc cx}; не работает :|
Вот так работает asm("inc %cx"); =) Ну дак как на счет листинга, понимаю неохота разжовывать, но всетаки ^_^
movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax тут написано: eax=((0+15+15)/2^4)*2^4 что эквивалентно eax=16. Поэтому вместо вышеприведенного кода получаем: movl $16, %eax --------- movl %eax, -4(%ebp) movl -4(%ebp), %eax тут написано: [ebp-4] = eax; eax = [ebp-4]. Это тоже самое, что и b=a; a=b; но b потом нигде не используется. Понятное дело, что компилятор это пропустит, что он собственно и сделал. ------------ pushl %ebp movl %esp, %ebp subl $8, %esp andl $-16, %esp ... leave ret тут написан вход и выход в процедуру. Третья строка "выделяет" стековую память под переменную b, которая не используется. Четвертая для выравнивания стековой памяти по 16 байтной границе. Т.к. переменная b не используется, то это все кроме ret я бы убрал и оставил вот в таком виде: _main: movl $16, %eax call __alloca call ___main retn
Хотелось бы понять почему компилятор такой тривиальный код превращает, в большой набор ненужных в принципе ассемблерных строчек?
igrock Дык компилятор создает так называемый "startup-code", из которого, собственно и вызывается функция main. В зависимости от того, под какую платформу компилируется код, стартовый код будет выглядеть по-разному. К примеру, если ты пишешь консольное приложение, то компилятор передаст твоей функции main ряд аргументов (int argc, char *argv[], ...). В твоем случае, поскольку у тебя аргументы в функцию main не передаются, и код достаточно простой (я, правда, особенностей используемого тобой компилятора не знаю, говорю с общих позиций). Если ты посмотришь стартовый код в программах для Win32, то увидишь, что кода больше, так как операционной системе нужно проделать определенную работу (создать среду исполнения) прежде чем будет вызвана функция WinMain. В Билдере и Дельфи стартовый код больше, поскольку требуется совершить еще больше действий (инициализация библиотек Борланда, загрузка ресурсных строк и т.д.).
igrock Дополню crypto Хотя в определённых случаях стартовый код в полном объёме не нужен (данная программа -- именно такой случай), но у компилятора либо вовсе нет разных вариантов стартового кода (и тогда он одинаковый для всех), либо вариаций сравнительно мало -- вот он и лепит кучу лишнего.