Что происходит, когда ассемблерный код переводится в код объекта?

463
Panther Coder

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

Что беспокоит меня, так это последствия этой стадии (я знаю о промежуточной стадии связывания).

Я имею в виду, что именно происходит после этого этапа? Скажем, последний исполняемый файл - это необработанный двоичный файл. Означает ли это, что код операции f8преобразуется в двоичные данные 1111 1000и сохраняется в файле?

Если это так, то почему я не могу просмотреть двоичное содержимое двоичного файла с помощью обычного текстового редактора (например, «Блокнот») - в конце концов, это «0» и «1» правильно?

1
* «Я знаю о промежуточной стадии связывания» * - Неправильно, стадия связывания будет * после * сборки. * «Что именно происходит после этого этапа» * - Зависит от того, создает ли сборка перемещаемый объектный код (который может быть связан с другими объектными файлами) или абсолютный объектный код. * «в конце концов, это« 0 »и« 1 справа »* - Да, но текстовый редактор всегда обрабатывает эти двоичные данные как коды для текста (например, ASCII), тогда как ** дизассемблер ** будет обрабатывать данные как машинный код, и отображать коды операций и операнды. sawdust 7 лет назад 0
Вам не хватает ключевого момента, `f8` не нужно" конвертировать ", это уже * * * 1111 1000`, это просто разные представления одной и той же вещи. Один показан как шестнадцатеричный, другой как двоичный. Преимущество шестнадцатеричного кода заключается в том, что он немного более удобочитаем для человека и обладает аккуратным побочным эффектом разделения двоичных четырехугольников на однозначные числа, в данном случае f = 1111 и 8 = 1000. Основной единицей измерения, используемой ЦП, являются двоичные цифры, но люди склонны используйте шестнадцатеричные представления. Mokubai 7 лет назад 1

1 ответ на вопрос

2
Alex

Во-первых, всегда используйте правильный инструмент для работы. Текстовый редактор для просмотра бинарных файлов такой же, как использовать нож для гвоздя. Используйте любой HEX viewer / редактор для таких задач или лучше используйте инструмент, который знает внутренности рассматриваемого двоичного файла. Если мы говорим о кодах операций процессора, то что-то вроде IDA Pro free или OllyDbg будет полезно для анализа внутренних компонентов исполняемых файлов.

Означает ли это, что код операции f8преобразуется в двоичные данные 1111 1000и сохраняется в файле?

Как правильно указал @Mokubai - 0xF8это тот же номер, что 1111 1000и один, представленный в шестнадцатеричной записи, и последний как двоичное представление. Это то же самое, что число 248 в десятичной системе.

Если вы создаете исполняемый вручную код из кодов операций ЦП (или компилируете исходный код на ассемблере), то ЦП i386 распознает 0xF8( 0b11111000или 248 - все то же самое) как CLCинструкцию.

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

Это правда, кроме - "Код сборки, сгенерированный компилятором". Я просто хочу убедиться, что вы правильно понимаете разницу между "кодом сборки" и кодами операций. Операционные коды - это точный язык, который процессор может понять, это просто цифры (и именно так мы запрограммировали первые компьютеры, когда трансляторы из мнемоники процессора, то есть ассемблера, были мечтой)

В настоящее время мы в основном используем «прямую» компиляцию из языка программирования высокого уровня напрямую в исполняемые двоичные файлы с такими компиляторами, как C / C ++ / GoLang, которые генерируют коды операций процессора.
(Когда я сказал «прямую компиляцию», это на самом деле не так, когда компиляторы под капотом делают несколько шагов, прежде чем получаются исполняемые двоичные файлы, но для конечного пользователя это выглядит так же, как мы за рулем автомобиля, и не нужно знать, как бензин превращается в движение)

Как правильно упомянул @sawdust в комментарии, языки программирования более высокого уровня могут использовать разные стратегии для создания кодов операций ЦП. Например, вы можете проанализировать gccкомпилятор, как он будет готовить коды операций, сказав ему генерировать код ассемблера, который будет использоваться для создания кодов операций (объектные коды).

 gcc -S -o myprogram.asm myprogram.c 

Если это так, то почему я не могу просмотреть двоичное содержимое двоичного файла с помощью обычного текстового редактора (например, «Блокнот») - в конце концов, это «0» и «1» правильно?

Блокнот говорят на другом языке. Он понимает свои собственные «коды операций» - ASCII, все остальное, что он «греческий» для Блокнота.

* «Такие компиляторы, как C / C ++ / GoLang, не создают« ассемблерный код », а генерируют коды операций напрямую», - возможно, вы можете придумать исключение, но в целом это не так. Я использовал по крайней мере три компилятора Си и все три сгенерированных исходных кода сборки перед генерацией объектного кода. Я знаю это, потому что я должен был сообщить об ошибках оптимизации компилятора и использовал вывод ассемблера, чтобы доказать, что компилятор генерировал плохой код из C. sawdust 7 лет назад 1
Вы вводите в заблуждение OP, соглашаясь с тем, что `f8` конвертируется в двоичный файл. Никакого фактического преобразования не происходит вообще, и это не нужно, это просто разные представления одной и той же вещи. `f8` - просто более удобочитаемое представление` 1111 1000`. Mokubai 7 лет назад 0
@Mokubai Нет, я не сказал, что 'f8' -> двоичный файл, я сказал `clc` мнемонический ->` f8`, который является `11111000`. `f8` и` 11111000` - это просто разные представления одного и того же числа Alex 7 лет назад 0
@sawdust Вы правы, я имел в виду `gcc -o binexe source.c`. Я собираюсь исправить свой ответ Alex 7 лет назад 0
Он задает конкретный вопрос, который вы процитировали, а затем ответили утвердительно, а затем уточнили. Я не оспариваю правильность следующего предложения, только то, что прямое «да» в качестве первой части вашего предложения, отвечая на его вопрос, может создать у него впечатление, что его предположение было верным и что происходит какой-то дополнительный шаг обращения , Удаление «да» будет достаточно. Mokubai 7 лет назад 0
@Mokubai Ооо, теперь я понимаю, что ты имеешь в виду. Спасибо за помощь ! Alex 7 лет назад 0
* «это то, как мы программировали ** первые компьютеры **, когда компиляторы из мнемоники ЦП, или ассемблера, были мечтой» * - Вы претендуете на то, что стары (что использовали UNIVAC) ?? !! Компиляторы не являются ассемблерами, и их следует объединять. Я сомневаюсь, что ты программировал дольше меня (то есть с 1967 года). Какой компьютер вы использовали, у которого не было ассемблера? FWIW я написал в машинном коде, но только для патчей к прошивке. sawdust 7 лет назад 0
@sawdust UNIVAC, как компьютер, это то, что мы запрограммировали на бумажных карточках в университете, но меня это не коснулось. Моя страсть к компьютерному миру началась с Intel 8080 на специальном «компьютере», который был сконструирован и изготовлен из сотен SN74LS74, SN74LS00 ... несовместимых с остальным миром, где «операционная система» помещается в 8 КБ EPROM. Вы можете вообразить, насколько «забавно» было программировать первые версии этого компьютера, набрав коды аппаратного обеспечения программиста и записав его в EPROM. Позже мы написали ассемблер для этого компа, и это был один из самых счастливых моментов в моей жизни :) Alex 7 лет назад 0
@sawdust Вы правы относительно правильного термина в отношении ассемблера, я его исправил, компиляторы -> переводчики. Я вероятно должен избегать длинных объяснений с моим английским языком. Я ценю, что вы помогли мне исправить мой ответ. Alex 7 лет назад 0
Я почти уверен, что у Intel был ассемблер; Вы просто должны были заплатить за это. Но у вас, вероятно, не было периферийных устройств, чтобы использовать его в любом случае. sawdust 7 лет назад 0
* «Мы в основном используем прямую компиляцию из языка программирования высокого уровня напрямую в исполняемые двоичные файлы с компиляторами» * - Это все еще ложное утверждение. Тот факт, что компилятор имеет промежуточные этапы (например, создание языка ассемблера из HLL), которые не видны, не означает, что существует прямая генерация кода. Вы также игнорируете шаг связывания. Типичный исполняемый файл, на который ссылается OP, - это не двоичный образ, а, вероятно, перемещаемый исполняемый файл, который требует динамического связывания с общими библиотеками. sawdust 7 лет назад 0
@sawdust Я не думаю, что нам нужно начинать с глубоких объяснений - «Как работают компиляторы», когда вопрос - «Почему коды операций не видны в Блокноте», но я действительно ценю ваши комментарии, которые помогли улучшить мой пост ! Я добавил пояснения по поводу "прямой компиляции". Alex 7 лет назад 0