Вопрос по сборке и компьютерным программам
Я прочитал эту статью: 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 компилируется до языка ассемблера, когда он выполняется и в тот момент, когда он выполняется, он ничем не отличается от любой другой программы, которая может работать на данном процессоре. Да, вы можете использовать встроенную сборку, например, чтобы перейти к определенной ячейке памяти и выполнить код.