В чем разница между меткой и функцией в сборке

Следовал инструкции по сборке на 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, программный счетчик) помещаются / сохраняются в стек. При выполнении команды возврата данные из стека восстанавливаются. Это необходимо для возможности продолжить выполнение программы с адреса сразу после вызова вашей функции.

Другие вопросы по тегам