Меня смущает машинный код и собственный код в контексте языков .NET.
В чем разница между ними? Они одинаковы?
.net
assembly
bytecode
machine-code
Samaladeepak
источник
источник
Ответы:
Эти термины действительно немного сбивают с толку, потому что иногда они используются непоследовательно.
Машинный код: это наиболее четко определенный. Это код, который использует инструкции байт-кода, которые ваш процессор (физический кусок металла, который выполняет фактическую работу) понимает и выполняет напрямую. Весь другой код должен быть переведен или преобразован в машинный код, прежде чем ваша машина сможет его выполнить.
Собственный код: этот термин иногда используется в тех местах, где имеется в виду машинный код (см. Выше). Однако иногда это слово также используется для обозначения неуправляемого кода (см. Ниже).
Неуправляемый код и управляемый код. Неуправляемый код - это код, написанный на языке программирования, таком как C или C ++, который компилируется непосредственно в машинный код . Он контрастирует с управляемым кодом , который написан на C #, VB.NET, Java или аналогичных языках и выполняется в виртуальной среде (такой как .NET или JavaVM), которая своего рода «имитирует» процессор в программном обеспечении. Основное отличие состоит в том, что управляемый код «управляет» ресурсами (в основном выделением памяти) за вас, используя сборку мусора и сохраняя ссылки на объекты непрозрачными. Неуправляемый код- это тип кода, который требует от вас вручную выделять и освобождать память, что иногда вызывает утечки памяти (когда вы забываете освободить память), а иногда и ошибки сегментации (когда вы освобождаете память слишком рано). Неуправляемый также обычно подразумевает отсутствие проверок времени выполнения на наличие распространенных ошибок, таких как разыменование нулевого указателя или переполнение границ массива.
Строго говоря, большинство языков с динамической типизацией, таких как Perl, Python, PHP и Ruby, также являются управляемым кодом . Однако они обычно не описываются как таковые, что показывает, что управляемый код на самом деле является своего рода маркетинговым термином для действительно больших, серьезных коммерческих сред программирования (.NET и Java).
Ассемблерный код: этот термин обычно относится к типу исходного кода, который люди пишут, когда они действительно хотят написать байт-код. Ассемблер это программа , которая превращает этот исходный код в реальном байт-кода. Это не компилятор, потому что преобразование - 1-к-1. Однако термин неоднозначен относительно того, какой тип байт-кода используется: он может быть управляемым или неуправляемым. Если он неуправляемый, результирующий байт-код является машинным кодом . Если им управлять, это приводит к тому, что байт-код используется негласно виртуальной средой, такой как .NET. Управляемый код (например, C #, Java) компилируется в этот специальный язык байт-кода, который в случае .NET называется Common Intermediate Language (CIL), а в Java - байт-кодом Java.. Обычному программисту обычно не нужно иметь доступ к этому коду или писать на этом языке напрямую, но когда люди это делают, они часто называют его кодом ассемблера, потому что они используют ассемблер для преобразования его в байт-код.
источник
То, что вы видите, когда используете Debug + Windows + Disassembly при отладке программы на C #, является хорошим руководством для этих терминов. Вот его аннотированная версия, когда я компилирую программу hello world, написанную на C #, в конфигурации Release с включенной оптимизацией JIT:
Щелкните окно правой кнопкой мыши и установите флажок «Показать байты кода», чтобы получить аналогичное отображение.
Столбец слева - это адрес машинного кода. Его значение подделывается отладчиком, код фактически находится где-то в другом месте. Но это может быть где угодно, в зависимости от местоположения, выбранного JIT-компилятором, поэтому отладчик просто начинает нумерацию адресов с 0 в начале метода.
Второй столбец - это машинный код . Фактические единицы и нули, которые выполняет ЦП. Машинный код, как и здесь, обычно отображается в шестнадцатеричном формате. Показательным, возможно, является то, что 0x8B выбирает команду MOV, дополнительные байты нужны для того, чтобы точно сказать ЦП, что нужно переместить. Также обратите внимание на две разновидности инструкции CALL: 0xE8 - это прямой вызов, 0xFF - это инструкция косвенного вызова.
Третий столбец - это код сборки. . Ассемблер - это простой язык, призванный упростить написание машинного кода. Это можно сравнить с компиляцией C # в IL. Компилятор, используемый для перевода ассемблерного кода, называется «ассемблер». У вас, вероятно, есть ассемблер Microsoft на вашем компьютере, его исполняемое имя - ml.exe, ml64.exe для 64-битной версии. Используются две распространенные версии языков ассемблера. Вы видите тот, который используют Intel и AMD. В мире открытого исходного кода сборка в нотации AT&T является обычным явлением. Синтаксис языка сильно зависит от типа процессора, для которого он был написан, язык ассемблера для PowerPC сильно отличается.
Хорошо, это касается двух терминов в вашем вопросе. «Собственный код» - это нечеткий термин, он нередко используется для описания кода на неуправляемом языке. Возможно, поучительно посмотреть, какой машинный код генерирует компилятор C. Это версия hello world на C:
Я не аннотировал его, в основном потому, что он очень похож на машинный код, сгенерированный программой C #. Вызов функции printf () сильно отличается от вызова Console.WriteLine (), но все остальное примерно то же самое. Также обратите внимание, что отладчик теперь генерирует реальный адрес машинного кода и что он немного умнее относится к символам. Побочный эффект генерации отладочной информации после генерации машинного кода, как часто делают неуправляемые компиляторы. Я также должен упомянуть, что я отключил несколько параметров оптимизации машинного кода, чтобы машинный код выглядел похожим. Компиляторы C / C ++ имеют намного больше времени для оптимизации кода, результат часто трудно интерпретировать. И очень сложно отлаживать.
Ключевым моментом здесь является то, что между машинным кодом, сгенерированным из управляемого языка JIT-компилятором, и машинным кодом, сгенерированным компилятором собственного кода , очень мало различий. Это основная причина, по которой язык C # может конкурировать с компилятором нативного кода. Единственная реальная разница между ними - вызовы функций поддержки. Многие из них реализованы в CLR. И это в первую очередь вращается вокруг сборщика мусора.
источник
Собственный код и машинный код - это одно и то же - фактические байты, которые выполняет ЦП.
Ассемблерный код имеет два значения: одно - это машинный код, переведенный в более удобочитаемую форму (с байтами для инструкций, переведенными в короткие словесные мнемоники, такие как «JMP» (который «перескакивает» в другое место в коде). - это байт-код IL (байты команд, которые генерируются компиляторами, такими как C # или VB, которые в конечном итоге будут переведены в машинный код, но еще не переведены), который находится в DLL или EXE.
источник
В .NET сборки содержат код промежуточного языка MS (MSIL, иногда CIL).
Это похоже на машинный код «высокого уровня».
При загрузке MSIL компилируется JIT-компилятором в собственный код (машинный код Intel x86 или x64).
источник