Вопрос по сборке и компьютерным программам - PullRequest
4 голосов
/ 14 августа 2011

Я прочитал эту статью: http://en.wikipedia.org/wiki/Assembly_language

Там написано:

Взять, к примеру, инструкцию, которая сообщает процессору x86 / IA-32 переместить немедленное 8-битное значение в регистр. Двоичный код для эта инструкция - 10110, за которой следует 3-битный идентификатор, для которого Зарегистрируйтесь, чтобы использовать. Идентификатор для регистра AL равен 000, поэтому следующий машинный код загружает регистр AL с данными 01100001. [4]

10110000 01100001

Это объясняет, как это проще написать как:

MOV AL, 61h       ; Load AL with 97 decimal (61 hex)

Теперь вот мои вопросы.

Итак, компьютерные программы / исполняемые файлы - это просто двоичные данные (0 и 1)?

При просмотре с помощью дизассемблера, такого как OllyDbg, он просто пытается вернуть эти 0 и 1 обратно на некоторый язык ассемблера (Intel?), И вывод в основном правильный?

Если у меня есть эта 10110000 01100001 программа на моем SSD, и я пишу приложение C # / PHP / wtvr, которое читает содержимое файла и выводит их в виде битов, я увижу эти точные 10110000 01100001 цифры?

Как операционная система выполняет "выполнение"? Как это говорит процессору, что «эй, возьми эти биты и запусти их»? Могу ли я сделать это в C # / C ++ напрямую?

Ответы [ 3 ]

2 голосов
/ 14 августа 2011

Итак, компьютерные программы / исполняемые файлы - это просто двоичные данные (0 и 1)?

Да, как изображения, видео и другие данные.

При просмотре с помощью дизассемблера, такого как OllyDbg, он просто пытается вернуть эти 0 и 1 обратно на некоторый язык ассемблера (Intel?), И вывод в основном правильный?

Да, в этом конкретном случае оно всегда будет правильным, поскольку mov al, 61h всегда собирается в 0xB0 0x61 Руководства разработчика программного обеспечения для архитектуры Intel 64 и IA-32 и в других местах, обычно записываемых как B0 61) в 16-, 32- и 64-битном режиме. Обратите внимание, что 0xB0 0x61 = 0b10110000 0b01100001.

Вы можете найти кодировку для различных инструкций в Томе 2А. Например, здесь это «B0 + rb MOV r8, imm8 E Valid Valid Переместить imm8 в r8». на стр. 3-644.

Другие инструкции имеют разные значения, в зависимости от того, интерпретируются они в 16/32 или 64-битном режиме. Рассмотрим эту короткую последовательность байтов: 66 83 C0 04 41 80 C0 05

В 16-битном режиме они означают:

00000000  6683C004          add eax,byte +0x4
00000004  41                inc cx
00000005  80C005            add al,0x5

В 32-битном режиме они означают:

00000000  6683C004          add ax,byte +0x4
00000004  41                inc ecx
00000005  80C005            add al,0x5

И, наконец, в 64-битном режиме:

00000000  6683C004          add ax,byte +0x4
00000004  4180C005          add r8b,0x5

Таким образом, инструкции не всегда можно правильно разобрать, не зная контекста (это даже не принимая во внимание то, что в текстовом сегменте могут находиться другие вещи, кроме кода, а код может выполнять такие неприятные вещи, как генерация кода на лету или самообучение. изменить).

Если у меня есть эта программа 10110000 01100001 на моем SSD и я пишу приложение C # / PHP / wtvr, которое читает содержимое файла и выводит их в виде битов, я увижу эти точные цифры 10110000 01100001?

Да, в том смысле, что если приложение содержит инструкцию mov al, 61h, файл будет содержать байты 0xB0 и 0x61.

Как операционная система выполняет "выполнение"? Как это говорит процессору, что «эй, возьми эти биты и запусти их»? Могу ли я сделать это в C # / C ++ напрямую?

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

Первый процессор также отвечает за пробуждение других ядер / процессоров на многоядерном / многопроцессорном компьютере. См. этот ТАК вопрос.

Для вызова кода, который вы загружаете непосредственно в C ++ (я не думаю, что это возможно в C # без использования небезопасного / нативного кода), требуются специфические для платформы приемы. Для Windows вы, вероятно, захотите взглянуть на VirtualProtect и на linux mprotect(2). Или, возможно, более реалистично из файла, который отображается с помощью этого процесса для Windows или mmap(2) для Linux.

1 голос
/ 14 августа 2011

Итак, компьютерные программы / исполняемые файлы - это просто двоичные данные (0 и 1)?

YES.

При просмотре с помощью дизассемблера, такого как OllyDbg, он просто пытается вернуться те 0 и 1 вернулись к некоторому языку ассемблера (Intel?) и тому вывод в основном правильный?

ДА. За исключением того, что если двоичные данные представляют код для процессора, для которого предназначен дизассемблер, выходные данные будут полностью правильными, а не просто «в основном» правильными.

Если у меня есть эта программа 10110000 01100001 на моем SSD, и я пишу Приложение C # / PHP / wtvr, которое читает содержимое файла и выводит как биты, увижу ли я эти точные цифры 10110000 01100001?

YES

Как операционная система выполняет фактическое "выполнение"? Как это скажите процессору, что "эй, возьми эти биты и запусти их"?

Операционная система - это просто программа, как и любая другая, это инструкции, выполняемые на процессоре. Упрощенно, когда операционная система выполняет код, все, что она делает, - это переходит на начальный адрес того места, где находится код, и, следовательно, процессор теперь начинает выполнять любой код, находящийся в этом месте.

Могу ли я сделать это в C # / C ++ напрямую?

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

1 голос
/ 14 августа 2011

это много вопросов:

Да, компьютерные программы / исполняемые файлы - это просто двоичные данные 0 / 1с.

Да, дизассемблер пытается разобраться в 0 / 1с ... и использует дополнительные знания о формате файла (EXE обычно соответствует спецификации PE, COM - другая спецификация и т. Д.) И ОС, которую предполагается использовать в двоичном файле запустить и API доступны и т. д.

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

Обычно ОС загружает файл и обрабатывает его содержимое в соответствии со спецификацией - например, переупорядочивает некоторые области памяти и т. Д. Затем он помечает области памяти, которые содержат исполняемый код как исполняемый, и выполняет JMP или CALL по адресу первой инструкции так называемой точки входа (опять же, это зависит от формата / спецификации файла).

В C # вы имеете дело не со сборкой как с языком, а с «байт-кодом» (инструкциями IL) ... вы можете создавать или загружать их с помощью методов Framework и т. Д. В c ++ вы могли бы иметь дело непосредственно со сборкой, если вы действительно этого хотите, но она не переносима и может усложниться ... поэтому вы обычно делаете это только тогда, когда выигрыш действительно того стоит (например, необходимое повышение производительности в 10 раз). 1011 *

...