Подтвердить что ты не робот

Как ОС влияет на работу кода сборки?

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

Как работает OS, код которого влияет на то, что делает код, или определить, работает ли код? Могу ли я следовать учебнику на базе Windows и изменить несколько команд, чтобы он работал на Mac с относительной легкостью? В более общем плане, есть ли что-то сложное, что программист Mac-сборки должен знать? Спасибо!

4b9b3361

Ответ 1

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

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

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

Внешний мир

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

Самая важная часть ABI - это то, что конвенция вызова используется для функций стиля C. Они чаще всего поддерживаются, и то, с чем вы, вероятно, будете взаимодействовать, если вы пишете сборку. Agner Fog поддерживает несколько хороших ресурсов на его сайте; особенно полезно подробное описание соглашений о вызовах. В своем ответе Норман Рэмси упоминает ПИК и динамические библиотеки; по моему опыту, вам, как правило, не нужно беспокоиться об этом, если вы этого не хотите. Статическое связывание отлично подходит для типичного использования языка ассемблера (например, для перезаписи основных функций внутреннего контура или другой точки доступа).

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

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

Другое, что ваша программа будет делать, это сделать системные вызовы. Вы можете написать полную и полезную программу сборки, которая никогда не вызовет внешние функции C, но если вы хотите написать чистую ассемблерную программу, которая не передает аутсорсинг Fun Stuff кому-то другому, вам понадобятся системные вызовы. И, к сожалению, системные вызовы полностью и совершенно разные для каждой ОС. Системные вызовы в стиле 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, если вы хотите взаимодействовать с внешним отладчиком (правильно настроенным, удачным!). Ни одна из этих функций не зависит от вашей ОС. Единственное реальное ограничение, которое у вас есть, это то, что вы работаете в Ring 3, а не Ring 0, и поэтому некоторые регистры управления процессором будут недоступны для вас. (Но если вам это нужно, вы пишете код ОС, а не код приложения.) Кроме этого, машина заложена вам: идите и вычислите!

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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