В чем разница между меткой и функцией в сборке
Следовал инструкции по сборке на YouTube здесь через синтаксис AT&T. Я только что узнал об объявлении (если это правильный термин здесь) функции с директивой.type, такой как:
.type MyFunction, @function Теперь я могу определить свою функцию следующим образом:
MyFunction: и впоследствии вызывать его всякий раз, когда:
call MyFunction. Я знаю, что до этого в уроках мы просто создавали метку, которая была прикреплена к некоторому коду:
MyLabel: который затем можно было бы назвать так:
позвоните MyLabel Итак, мои вопросы:
В чем именно разница между функцией, объявленной с.type, и функцией ', объявленной просто с меткой? Когда один должен быть использован поверх другого, или это имеет значение?
3 ответа
Вот что в документации binutils говорится о.type
директива (при условии, что вы используете ассемблер GNU):
Эта директива используется для установки типа символа.
...
Для целей ELF директива.type используется следующим образом:
.type name , type description
Согласно документам по типу символа:
Атрибут type символа содержит информацию о перемещении (разделе), любые настройки флага, указывающие, что символ является внешним, и (необязательно) другую информацию для компоновщиков и отладчиков. Точный формат зависит от используемого формата вывода объектного кода.
.type MyFunction, @function
отмечает этикетку MyFunction
(который является символом) как функция для компоновщика или отладчика.
При написании файлов чистой сборки вручную в этом нет необходимости. Вот пример файла, в которомitoa
функция вызывается. Как видите, перед меткой нет директив.
Таким образом, метки могут быть помечены как функции, но для выполнения кода в любом случае это просто цель перехода.
Что касается процессора, то разницы нет. Многие ассемблеры не требуют от вас объявления.type MyFunction, @function
совсем; скорее, вы просто ставите куда хотите, а затемcall MyFunction
Идти туда.
Метки — это особенность ассемблеров, которая делает их гораздо более удобными в использовании, чем то, что люди делали до их появления (например, ввод байтов с помощью шестнадцатеричного редактора).
MyFunction:
nop
ret
фактически является постоянным указателем на инструкцию, расположенную непосредственно под ней, в данном случаеnop
. В зависимости от того, сколько кода находится в вашем файле и где он находится, метка равна некоторому числу, но гораздо проще позволить ассемблеру управлять этим за нас.
Представьте, если бы у нас не было ярлыков. Нам пришлось бы помнить, по какому адресу находится адрес, и каждый раз, когда мы меняем нашу программу, нам пришлось бы вручную обновлять все операторы и с правильным пунктом назначения. Звучит ужасно, не так ли?
Относительные ветки обрабатываются по-разному, но конечный результат тот же. Для чего-то вроде этого:
MyFunction:
add eax,ebx
jne MyFunction
вjne MyFunction
не кодируется как постоянный адрес, а представляет собой смещение со знаком, которое добавляется/вычитается из%rip
чтобы сделать его равным любой ячейке памяти, соответствующейMyFunction
является.
РЕДАКТИРОВАТЬ: на x86jmp
иcall
также относительны, как в приведенном выше примере, но это не относится ко всем архитектурам.
Я думаю, какую бы сборку вы ни использовали, это команда возврата. Какое бы имя "return" ни использовалось в вашем ассемблере. Вызов функции отличается от ветвления тем, что некоторые данные контекста (регистр состояния с битами N, C, V, программный счетчик) помещаются / сохраняются в стек. При выполнении команды возврата данные из стека восстанавливаются. Это необходимо для возможности продолжить выполнение программы с адреса сразу после вызова вашей функции.