В чем разница между собственным кодом, машинным кодом и кодом сборки? - PullRequest
92 голосов
/ 08 августа 2010

Я запутался в машинном коде и нативном коде в контексте языков .NET.

В чем разница между ними?Они одинаковые?

Ответы [ 4 ]

138 голосов
/ 08 августа 2010

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

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

Собственный код: Этот термин иногда используется в местах, где подразумевается машинный код (см. Выше). Однако иногда оно также означает неуправляемый код (см. Ниже).

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

43 голосов
/ 08 августа 2010

То, что вы видите, когда используете Debug + Windows + Разборка при отладке программы на C #, является хорошим руководством для этих условий.Вот его аннотированная версия, когда я компилирую программу «hello world», написанную на C #, в конфигурации выпуска с включенной оптимизацией JIT:

        static void Main(string[] args) {
            Console.WriteLine("Hello world");
00000000 55                push        ebp                           ; save stack frame pointer
00000001 8B EC             mov         ebp,esp                       ; setup current frame
00000003 E8 30 BE 03 6F    call        6F03BE38                      ; Console.Out property getter
00000008 8B C8             mov         ecx,eax                       ; setup "this"
0000000a 8B 15 88 20 BD 02 mov         edx,dword ptr ds:[02BD2088h]  ; arg = "Hello world"
00000010 8B 01             mov         eax,dword ptr [ecx]           ; TextWriter reference
00000012 FF 90 D8 00 00 00 call        dword ptr [eax+000000D8h]     ; TextWriter.WriteLine()
00000018 5D                pop         ebp                           ; restore stack frame pointer
        }
00000019 C3                ret                                       ; done, return

Щелкните правой кнопкой мыши в окне и отметьте «Показать байты кода», чтобыполучить аналогичный дисплей.

В столбце слева указан адрес машинного кода.Его значение подделывается отладчиком, код фактически находится где-то еще.Но это может быть где угодно, в зависимости от местоположения, выбранного компилятором JIT, поэтому отладчик просто начинает нумерацию адресов с 0 в начале метода.

Второй столбец - машинный код .Фактические 1 и 0, которые выполняет ЦП.Машинный код, как здесь, обычно отображается в шестнадцатеричном виде.Возможно, показательно, что 0x8B выбирает инструкцию MOV, дополнительные байты предназначены для того, чтобы точно указать процессору, что нужно переместить.Также обратите внимание на две разновидности инструкции CALL: 0xE8 - это прямой вызов, 0xFF - это команда косвенного вызова.

Третий столбец - это код сборки .Сборка - это простой язык, разработанный для облегчения написания машинного кода.Это сравнивается с C #, компилируемым в IL.Компилятор, используемый для перевода ассемблерного кода, называется «ассемблер».Возможно, на вашей машине установлен ассемблер Microsoft, его исполняемый файл называется ml.exe, ml64.exe для 64-битной версии.Существует две распространенные версии языков ассемблера.То, что вы видите, это то, что Intel и AMD используют.В мире открытого исходного кода сборка в нотации AT & T распространена.Синтаксис языка сильно зависит от типа процессора, для которого он был написан, язык ассемблера для PowerPC очень отличается.

Хорошо, это касается двух терминов в вашем вопросе.«Нативный код» - это нечеткий термин, он нередко используется для описания кода на неуправляемом языке.Возможно, поучительно посмотреть, какой машинный код генерируется компилятором Си.Это версия 'hello world' на C:

int _tmain(int argc, _TCHAR* argv[])
{
00401010 55               push        ebp  
00401011 8B EC            mov         ebp,esp 
    printf("Hello world");
00401013 68 6C 6C 45 00   push        offset ___xt_z+128h (456C6Ch) 
00401018 E8 13 00 00 00   call        printf (401030h) 
0040101D 83 C4 04         add         esp,4 
    return 0;
00401020 33 C0            xor         eax,eax 
}
00401022 5D               pop         ebp  
00401023 C3               ret   

Я не аннотировал ее, в основном потому, что она очень похожа на машинный код, сгенерированный программой C #.Вызов функции printf () сильно отличается от вызова Console.WriteLine (), но все остальное примерно одинаково.Также обратите внимание, что отладчик теперь генерирует адрес реального машинного кода и что он немного умнее с символами.Побочный эффект генерации отладочной информации после генерации машинного кода, как это часто делают неуправляемые компиляторы.Следует также упомянуть, что я отключил несколько параметров оптимизации машинного кода, чтобы машинный код выглядел одинаково.Компиляторы C / C ++ имеют гораздо больше времени для оптимизации кода, результат часто трудно интерпретировать.И очень трудно отлаживать.

Ключевым моментом здесь является то, что очень мало различий между машинным кодом, сгенерированным из управляемого языка компилятором JIT, и машинным кодом, сгенерированнымкомпилятор нативного кода.Что является основной причиной, по которой язык C # может конкурировать с компилятором нативного кода.Единственная реальная разница между ними - вызовы функций поддержки.Многие из которых реализованы в CLR.И это вращается вокруг сборщика мусора.

5 голосов
/ 08 августа 2010

Собственный код и машинный код - это одно и то же - фактические байты, которые выполняет ЦП.

Код сборки имеет два значения: одно - это машинный код, переведенный в более читабельную форму (сбайты для инструкций, переведенных в короткую словесную мнемонику, такую ​​как «JMP» (которая «перепрыгивает» в другое место в коде). Другой - байт-код IL (байты инструкций, которые генерируют компиляторы, такие как C # или VB, которые в конечном итоге будут переведены в машинукод, в конце концов, но еще не), который живет в DLL или EXE.

2 голосов
/ 08 августа 2010

В .NET сборки содержат MS Intermediate Language код (MSIL, иногда CIL).
Это похоже на машинный код высокого уровня.

При загрузке MSILкомпилируется JIT-компилятором в собственный код (машинный код Intel x86 или x64).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...