Как ОПЕРАЦИОННАЯ система влияет на то, как выполняется ассемблерный код?

StackOverflow https://stackoverflow.com/questions/1175375

  •  19-09-2019
  •  | 
  •  

Вопрос

Я надеюсь выучить язык ассемблера для x86.Я нахожусь на Mac, и я предполагаю, что большинство руководств / книг по x86 используют код, предназначенный для Windows.

Как ОПЕРАЦИОННАЯ система, на которой выполняется код, влияет на то, что делает код, или определяет, работает ли код вообще?Могу ли я следовать руководству для Windows и изменить несколько команд, чтобы оно работало для Mac с относительной легкостью?В более общем плане, есть ли что-нибудь сложное, что, в частности, должен знать программист Mac assembly?Спасибо!

Это было полезно?

Решение

(Конечно, применимо все нижеследующее Только на язык ассемблера x86 и x86-64, для процессоров IA-32 и AMD64 и операционных систем.)

Все остальные ответы, которые видны в данный момент, верны, но, на мой взгляд, упускают суть.Синтаксис AT & T по сравнению с Intel - это совершенно не проблема;любой приличный инструмент будет работать с обоими синтаксисами или иметь аналог или замену, которая работает.И они все равно собирают одно и то же.(Подсказка:вы действительно хотите использовать синтаксис Intel.Вся официальная документация по процессору так и делает.Синтаксис AT & T - это всего лишь одна гигантская головная боль.) Да, найти правильные флаги для передачи ассемблеру и компоновщику может быть непросто, но вы будете знать, когда получите их, и вам нужно будет сделать это только один раз для каждой операционной системы (если вы не забудете это где-нибудь записать!).

Сами инструкции по сборке, конечно, полностью не зависят от операционной системы.Центральный процессор ему все равно под какой операционной системой он запущен.Если вы не занимаетесь хакерством крайне низкого уровня (то есть разработкой операционной системы), тонкости взаимодействия операционной системы и процессора практически не имеют значения.

Внешний мир

Проблема с языком ассемблера возникает, когда вы взаимодействуете с внешним миром:ядро операционной системы и другой пользовательский код.Пользовательское пространство - самое сложное:вы должны правильно настроить ABI, иначе ваша программа сборки практически бесполезна.Эта часть, как правило, не переносима между операционными системами, если вы не используете trampolines / thunks (по сути, еще один уровень абстракции, который необходимо переписать для каждой ОС, которую вы собираетесь поддерживать).

Наиболее важной частью ABI является независимое соглашение о вызове функций в стиле C.Это то, что поддерживается чаще всего, и с чем вы, вероятно, будете взаимодействовать, если будете писать assembly.Агнер Фог располагает несколькими хорошими ресурсами по его сайт;тот самый подробное описание соглашений о вызовах это особенно полезно.В своем ответе Норман Рэмси упоминает PIC и динамические библиотеки;по моему опыту, вам обычно не нужно беспокоиться о них, если вы этого не хотите.Статическое связывание отлично работает для типичных применений языка ассемблера (например, для перезаписи основных функций внутреннего цикла или другой точки доступа).

Соглашение о вызовах работает в двух направлениях:вы можете вызвать C из assembly или assembly из C.Последнее, как правило, немного проще, но большой разницы нет.Вызов C из assembly позволяет вам использовать такие вещи, как функции вывода стандартной библиотеки C, в то время как вызов assembly из C обычно позволяет получить доступ к реализации сборки одной функции, критичной для производительности.

Системные вызовы

Другая вещь, которую будет делать ваша программа, - это выполнять системные вызовы.Вы можете написать полную и полезную программу на ассемблере, которая никогда не вызывает внешние функции C, но если вы хотите написать программу на чистом языке ассемблера, которая не передает забавные вещи на аутсорсинг в чужой код, вы собираетесь потребность системные вызовы.И, к сожалению, системные вызовы совершенно разные в каждой операционной системе.Системные вызовы в стиле Unix, которые вам понадобятся, включают в себя (но, безусловно, ими не ограничиваются!) open, creat, read, write, и самое важное exit, вместе с mmap если вам нравится динамически выделять память.

Хотя все операционные системы отличаются друг от друга, большинство современных операционных систем следуют общему шаблону:обычно вы загружаете номер нужного системного вызова в регистр EAX в 32-разрядном коде затем загрузите параметры (как вы это делаете, сильно варьируется) и, наконец, отправьте запрос на прерывание:это INT 2E для ядер Windows NT или INT 80h для Linux 2.x и FreeBSD (и, я полагаю, OSX).Затем ядро берет управление на себя, выполняет системный вызов и возвращает выполнение вашей программе.В зависимости от операционной системы это может привести к удалению регистров или стекирования как часть системного вызова;чтобы быть уверенным, вам нужно обязательно ознакомиться с документацией по системным вызовам для вашей платформы.

SYSENTER

Ядра Linux 2.6 (и, я полагаю, Windows XP и новее, хотя на самом деле я никогда не пробовал это в Windows) также поддерживают более новый и быстрый метод выполнения системного вызова:тот самый SYSENTER инструкция, введенная Intel в новых чипах Pentium.Чипы AMD имеют SYSCALL, но немногие 32-разрядные операционные системы используют его (хотя, я думаю, это стандарт для 64-разрядных;Мне не приходилось выполнять прямые системные вызовы из 64-разрядной программы, поэтому я не уверен в этом). SYSENTER значительно сложнее в настройке и использовании (см., например, Линус Торвальдс о внедрении SYSENTER поддержка Linux 2.6:"Я отвратительная свинья и горжусь этим в придачу"). Я могу лично засвидетельствовать ее особенность;Однажды я написал функцию сборки, которая выдавала SYSENTER непосредственно к ядру Linux 2.6, и я все еще не понимаю различных трюков со стеком и регистрацией, которые заставили это работать...но работа у него получилась!

SYSENTER это несколько быстрее, чем выдача INT 80h, и поэтому его использование желательно, когда оно доступно.Чтобы упростить написание как быстрого, так и переносимого кода, Linux сопоставляет VDSO, называемый linux-gate в адресное пространство каждой программы;вызов специальной функции в этом VDSO вызовет системный вызов с помощью самого быстрого доступного механизма.К сожалению, его использование, как правило, доставляет больше хлопот, чем того стоит: INT 80h это настолько проще сделать в небольшой процедуре сборки, что это стоит небольшого снижения скорости.Если только вам не нужна максимальная производительность...и если вам это нужно, вы, вероятно, все равно не захотите обращаться к VDSO, и вы знаете свое оборудование, так что вы можете просто сделать ужасно небезопасную вещь и выдать SYSENTER себя.

Все Остальное

Помимо требований, предъявляемых взаимодействием с ядром и другими программами, различий между операционными системами очень, очень мало.Сборка раскрывает душу машины:вы можете работать так, как вам нравится, и внутри вашего собственного кода вы не связаны каким-либо конкретным соглашением о вызовах.У вас есть свободный доступ к подразделениям FPU и SSE;ты можешь PREFETCH напрямую передавать данные из памяти в кэш L1 и следить за тем, чтобы они были горячими, когда вам это нужно;вы можете жевать стопку по своему желанию;вы можете выдать INT 3 если вы хотите взаимодействовать с (правильно настроенным;удачи!) внешний отладчик.Ни одна из этих вещей не зависит от вашей операционной системы.Единственное реальное ограничение, которое у вас есть, заключается в том, что вы работаете в кольце 3, а не в кольце 0, и поэтому некоторые управляющие регистры процессора будут вам недоступны.(Но если они вам нужны, вы пишете код операционной системы, а не код приложения.) В остальном машина открыта для вас:идите вперед и вычисляйте!

Другие советы

Вообще говоря, пока вы используете один и тот же ассемблер и одну и ту же архитектуру (например, NASM и x86-64), вы сможете собирать сборку как на Windows, так и на Mac.

Однако важно иметь в виду, что форматы исполняемых файлов и среды выполнения могут различаться.Например, Windows может эмулировать/обрабатывать определенные привилегированные инструкции иначе, чем Mac, что приводит к другому поведению.

Также большая часть разницы заключается в том, как программа взаимодействует с внешним миром.

Например, если вы хотите отобразить сообщение пользователю, прочитать файл или выделить больше памяти, вам нужно попросить ОС сделать это, выполнив какой-то системный вызов.Это будет совсем другое между ОС.

Сам синтаксис языка должен быть в основном идентичен, если вы используете один и тот же ассемблер.Разные ассемблеры иногда имеют немного разный порядок синтаксиса или разные макросы, но к этому нет ничего сложного.

Большой разрыв в языке ассемблера Intel происходит между синтаксисом AT&T и синтаксисом Intel.Вам понадобится ассемблер для вашего Mac, который использует тот же синтаксис, что и все используемые вами учебные пособия.Поскольку я считаю, что MacOS Darwin, вариант BSD, использует синтаксис AT&T, а ассемблер Microsoft использует синтаксис Intel, вам нужно быть осторожным.

Другое отличие, на которое следует обратить внимание, — это системный двоичный интерфейс приложений (ABI), который охватывает соглашения о вызовах, структуру стека, системные вызовы и т. д.Они могут существенно отличаться в разных ОС, особенно когда дело касается позиционно-независимый код и динамическое связывание.У меня остались смутные неприятные воспоминания о том, что PIC был особенно сложен на PowerPC MacOS, но, возможно, на Intel он проще.

Один совет: узнать x86_64 (также известный как AMD64) — гораздо интереснее писать ассемблерный код вручную, и вы будете более подготовлены к будущему.

Когда я окунулся в Ассемблер во время одного из моих программирование туриста посещений, ошибка, которая задерживала меня в каждом уроке, заключалась в невозможности скомпилировать в правильный двоичный формат.Большинство учебных пособий дают elf (для Linux) и aoutb (для BSD), но в последнем случае (логический выбор?) OS X жалуется:

ld: hello.o bad magic number (not a Mach-O file)

еще Mach-O не подходит как формат, и если вы man nasm ты получишь только bin, aout и elf форматы файлов - man ld больше не поможет - macho есть возможность сделать формат Mach-O для OS X:

nasm -f macho hello.asm

я описал путешествие здесь (включает ссылку на хороший пакет TextMate для сборки и другую информацию), но, если быть кратким, вышеизложенное — это то, что вам нужно для начала.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top