Давайте разбить его:
.file "delta.c"
Компилятор использует это, чтобы сказать вам исходный файл, сборка из. Это мало значит для ассемблера.
.section .rodata
Это начинает новый раздел. «Родата» - это название раздела «Только для чтения». Этот раздел завершает запись данных в исполняемый файл, который получает память, отображаемую как данные только для чтения. Все страницы «.rodata» исполняемого образа в конечном итоге разделяются всеми процессами, загружающими изображение .
Как правило, любые «константы времени компиляции» в исходном коде, которые не могут быть оптимизированы в рамках встроенных функций, будут храниться в разделе «Только чтение данных».
.LC0:
.string "%d"
.LC0"
часть этикетки. Это доказывает символическое имя, которое ссылается на байты, которые происходят после него в файле. В этом случае «LC0» представляет строку «% d». Ассемблер GNU использует соглашение о том, что метки, начинающиеся с «L», считаются «локальными метками». Это имеет технический смысл, который в основном интересен людям, которые пишут компиляторы и линкеры. В этом случае он используется компилятором для обращения к символу, который является частным для конкретного объектного файла. В этом случае он представляет собой строчную константу.
.text
Это начинает новый раздел. Раздел «текст» - это раздел в объектных файлах, в которых хранится исполняемый код.
.globl main
«.global» директива указывает ассемблеру, чтобы добавить метку, которая следует за ним в списке ярлыков „экспортируемые“ генерируемым объектный файл. Это в основном означает «это символ, который должен быть видимым компоновщику». Например, «нестатическая» функция в «C» может быть вызвана любым c-файлом, который объявляет (или включает) прототип совместимой функции. Вот почему вы можете #include stdio.h
, а затем позвонить printf
. Когда какая-либо нестатическая C-функция компилируется, компилятор создает сборку, которая объявляет глобальную метку, указывающую в начале функции. Сравните это с вещами, которые не должны быть связаны, например, с строковыми литералами. Ассемблерный код в объектном файле по-прежнему нуждается в ярлыке для ссылки на литеральные данные. Это «местные» символы.
.type main, @function
Я не знаю точно, как GAS (ГНУ ассемблер) обрабатывает «.Type» директивы. Однако это указывает ассемблеру, что метка «main» относится к исполняемому коду, а не к данным.
main:
Это определяет точку входа для вашей «основной» функции.
.LFB0:
Это «местная метка», которая относится к началу функции.
.cfi_startproc
Это директива «Информация о кадре». Он инструктирует ассемблер испускать информацию для отладки формата карлика.
pushl %ebp
Это стандартная часть функции «пролог» в ассемблере. Он сохраняет текущее значение регистра «ebp». Регистр «ebp» или «base» используется для хранения «базы» фрейма стека внутри функции. В то время как регистр esp («указатель стека») может меняться, поскольку функции вызываются внутри функции, «ebp» остается фиксированным. Любые аргументы функции всегда можно получить относительно «ebp». По соглашениям ABI, прежде чем functon сможет изменить регистр EBP, он должен сохранить его, чтобы исходное значение могло быть восстановлено до возвращения функции.
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
Я не исследовал их подробно, но я считаю, что они связаны с DWARF отладочной информации.
movl %esp, %ebp
ГАЗ использует AT & T синтаксис, что в обратном направлении от того, что использует руководство Intel. Это означает, что «set ebp равен esp». Это в основном устанавливает «базовый указатель» для остальной части функции.
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
Это также часть эпилятора для функции. Это выравнивает указатель стека, а затем вычитает из него достаточно места, чтобы удерживать все локали для функции.
movl $4, 28(%esp)
Это загружает 32-битную целую константу 4 в слот в кадре стека.
movl $.LC0, %eax
Это загружает константу строки "% d", определенную выше, в eax.
movl 28(%esp), %edx
Это загружает значение «4», сохраненное в смещении 28 в стеке, в edx. Скорее всего, ваш код был скомпилирован с отключенными оптимизациями.
movl %edx, 4(%esp)
Затем оно перемещает значение 4 в стек, в том месте, которое должно быть при вызове printf.
movl %eax, (%esp)
Это загружает строку «% d» в место в стеке, которое должно быть при вызове printf.
call printf
Это вызывает печатьf.
movl $0, %eax
Это устанавливает EAX значение 0. Учитывая, что следующие инструкции «оставить» и «в отставке», это equavlent «вернуть 0» в коде C. Регистр EAX используется для хранения возвращаемого значения функции.
leave
Эта инструкция очищает рамку вызова.Он возвращает ESP обратно в EBP, затем выталкивает EBP из модифицированного указателя стека. Как и следующая инструкция, это часть эпилога этой функции.
.cfi_restore 5
.cfi_def_cfa 4, 4
Это более DWARF материал
ret
Это фактическая команда возврата. Он возвращается из functon
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",@progbits
Какая часть дает вам проблемы? Мы не можем объяснить каждую строку, если вы на этом уровне, вам нужно начать с чтения книги, а не путем прямого перехода к чему-то непонятным. Расскажите нам, какие части вы понимаете и какие части вы не понимаете. – Gilles
В вашем примере есть несколько основных понятий, которые будут затеряться в процессе объяснения инструкций по строкам. Если у вас мало или вообще нет понимания инструкций по сборке, вы должны получить книгу или какой-либо онлайн-материал, начиная с основ. Как только вы знакомы с работой инструкций, можно охватить более широкие концепции управления фреймом стека, правилами регистрации/памяти и функциональными вызовами. – lurker
На самом деле, я мало знаю о языках ассемблера, все, что я знаю, это мотив, добавление и т. Д. Я бы лучше выбрал ваше мнение. –