Почему существует разница между языками ассемблера, такими как Windows, Linux? - PullRequest
18 голосов
/ 05 января 2011

Я относительно новичок во всех этих низкоуровневых вещах, на ассемблере ... и хочу выучить более подробно. Почему существует разница между Linux и языками сборки Windows?

Как я понимаю, когда я компилирую код на C Операционная система на самом деле не производит чистый машинный или ассемблерный код, она производит двоичный код, зависящий от ОС. Но почему?

Например, когда я использую систему x86, процессор понимает только ASM x86, я прав? Так почему мы не пишем чистый код сборки x86 и почему существуют разные варианты сборки в зависимости от операционной системы? Если бы мы писали чистый ASM или ОС производили чистый ASM, не было бы проблем совместимости двоичных файлов между операционными системами или нет?

Мне действительно интересно все причины, стоящие за ними. Любой подробный ответ, статья, книга были бы отличными. Спасибо.

Ответы [ 9 ]

22 голосов
/ 05 января 2011

Разницы нет.Код сборки одинаков, если процессор одинаков.Код x86, скомпилированный в Windows, двоично совместим с кодом x86 в Linux.Компилятор не создает OS-зависимый двоичный код, но он может упаковать код в другой формат (например, PE против ELF).

Разница в том, какие библиотеки используются.Чтобы использовать содержимое операционной системы (например, ввод-вывод), вы должны создать ссылку на библиотеки операционной системы.Неудивительно, что системные библиотеки Windows недоступны на компьютере с Linux (если, конечно, у вас нет Wine) и наоборот.

7 голосов
/ 05 января 2011

Ну, вы не запускаете прямую сборку.Код должен быть в каком-то исполняемом формате: Windows использует PE, большинство Unices сейчас используют ELF (хотя были и другие, например, a.out).

Базовые инструкции по сборке те же, ифункции, которые вы создаете с их помощью, одинаковы.

Проблема связана с доступом к другим ресурсам.Процессор действительно хорош в вычислениях, но не может получить доступ к жесткому диску, распечатать символ на экране или подключиться к телефону Bluetooth.Эти элементы всегда так или иначе зависят от операционной системы.Они реализованы в виде системных вызовов, когда процессор сигнализирует операционной системе о выполнении определенной задачи.Задача № 17 в Linux не обязательно является задачей 17 в Windows;они могут даже не иметь эквивалентов.

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

5 голосов
/ 05 января 2011

В дополнение к другим ответам.

ОС диктует свой двоичный интерфейс приложения (ABI), который включает в себя формат исполняемых объектов. Это Исполняемый и связываемый формат (ELF) для Linux (и многих других Unix-подобных систем) и Переносимый исполняемый файл (PE) в Windows. См. в этой таблице для других форматов.

3 голосов
/ 05 января 2011

Исторически сборка Linux обычно выполняется с использованием синтаксиса AT & T, поскольку это то, что поддерживает GNU Assembler .Аналогично, ассемблеры Windows, как правило, используют синтаксис Intel, как с MASM и NASM .

Все ассемблеры x86 выдают одинаковый вывод, то есть машинный код x86,Кроме того, вы можете использовать NASM или GNU Assembler для Linux для программирования под синтаксисом Intel, а GNU Assembler для Windows - для программирования под синтаксисом AT & T.

3 голосов
/ 05 января 2011

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

1 голос
/ 28 января 2017

Язык ассемблера связан с архитектурой процессора не с O.S., а с O.S. иметь ряд системных функций, скомпилированных в двоичном формате, которые ваша ассемблерная программа может вызывать путем вызова прерывания. Например, стандартный ввод-вывод, операция ecc ....

1 голос
/ 04 июля 2014

Существует несколько ассемблеров для различных платформ, которые, учитывая исходный файл, будут генерировать выходной двоичный файл напрямую, который предназначен для загрузки по определенному адресу. Такие ассемблеры были популярны для некоторых небольших микроконтроллеров или для некоторых исторических процессоров, таких как 6502 и Z80. При сборке программы необходимо знать адрес, где она должна находиться; использование другого адреса потребовало бы повторной сборки программы. С другой стороны, сборка в такой системе была одношаговой. Запустите ассемблер для исходного кода и получите исполняемый вывод. В некоторых случаях было бы возможно иметь исходный код, ассемблер и выводить все сразу в память (на моем Commodore 64 я использовал ассемблер, который был опубликован в журнале Compute Gazette, который так работал).

Хотя повторная сборка всего в любое время, когда изменения адреса могут быть полезны для программы, которая «захватит компьютер», во многих случаях желательно использовать многошаговый процесс, где исходные файлы обрабатываются в файлы объектного кода, которые содержат собранные инструкции, но также содержат различную «символическую» информацию о них; эти файлы затем обрабатываются различными способами, чтобы либо получить образ памяти, который может быть загружен непосредственно в память, либо объединенный перемещаемый объектный файл, который загрузчик операционной системы будет знать, как настроить для любого адреса, по которому он может быть загружен .

Чтобы система связывания объектов была полезной, она должна позволять откладывать определенные виды вычислений адресов до тех пор, пока программа не будет связана или загружена. Некоторые системы позволяют выполнять исключительно простые вычисления во время соединения / загрузки, в то время как другие допускают более сложные вычисления. Более простые схемы могут быть более эффективными, когда они работоспособны, но их ограничения могут привести к обходным решениям. Например, подпрограмма, которая будет использовать BX для циклического прохождения структуры данных с длиной менее 256 байтов, может быть записана примерно так:

    mov bx,StartAddr

LP: мов ал, [bx] ... сделать некоторые вычисления inc bx cmp bl, <(StartAddr + Length); <префиксный оператор означает "LSB of" JNZ LP </p>

Можно было бы использовать cmp bx,(StartAddr+Length), но если бы инструменты компиляции могли это поддерживать, сравнение только младшего байта было бы быстрее. С другой стороны, некоторые виды 16-битных инструментов сборки / компоновки могут требовать, чтобы все исправления адресов выполнялись с 16-битными адресами, хранящимися в коде.

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

1 голос
/ 05 января 2011

Нет никакой разницы в языках ассемблера (хотя могут быть различия между ассемблерами и, следовательно, используемыми обозначениями), при условии, что мы придерживаемся x86. И Linux, и Microsoft Windows работают на других архитектурах, особенно в случае Linux.

Тем не менее, операционная система в настоящее время не просто загружает программу в память и отпускает ее. Предоставляет большое количество услуг. Так как он также защищает программы друг от друга, он накладывает ограничения. Чтобы сделать что-то кроме базовых вычислений, обычно необходимо пройти через операционную систему. (Это было менее верно для более старых операционных систем, таких как MS-DOS и CP / M, которые могли загружать программы, которые запускались бы независимо, но в настоящее время в значительной степени каждая не встроенная система имеет современную ОС.)

Также программы не хранятся в виде простых двоичных объектов. Обычно необходимо связать с другими библиотеками, часто, поскольку программа загружается для выполнения (например, так работают библиотеки DLL), и необходимо связываться с ОС. Может быть другая информация, которая требуется ОС, и, следовательно, должна быть какая-то информация о двоичном двоичном объекте в исполняемом файле. Это зависит от операционной системы.

Таким образом, исполняемые файлы должны быть в формате для загрузки в память, и это зависит от ОС к ОС. Чтобы сделать что-нибудь полезное, они должны делать вызовы ОС, которые отличаются между системами. Вот почему вы не можете взять исполняемый файл Windows и связанные библиотеки и запустить его в Linux.

1 голос
/ 05 января 2011

ОС определяет две вещи: (1) соглашение о вызовах , которое определяет, как параметры помещаются в стек и, следовательно, влияет на код сборки, и (2) библиотеки времени выполнения, которые реализуют общие функции например, выделение памяти, ввод / вывод, математика высокого уровня и т. д.

Таким образом, хотя x+y компилируется в один и тот же код сборки под Windows или Linux на процессоре x86, y = sin(x) будет отличаться из-за разного соглашения о вызовах и другой математической библиотеки.

Кроме того, сам язык ассемблера зависит от процессора. x86, x86_64, ARM, PowerPC, каждый имеет свой язык ассемблера.

...