Nie mam pojęcia co do kodu maszynowego i kodu natywnego w kontekście języków .NET.
Jaka jest różnica między nimi? Czy oni są tacy sami?
.net
assembly
bytecode
machine-code
samaladeepak
źródło
źródło
Odpowiedzi:
Terminy są rzeczywiście nieco zagmatwane, ponieważ czasami są używane niekonsekwentnie.
Kod maszynowy: jest to najlepiej zdefiniowany. Jest to kod wykorzystujący instrukcje kodu bajtowego, które Twój procesor (fizyczny kawałek metalu wykonujący rzeczywistą pracę) rozumie i bezpośrednio wykonuje. Cały inny kod musi zostać przetłumaczony lub przekształcony w kod maszynowy, zanim maszyna będzie mogła go wykonać.
Kod macierzysty: ten termin jest czasami używany w miejscach, w których rozumie się kod maszynowy (patrz powyżej). Jednak czasami jest również używany w znaczeniu kodu niezarządzanego (patrz poniżej).
Kod niezarządzany i kod zarządzany: kod niezarządzany odnosi się do kodu napisanego w języku programowania, takim jak C lub C ++, który jest kompilowany bezpośrednio do kodu maszynowego . Kontrastuje to z kodem zarządzanym , który jest napisany w języku C #, VB.NET, Java lub podobnym i wykonywany w środowisku wirtualnym (takim jak .NET lub JavaVM), który rodzaj „symuluje” procesor w oprogramowaniu. Główna różnica polega na tym, że kod zarządzany „zarządza” zasobami (głównie alokacją pamięci) za Ciebie, wykorzystując wyrzucanie elementów bezużytecznych i utrzymując nieprzezroczyste odwołania do obiektów. Kod niezarządzanyjest rodzajem kodu, który wymaga ręcznego przydzielania i cofania alokacji pamięci, czasami powodując wycieki pamięci (gdy zapomnisz o cofnięciu alokacji), a czasami błędy segmentacji (gdy cofasz alokację zbyt wcześnie). Niezarządzane również zwykle oznacza, że nie ma sprawdzania w czasie wykonywania typowych błędów, takich jak wyłuskiwanie wskaźnika null lub przepełnienie granic tablicy.
Ściśle mówiąc, większość języków z typami dynamicznymi - na przykład Perl, Python, PHP i Ruby - jest również kodem zarządzanym . Jednak nie są one powszechnie opisywane jako takie, co pokazuje, że kod zarządzany jest w rzeczywistości terminem marketingowym dla naprawdę dużych, poważnych, komercyjnych środowisk programistycznych (.NET i Java).
Kod asemblerowy: ten termin ogólnie odnosi się do rodzaju kodu źródłowego, który ludzie piszą, kiedy naprawdę chcą pisać kod bajtowy. Assembler to program, który zamienia ten kod źródłowy do kodu bajtowego rzeczywistym. To nie jest kompilator, ponieważ transformacja jest 1 do 1. Jednak termin jest niejednoznaczny, jeśli chodzi o rodzaj używanego kodu bajtowego: może być zarządzany lub niezarządzany. Jeśli nie jest zarządzany, wynikowy kod bajtowy jest kodem maszynowym . Jeśli jest zarządzany, skutkuje to kodem bajtowym używanym za kulisami przez środowisko wirtualne, takie jak .NET. Kod zarządzany (np. C #, Java) jest kompilowany do tego specjalnego języka kodu bajtowego, który w przypadku .NET nazywa się Common Intermediate Language (CIL), aw Javie nazywa się kodem bajtowym Java. Zwykły programista nie ma zwykle potrzeby dostępu do tego kodu lub bezpośredniego pisania w tym języku, ale kiedy ludzie to robią, często nazywają go kodem asemblera, ponieważ używają asemblera do przekształcenia go w kod bajtowy.
źródło
To, co widzisz, gdy używasz Debug + Windows + Demontaż podczas debugowania programu C #, jest dobrym przewodnikiem dla tych warunków. Oto wersja z adnotacjami, gdy kompiluję program „Hello world” napisany w C # w konfiguracji wydania z włączoną optymalizacją JIT:
Kliknij prawym przyciskiem myszy okno i zaznacz opcję „Pokaż bajty kodu”, aby uzyskać podobny widok.
Kolumna po lewej stronie to adres kodu maszynowego. Debugger fałszuje jego wartość, kod faktycznie znajduje się gdzie indziej. Ale może to być gdziekolwiek, w zależności od lokalizacji wybranej przez kompilator JIT, więc debugger zaczyna numerować adresy od 0 na początku metody.
Druga kolumna to kod maszynowy . Rzeczywiste 1 i 0, które wykonuje procesor. Kod maszynowy, jak tutaj, jest zwykle wyświetlany w postaci szesnastkowej. Ilustracją może być to, że 0x8B wybiera instrukcję MOV, dodatkowe bajty są tam, aby powiedzieć procesorowi dokładnie, co ma zostać przeniesione. Zwróć także uwagę na dwa rodzaje instrukcji CALL, 0xE8 to wywołanie bezpośrednie, 0xFF to instrukcja wywołania pośredniego.
Trzecia kolumna to kod zespołu . Asembler to prosty język, zaprojektowany, aby ułatwić pisanie kodu maszynowego. Porównuje się do kompilacji języka C # do IL. Kompilator używany do tłumaczenia kodu asemblera nazywany jest „assemblerem”. Prawdopodobnie masz asembler firmy Microsoft na swoim komputerze, jego nazwa wykonywalna to ml.exe, ml64.exe dla wersji 64-bitowej. W użyciu są dwie popularne wersje języków asemblera. Ten, który widzisz, to ten, którego używają Intel i AMD. W świecie open source asemblacja w notacji AT&T jest powszechna. Składnia języka jest silnie zależna od rodzaju procesora, dla którego został napisany, język asemblera dla PowerPC jest zupełnie inny.
OK, to dotyczy dwóch terminów z twojego pytania. „Kod natywny” jest terminem rozmytym i nierzadko jest używany do opisywania kodu w niezarządzanym języku. Być może pouczające jest sprawdzenie, jaki rodzaj kodu maszynowego jest generowany przez kompilator C. To jest wersja „hello world” w języku C:
Nie dodałem adnotacji, głównie dlatego, że jest tak podobny do kodu maszynowego generowanego przez program C #. Wywołanie funkcji printf () różni się znacznie od wywołania Console.WriteLine (), ale wszystko inne jest mniej więcej takie samo. Należy również zauważyć, że debugger generuje teraz prawdziwy adres kodu maszynowego i że jest nieco mądrzejszy w zakresie symboli. Efekt uboczny generowania informacji debugowania po wygenerowaniu kodu maszynowego, tak jak często robią to niezarządzane kompilatory. Powinienem również wspomnieć, że wyłączyłem kilka opcji optymalizacji kodu maszynowego, aby kod maszynowy wyglądał podobnie. Kompilatory C / C ++ mają dużo więcej czasu na optymalizację kodu, wynik jest często trudny do zinterpretowania. I bardzo trudne do debugowania.
Kluczową kwestią jest to, że istnieje bardzo niewiele różnic między kodem maszynowym wygenerowanym z języka zarządzanego przez kompilator JIT a kodem maszynowym wygenerowanym przez kompilator kodu natywnego. To jest główny powód, dla którego język C # może konkurować z kompilatorem kodu natywnego. Jedyną prawdziwą różnicą między nimi są wywołania funkcji wsparcia. Wiele z nich jest zaimplementowanych w środowisku CLR. A to przede wszystkim kręci się wokół garbage collectora.
źródło
Kod natywny i kod maszynowy to to samo - rzeczywiste bajty wykonywane przez procesor.
Kod asemblera ma dwa znaczenia: jedno to kod maszynowy przetłumaczony na bardziej czytelną dla człowieka formę (z bajtami instrukcji przetłumaczonymi na krótkie, podobne do słów mnemoniki, takie jak „JMP” (które „skaczą” w inne miejsce w kodzie). to kod bajtowy IL (bajty instrukcji generowane przez kompilatory, takie jak C # lub VB, które ostatecznie zostaną przetłumaczone na kod maszynowy, ale jeszcze nie są), który znajduje się w bibliotece DLL lub EXE.
źródło
W .NET zestawy zawierają kod MS Intermediate Language (MSIL, czasami CIL).
To jest jak kod maszynowy „wysokiego poziomu”.
Po załadowaniu MSIL jest kompilowany przez kompilator JIT do kodu natywnego (kod maszynowy Intel x86 lub x64).
źródło