Почему существует разница между ассемблерами, такими как Windows, Linux?
Я относительно новичок во всем этом низкоуровневом материале, ассемблере.. и хочу узнать более подробно. Почему существует разница между Linux, Windows Assembly languages?
Как я понимаю, когда я компилирую код C, операционная система на самом деле не производит чистый машинный или ассемблерный код, он выдает двоичный код, зависящий от ОС. Но почему?
Например, когда я использую систему x86, CPU понимает только x86 ASM. Правильно ли?. Почему мы не записываем чистый x64-ассемблерный код и почему существуют разные варианты сборки на основе операционной системы? Если бы мы писали чистую ASM или ОС, производящую чистую ASM, не было бы проблем с бинарной совместимостью между операционными системами или нет?
Мне действительно интересно все причины. Любой подробный ответ, статья, книга были бы замечательными. Спасибо.
Ответы
Ответ 1
Нет никакой разницы. Код сборки тот же, если процессор тот же. Код x86, скомпилированный в Windows, двоично совместим с кодом x86 в Linux. Компилятор не создает двоичный код, зависящий от ОС, но он может упаковывать код в другом формате (например, PE или ELF).
Разница в том, какие библиотеки используются. Чтобы использовать материал ОС (например, I/O), вы должны ссылаться на библиотеки операционной системы. Неудивительно, что системные библиотеки Windows недоступны на машине Linux (если только у вас нет Wine) и наоборот.
Ответ 2
В дополнение к другим ответам.
ОС диктует свой Application Binary Interface (ABI), который включает в себя формат исполняемых объектов. Это Исполняемый и связанный формат (ELF) для Linux (и многих других Unix-подобных систем) и Portable Executable (PE) в Windows. См. эту таблицу для других форматов.
Ответ 3
Хорошо, вы не выполняете прямую сборку. Код должен быть в каком-то исполняемом формате: окна используют PE, большинство Unices теперь используют ELF (хотя были и другие, такие как a.out).
Инструкции базовой сборки одинаковы, а функции, которые вы создаете с ними, одинаковы.
Проблема связана с доступом к другим ресурсам. Процессор действительно хорош в расчете, но не может получить доступ к жесткому диску или распечатать символ на экране или подключиться к телефону Bluetooth. Эти элементы всегда зависят от операционной системы. Они реализованы с точки зрения системных вызовов, когда процессор сигнализирует операционной системе выполнить определенную задачу. Задача номер 17 на linux не обязательно является задачей 17 на окнах; они могут даже не иметь эквивалентов.
Так как большинство библиотек имеют некоторые системные вызовы на самых низких уровнях, вот почему код нельзя просто перекомпилировать в каждом случае.
Ответ 4
Если вы не используете среду разработки встроенной системы, вы компилируете ее с компиляторами, предназначенными для определенной среды выполнения. Эта среда выполнения определяет соглашения об использовании аппаратного обеспечения: передачу аргументов, обработку исключений и т.д. Эти соглашения взаимодействуют с операционной системой или, по крайней мере, с доступными библиотеками времени выполнения, с которыми программа должна связываться.
Ответ 5
Исторически сборка Linux обычно выполняется с использованием синтаксиса AT & T, так как это поддерживает GNU Assembler. Аналогично, ассемблеры Windows имеют тенденцию использовать синтаксис Intel, например, MASM и NASM.
Все ассемблеры x86 производят один и тот же вывод - то есть машинный код x86. И вы можете использовать NASM или GNU Assembler в Linux для программирования под синтаксисом Intel и GNU Assembler в Windows для программирования под синтаксисом AT & T.
Ответ 6
ОС определяет две вещи: (1) соглашение о вызовах, которое определяет, как параметры идут в стеке и поэтому воздействует на код сборки, и (2) библиотеки времени выполнения, которые реализуют общие функции, такие как распределение памяти, ввод/вывод, математика более высокого уровня и т.д.
Итак, пока x+y
компилируется в тот же ассемблерный код под Windows или Linux на процессоре x86, y = sin(x)
будет отличаться из-за другого соглашения о вызовах и другой математической библиотеки.
Кроме того, сам ассемблер зависит от процессора. x86, x86_64, ARM, PowerPC, каждый из которых имеет свой собственный язык ассемблера.
Ответ 7
Там нет различий в языках ассемблера (хотя могут быть различия между сборщиками и, следовательно, используемые обозначения), если мы придерживаемся x86. И Linux, и Microsoft Windows работают на других архитектурах, более того, в случае Linux.
Однако операционная система в настоящее время не просто загружает программу в память и позволяет ей работать. Он предоставляет большой объем услуг. Поскольку он также защищает программы друг от друга, он налагает ограничения. Чтобы делать что-либо, кроме базовых вычислений, обычно необходимо пройти через операционную систему. (Это было менее верно для более старых операционных систем, таких как MS-DOS и CP/M, которые могли загружать программы, которые запускались независимо, но в настоящее время почти вся не встроенная система имеет современную ОС.)
Кроме того, программы хранятся как простые двоичные капли. Обычно необходимо связываться с другими библиотеками, часто по мере загрузки программы для выполнения (например, как работают DLL), и необходимо связать с ОС. Там может быть другая информация, требуемая ОС, и поэтому в исполняемом файле должна быть какая-то информация о двоичном блобе. Это зависит от ОС.
Поэтому исполняемые файлы должны быть в формате, который должен быть загружен в память, и это зависит от ОС и ОС. Чтобы сделать что-нибудь полезное, они должны делать вызовы ОС, которые различаются между системами. Вот почему вы не можете использовать исполняемые и связанные с ним библиотеки Windows и запускать их в Linux.
Ответ 8
Существует несколько сборщиков для различных платформ, которые, с учетом исходного файла, будут создавать выходной двоичный файл, который предназначен для загрузки по определенному адресу. Такие ассемблеры были популярны для небольших микроконтроллеров или для некоторых исторических процессоров, таких как 6502 и Z80. При сборке программы необходимо знать адрес, в котором он должен был находиться; использование другого адреса потребует повторной сборки программы. С другой стороны, сборка в такой системе была одношаговым процессом. Запустите ассемблер в исходном коде и получите исполняемый файл. В некоторых случаях можно было бы одновременно иметь исходный код, ассемблер и выводить все в памяти (на моем Commodore 64 я использовал ассемблер, который был опубликован в журнале Compute Gazette, который работал так).
Несмотря на то, что все, что было связано с его изменением адреса, могло быть использовано для любой программы, которая "возьмет на себя машину", во многих случаях желательно использовать многоэтапный процесс, в котором исходные файлы обрабатываются в файлы объектного кода, которые содержат собранные инструкции, но также содержат различные виды "символической" информации о них; эти файлы затем обрабатываются различными способами, чтобы либо получить образ памяти, который может быть загружен непосредственно в память, либо объединенный перемещаемый файл объекта, который загрузчик операционной системы будет знать, как настроить любой адрес, на который он может быть загружен.
Для того, чтобы система привязки объектов была полезна, она должна позволить отложить определенные виды вычислений адресов до тех пор, пока программа не будет связана или не будет загружена. Некоторые системы позволяют выполнять исключительно простые вычисления в момент времени соединения/загрузки, в то время как другие допускают более сложные вычисления. Более простые схемы могут быть более эффективными, когда они работоспособны, но их ограничения могут вызвать обходные пути. В качестве примера, подпрограмма, которая будет использовать BX для циклического преобразования структуры данных с размером менее 256 байтов, может быть написана как нечто вроде:
mov bx,StartAddr
LP: mov al, [bx] ... сделать некоторые вычисления inc bx cmp bl, < (StartAddr + Length); < префикс оператора означает "LSB of" jnz lp
Можно было бы использовать cmp bx,(StartAddr+Length)
, но если инструменты компиляции могут его поддерживать, сравнение только младшего байта будет быстрее. С другой стороны, некоторые виды 16-разрядных средств сборки/компоновки могут потребовать, чтобы все исправления адресов выполнялись с 16-разрядными адресами, хранящимися в коде.
Поскольку разные системы допускают разные функции в своих форматах объектных кодов, для их управления требуются разные функции на своих языках ассемблера. Наборы инструкций могут быть указаны производителем чипов, но функции для выражения перемещаемых вычислений адресов обычно отсутствуют.
Ответ 9
Язык ассемблера связан с архитектурой ЦП, а не с O.S., но O.S. имеют серию системных функций, скомпилированных в двоичном формате, которые может вызывать ваша программа сборки, путем вызова прерывания. Например, стандартный входной выход, операция ecc....