Вопрос по сборке и компьютерным программам

Я прочитал эту статью: 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 ответа

Решение

Итак, компьютерные программы / исполняемые файлы - это просто двоичные данные (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.

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

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

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

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

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

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

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

ДА.

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

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

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

ДА

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

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

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

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

Другие вопросы по тегам