Какова цель директивы ассемблера GNU .code16? - PullRequest
0 голосов
/ 02 февраля 2020

Я не понимаю практического использования .code16 или других .code* директив. Что я понял из ответов на этот вопрос о StackOverflow ,

, когда кто-то определяет .code16 в своем коде сборки и делает следующее:

$ gcc -c -m32 -o main.o main.s

Он игнорирует .code16 и выходная сборка должны работать на 32-битной платформе. Если кто-то не указывает флаг -m, он, по-видимому, выбирает флаг, настроенный для g cc по умолчанию, в зависимости от хоста. Следовательно, в заключение, директива .code* всегда игнорируется и заменяется флагом -m.

Может кто-нибудь поправить меня, если я ошибаюсь в моем понимании, и какова ситуация, когда я буду использовать .code16 потому что я всегда могу определить, что использование -m16 и .code* в любом случае будет игнорироваться в зависимости от целевого режима.

.code16 (или другие) предназначены только для того, чтобы выдавать ошибки, когда данные не могут не вписываются в 16-битные регистры, иначе иначе они останутся бездействующими?

1 Ответ

0 голосов
/ 02 февраля 2020

Единственная причина, по которой вы обычно используете .code16, .code32 или .code64, заключается в ядре или загрузчике , когда вы хотите иметь машинный код для разных режимов в одном файле, Например, загрузчик, который запускается в реальном режиме (.code16), может включить защищенный режим и выполнить дальний переход (ljmp) к сегменту 32-битного кода. Вы хотите использовать .code32 перед этим блоком кода.

Если это не то, что вы делаете, не используйте их.

Использование их в других случаях просто позволяет вам застрелите себя в ногу и поместите 16-битный машинный код в 32-битный или 64-битный исполняемый файл ELF, чтобы вы получили ошибку времени выполнения вместо того, чтобы перехватить ошибку во время сборки. (например, потому что push %eax недопустим в 64-битном режиме). Не помещайте .code32 в начало вашей 32-битной программы; используйте комментарий, который говорит, что для сборки с gcc -m32.

Эти директивы сообщают ассемблеру, в каком режиме будет CPU, когда он декодирует эти инструкции . Таким образом, он знает, каким будет размер операнда по умолчанию и размер адреса, и нужен ли префикс для инструкции, которая использует 32-битный или 16-битный регистр.

Так, например, mov %eax, (%ecx) монтируется в 89 01 в 32-битном режиме.

Но после .code16 он монтируется в 67 66 89 01.

Если вы затем разберете это как 32-битный машинный код, это 67 66 89 01 mov %ax, (%bx,%di) (потому что ModRM отличается для операндов памяти в 16 против 32 и 64-битном режиме).


Обычно вы не используете .code16 вручную. Вы можете использовать gcc -m16 foo.c, чтобы получить G CC для вставки .code16gcc в начало файла, так что вы можете запустить его в 16-битном режиме, даже если он по-прежнему будет использовать 32-битный размер операнда и размер адреса (требуется 386-совместимый ЦП).


Если вы хотите включить 32 или 16-битный машинный код в качестве данных в обычную 64-битную программу, например, вашу программу Вы можете записать его в файл или изменить запущенный процесс, вы также можете использовать .code32 или .code16.

...