Вывод сборки GCC пустой программы на x86, win32
я пишу пустые программы, чтобы раздражать ад из кодеров stackoverflow, нет. Я просто изучаю инструментальную цепочку gnu.
теперь следующее Может быть слишком глубоким для меня, но для продолжения пустой программы saga я начал изучать вывод компилятора C, материал GNU as потребляет.
gcc version 4.4.0 (TDM-1 mingw32)
.c:
int main()
{
return 0;
}
ЦУС -Ы.c
.file "test.c"
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
call ___main
movl , %eax
leave
ret
вы можете объяснить, что здесь происходит? Здесь это мое усилие, чтобы понять это. Я использовал as руководство и мои минимальные знания x86 ASM:
.file "test.c"- это директива для логического именем.
.def: по документам "начните определять отладочную информацию для имени символа". Что такое символ (имя функции/переменная?) а какая отладочная информация?
.scl: документы говорят "класс хранения может отмечать, является ли символ статическим или внешний". Это то же самое статический и внешний я знаю от C? И что это за '2'?
.type: сохраняет параметр "как атрибут типа записи таблицы символов", я понятия не имею.
.endef: никаких проблем.
.text: теперь это проблематично, похоже, что-то называется разделом, и я прочитал, что это место для кода, но документы мне тоже не сказали много.
.globl" делает символ видимым для ld.", руководство довольно ясно об этом.
_main:это может быть начальный адрес (?) для моей основной функции
pushl_: длинный (32bit) толчок, который помещает EBP в стек
movl: 32-разрядный двигаться. Псевдо-С:EBP = ESP;
andl: логическое "и". Псевдо-С:ESP = -16 & ESP, я не вижу, в чем дело.
call: Толкает IP в стек (так что вызываемая процедура может найти свой путь назад) и продолжает там, где__mainесть. (что составляет __главная?)
movl: этот ноль должен быть константой, которую я возвращаю в конце моего кода. MOV помещает этот ноль в EAX.
leave: восстанавливает стек после ввода инструкции (?). Зачем?
ret: возвращается к адресу инструкции, сохраненному в стеке
Спасибо за помогите!
5 ответов:
.файл " тест.с"
команды, начиная с . директивы в ассемблере. Это просто говорит, что это "файл.c", эта информация может быть экспортирована в отладочную информацию exe.
.деф ___главная; .scl 2; .тип 32; .endef
.директивы def определяют символ отладки. scl 2 означает класс хранения 2 (внешний класс хранения) .тип 32 говорит, что эта сумма является функцией. Эти номера будут определены в формате PE-coff exe
___main-это функция, которая заботится о начальной загрузке, необходимой gcc (она будет делать такие вещи, как запуск статических инициализаторов c++ и других необходимых домашних хозяйств).
.textначинается текстовый раздел-код живет здесь.
.globl _main
определяет символ _main как глобальный, что делает его видимым для компоновщика и других связанных модулей в.
.def _main; .scl 2; .type 32; .endefто же самое , что и _main, создает отладочные символы, указывающие, что _main является функцией. Это может быть использовано отладчиками.
_main:
запускает новую метку (она будет в конечном итоге адрес). этот.директива globl выше делает этот адрес видимым для других объектов.
pushl %ebpсохраняет старый указатель кадра (регистр ebp) в стеке (поэтому его можно вернуть на место, когда эта функция заканчивается)
movl %esp, %ebpперемещает указатель стека в регистр ebp. ebp часто называют указателем кадра, он указывает на верхнюю часть значений стека в текущем "кадре" (обычно функция), (ссылаясь на переменные в стеке через ebp может помочь отладчикам)
andl $-16, %esp
и стек с fffffff0, который эффективно выравнивает его на границе 16 байт. Доступ к выровненным значениям в стеке осуществляется намного быстрее чем если бы они были не выровнены. Все эти предыдущие инструкции в значительной степени являются стандартным прологом функции.
call ___mainвызывает функцию __ _ main, которая будет выполнять инициализацию того, что нужно gcc. Вызов будет нажимать текущий указатель инструкции на стеке и перейти к адресу __ _ main
movl , %eaxШаг 0 в регистре eax,(0 в возврат 0;) регистр eax используется для хранения возвращаемых значений функций за нарушением соглашения о стандартном вызове конвенция.
оставить
инструкция по отпуску в значительной степени сокращена для
movl ebp,esp popl ebpт. е. он "отменяет" материал, сделанный в начале функции-восстановление указателя кадра и стека в его прежнее состояние.
ret
возвращает тому, кто вызвал эту функцию. Он выведет указатель инструкции из стека (который будет помещен соответствующей инструкцией вызова там) и прыгай туда.
есть очень похожее упражнение, описанное здесь:http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax
вы поняли большую часть этого -- я просто сделаю дополнительные заметки для акцента и дополнений.
__mainЭто подпрограмма в стандартной библиотеке GNU, которая заботится о различных инициализации запуска. Это не является строго необходимым для программ C, но требуется только в том случае, если код C связывается с С.++
_mainваша основная подпрограмма. А как_mainи__mainявляются кодовыми местоположениями, они имеют один и тот же класс хранения и тип. Я еще не выкопал определения для.sclи.typeеще. Вы можете получить некоторое освещение, определив несколько глобальных переменных.первые три инструкции настраивают кадр стека, который является техническим термином для рабочего хранения подпрограммы - локальные и временные переменные по большей части. Толкает
ebpсохраняет основание кадра стека вызывающего объекта. Положитьespнаebpустановка базы кадра стека. Элементandlвыравнивает кадр стека до границы 16 байт только в том случае, если какие-либо локальные переменные в стеке требуют выравнивания 16 байт (для инструкций x86 SIMD требуется это выравнивание, но выравнивание ускоряет обычные типы, такие какints иfloats.в этот момент Вы обычно ожидаете
espдля перемещения вниз в памяти, чтобы выделить пространство стека для локального переменная. Вашmainнет, поэтому gcc не беспокоит.вызов
__mainявляется специальным для основной точки входа и обычно не отображается в подпрограммах.остальное идет, как вы предположили. Регистрация
eaxэто место, чтобы поместить целочисленные коды возврата в двоичной спецификации.leaveотменяет кадр стека иretвозвращается к звонящему. В этом случае вызывающий объект-это низкоуровневая среда выполнения C, которая будет выполнять дополнительную магию (например, вызовatexit()функции, установите код выхода для процесса и попросите операционную систему завершить процесс.
по этому andl $-16,%esp
- 32 бит: -16 в десятичном равен 0xfffffff0 в шестнадцатеричном представлении
- 64 бит: -16 в десятичном виде равно 0xfffffffffffffff0 в шестнадцатеричном представлении
таким образом, он будет маскировать последние 4 бита ESP (кстати: 2**4 равно 16) и сохранит все остальные биты (независимо от того, является ли целевая система 32 или 64 бит).
дальше
andl $-16,%esp, это работает, потому что установка низких битов на ноль всегда будет регулировать%espвниз в значении, и стек растет вниз на x86.
у меня нет всех ответов, но я могу объяснить, что я знаю.
ebpиспользуется функцией для хранения начального состоянияespво время его потока ссылка на то, где аргументы передаются функции и где находятся ее собственные локальные переменные. Первое, что делает функция, это сохранить статус данногоebpделаешьpushl %ebp, это жизненно важно для функции, которая делает вызов, и чем заменяет его на свою текущую позицию стекаespделаешьmovl %esp, %ebp. Обнуление последних 4 битebpна данный момент GCC специфичен, я не знаю, почему этот компилятор делает это. Он будет работать, не делая этого. Теперь, наконец, мы идем в бизнес,call ___main, кто _ _ главный? Я не знаю... возможно, больше специальных процедур GCC, и, наконец, единственное, что делает ваш main (), установите возвращаемое значение как 0 сmovl , %eaxиleaveэто то же самое, что делатьmovl %ebp, %esp; popl %ebpвосстановитьebpгосударство, тоretдо конца.retpopseipи продолжить поток потока от этот момент, где бы он ни был (как его основной(), этот ret, вероятно, приводит к некоторой процедуре ядра, которая обрабатывает конец программы).большинство из них все об управлении стеком. Я написал подробный учебник о том, как используется стек некоторое время назад, было бы полезно объяснить, почему все эти вещи сделаны. Но это на португальском языке...
Comments