Kod zestawu a kod maszynowy a kod obiektowy?

227

Jaka jest różnica między kodem obiektowym, kodem maszynowym a kodem asemblera?

Czy możesz podać wizualny przykład ich różnicy?

mmcdole
źródło
Jestem również ciekawy, skąd wzięła się nazwa „kodu obiektu”? Co powinno w nim oznaczać słowo „obiekt”? Czy ma to jakiś związek z programowaniem obiektowym, czy tylko z przypadkiem nazw?
SasQ
@SasQ: Kod obiektowy .
Jesse Good,
Nie pytam o to, co to jest kod obiektowy, kapitanie Obvious. Pytam o to, skąd wzięła się nazwa i dlaczego nazywa się kodem „obiektowym”.
BarbaraKwarc,

Odpowiedzi:

296

Kod maszynowy to kod binarny (1 i 0), który może być wykonany bezpośrednio przez CPU. Jeśli otworzysz plik kodu maszynowego w edytorze tekstowym, zobaczysz śmieci, w tym znaki niedrukowalne (nie, nie te znaki niedrukowalne;)).

Kod obiektowy to część kodu maszynowego, która nie została jeszcze połączona z kompletnym programem. Jest to kod maszynowy dla jednej konkretnej biblioteki lub modułu, który będzie stanowić gotowy produkt. Może także zawierać symbole zastępcze lub przesunięcia, których nie ma w kodzie maszynowym ukończonego programu. Łącznik będzie używać tych zastępczych i offsety, aby połączyć wszystko razem.

Kod asemblera jest zwykłym tekstem i (nieco) czytelnym dla człowieka kodem źródłowym, który w większości ma bezpośredni analog 1: 1 z instrukcjami maszynowymi. Odbywa się to za pomocą mnemoniki rzeczywistych instrukcji, rejestrów lub innych zasobów. Przykłady obejmują JMPi MULTdo skoku i mnożenia instrukcji procesorów. W przeciwieństwie do kodu maszynowego, procesor nie rozumie kodu asemblera. Konwertujesz kod asemblera na maszynę za pomocą asemblera lub kompilatora , chociaż zwykle myślimy o kompilatorach w powiązaniu z językiem programowania wysokiego poziomu, które są oderwane od instrukcji CPU.

Zbudowanie kompletnego programu wymaga napisania kodu źródłowego programu w języku asemblera lub języku wyższego poziomu, takim jak C ++. Kod źródłowy jest składany (dla kodu asemblera) lub kompilowany (dla języków wyższego poziomu) z kodem obiektowym, a poszczególne moduły są ze sobą łączone, aby stać się kodem maszynowym dla końcowego programu. W przypadku bardzo prostych programów krok łączenia może nie być potrzebny. W innych przypadkach, takich jak IDE (zintegrowane środowisko programistyczne), można wywołać konsolidator i kompilator razem. W innych przypadkach można użyć skomplikowanego skryptu make lub pliku rozwiązania , aby poinformować środowisko, jak zbudować końcową aplikację.

Istnieją również języki interpretowane, które zachowują się inaczej. Języki interpretowane opierają się na kodzie maszynowym specjalnego programu tłumaczącego. Na poziomie podstawowym interpreter analizuje kod źródłowy i natychmiast konwertuje polecenia na nowy kod maszynowy i wykonuje je. Współcześni tłumacze, zwani czasem także środowiskiem wykonawczym lub maszyną wirtualną , są znacznie bardziej skomplikowane: ocenianie całych sekcji kodu źródłowego na raz, buforowanie i optymalizowanie w miarę możliwości oraz obsługa złożonych zadań zarządzania pamięcią. Zinterpretowany język można również wstępnie skompilować do pośredniego języka lub kodu bajtowego niższego poziomu, podobnie jak kod asemblera.

Joel Coehoorn
źródło
24
+1: ładna, ale nieco upraszczająca odpowiedź - nie wszystkie instrukcje montażu są tłumaczone 1: 1 na instrukcje maszynowe, a pliki obiektowe mogą również zawierać inne dane (informacje o przeniesieniu, tablice symboli, ...)
Christoph
5
Dodano słowo łasicy do pierwszego wydania, zredagowane, aby uczynić 2. jaśniejszym.
Joel Coehoorn
2
@Christoph: mówisz „nie wszystkie instrukcje montażu są tłumaczone 1: 1 na instrukcje maszynowe”, podaj przykład.
Olof Forshell
5
@Olof: Architektury RISC czasami dostarczają wirtualny zestaw instrukcji na poziomie zestawu - np. Pseudo-instrukcje MIPS ( en.wikipedia.org/wiki/MIPS_architecture#Pseudo_instructions )
Christoph
3
@Panzercrisis Asembler nic nie dodaje. Jest to bezpośrednie tłumaczenie tego, co napisałeś na rzeczywiste instrukcje maszynowe. I nie nazwałbym dodatkowego kodu wprowadzonego przez kompilatory „niepotrzebnym”
Joel Coehoorn
125

Pozostałe odpowiedzi dobrze opisały różnicę, ale poprosiłeś także o wizualizację. Oto schemat pokazujący, jak przechodzą od kodu C do pliku wykonywalnego.

Grafika Noob
źródło
3
Uważam to za bardzo pomocne, ale brakuje w nim etykiety „Kod maszynowy”
Alexx Roche,
Więc kiedy jest na poziomie kodu wykonywalnego, czy jest to równoważne z kodem maszynowym?
CMCDragonkai
3
W kontekście tego diagramu „kod obiektowy” to kod maszynowy.
Grafika Noob
5
W rzeczywistości zarówno kod obiektowy, jak i kod wykonywalny są kodami maszynowymi. różnica polega na tym, że kod obiektowy nie jest ukończonym programem. Musi być połączony z innymi kodami biblioteki pomocniczej / modułu, jak wskazano na schemacie, aby utworzyć kompletny program / kod wykonywalny.
okey_on
@okeyxyz na jakim poziomie byłoby poprawne powiedzieć, że jest on bezpośrednio wykonywany przez procesor? Po asemblerze, po linkerze, po module ładującym, po przekonwertowaniu go na mikrokontroler?
Celeritas
49

Kod zestawu to czytelna dla człowieka reprezentacja kodu maszynowego:

mov eax, 77
jmp anywhere

Kod maszynowy to czysty kod szesnastkowy:

5F 3A E3 F1

Zakładam, że masz na myśli kod obiektowy jak w pliku obiektowym. Jest to wariant kodu maszynowego, z tą różnicą, że skoki są tak sparametryzowane, że linker może je wypełnić.

Asembler służy do konwersji kodu asemblera na kod maszynowy (kod obiektu). Linker łączy kilka plików obiektów (i bibliotek) w celu wygenerowania pliku wykonywalnego.

Kiedyś napisałem program asemblerowy w postaci czystego heksa (brak dostępnego asemblera) na szczęście było to dawno temu na starym dobrym (starożytnym) 6502. Ale cieszę się, że są asemblery dla pentium.

Toon Krijthe
źródło
76
Nie nie nie nie. Kod maszynowy nie jest kodem szesnastkowym. jest czysto dwójkowy. Kod szesnastkowy to po prostu wygodna reprezentacja pliku binarnego.
Breton
56
Jeśli naprawdę popadamy w skrajności, to nie jest binarne, to ilość zmagazynowanej energii elektrycznej w obwodzie. ;-)
Toon Krijthe
17
Tak oczywiście. Istnieje związek między szesnastkowym a tym, co nazwalibyście „kodem maszynowym”, ale nie jest całkiem dokładne stwierdzenie, że szesnastkowy jest kodem maszynowym. To wszystko, co próbuję powiedzieć.
Breton
9
@Breton W tym sensie nie ma czegoś takiego jak „kod szesnastkowy”, prawda? „Kod szesnastkowy” to tylko sposób przeglądania kodu maszynowego. Możesz wyświetlić kod maszynowy w systemie szesnastkowym, binarnym, ósemkowym, dziesiętnym lub w dowolny sposób. Również w tym sensie nie ma również „kodu binarnego”. Ponownie, „kod binarny” jest tylko sposobem przeglądania kodu maszynowego.
Utku
9
@Breton To, co mówisz, nie ma większego sensu. Binarny jest sposobem reprezentacji, podobnie jak hex. Jeśli nie jest szesnastkowy, nie jest również binarny.
Koray Tugay,
18

8B 5D 32 to kod maszynowy

mov ebx, [ebp+32h] to montaż

lmylib.sozawiera 8B 5D 32kod obiektu

Quassnoi
źródło
8

Nie wspomniałem jeszcze o jednym, że istnieje kilka różnych rodzajów kodu asemblera. W najbardziej podstawowej formie wszystkie liczby użyte w instrukcjach muszą być określone jako stałe. Na przykład:

1902 USD: BD 37 14: LDA 1437 USD, X
1905 USD: 85 03: STA 03 USD
1907 USD: 85 09: STA 09 USD
1909 USD: CA: DEX
190 USD: 10: 1902 BPL

Powyższy fragment kodu, jeśli jest przechowywany pod adresem 1900 USD we wkładzie Atari 2600, wyświetli liczbę wierszy w różnych kolorach pobranych z tabeli rozpoczynającej się pod adresem 1437 USD. W przypadku niektórych narzędzi wpisanie adresu wraz z prawą częścią wiersza powyżej zapisuje w pamięci wartości pokazane w środkowej kolumnie i rozpoczyna następny wiersz o następującym adresie. Pisanie kodu w tej formie było znacznie wygodniejsze niż pisanie szesnastkowe, ale trzeba było znać dokładne adresy wszystkiego.

Większość asemblerów pozwala używać adresów symbolicznych. Powyższy kod zostałby napisany bardziej jak:

rainbow_lp:
  lda ColorTbl, x
  sta WSYNC
  sta COLUBK
  dex
  bpl rainbow_lp

Asembler automatycznie dostosuje instrukcję LDA, aby odnosiła się do dowolnego adresu mapowanego na etykietę ColorTbl. Korzystanie z tego stylu asemblera znacznie ułatwia pisanie i edycję kodu, niż byłoby to możliwe, gdyby ktoś musiał ręcznie wpisywać i utrzymywać wszystkie adresy.

supercat
źródło
1
+1. Jeszcze jedna dodatkowa uwaga: istnieją również różne składnie języka asemblera , z których najbardziej znane to Intel i AT&T .
informatik01
1
@ informatik01: Co powiesz na mnemonikę Intel 8080 vs. Zilog Z80? Domyślam się, że poprzedza wojnę składniową Intel vs AT&T.
supercat
Nie kłócąc się, właśnie wspomniałem o tym aspekcie (inna składnia) i podałem przykład dwóch najbardziej popularnych / dobrze znanych / sławnych składni.
informatik01
4

Kod źródłowy, kod zestawu, kod maszynowy, kod obiektu, kod bajtowy, plik wykonywalny i plik biblioteki.

Wszystkie te warunki są często bardzo mylące dla większości ludzi, ponieważ uważają, że wzajemnie się wykluczają . Zobacz diagram, aby zrozumieć ich relacje. Opis każdego terminu znajduje się poniżej.


Rodzaje kodu


Kod źródłowy

Instrukcje w języku czytelnym dla ludzi (programistycznym)


Kod wysokiego poziomu

Instrukcje napisane w języku wysokiego poziomu (programowania),
np. C, C ++ i programy Java


Kod zestawu

Instrukcje napisane w języku asemblera (rodzaj języka programowania niskiego poziomu). Jako pierwszy krok procesu kompilacji kod wysokiego poziomu jest konwertowany na tę formę. Jest to kod zestawu, który jest następnie konwertowany na rzeczywisty kod maszynowy. W większości systemów te dwa kroki są wykonywane automatycznie w ramach procesu kompilacji.
np. program.asm


Kod obiektowy

Produkt procesu kompilacji. Może mieć postać kodu maszynowego lub kodu bajtowego.
np. plik.o


Kod maszynowy

Instrukcje w języku maszynowym.
np. a.out


Kod bajtowy

Instrukcja w formie pośredniej, którą może wykonać interpreter, taki jak JVM.
np. plik klasy Java


Plik wykonywalny

Produkt procesu łączenia. Są to kod maszynowy, który może być bezpośrednio wykonany przez CPU.
np. plik .exe.

Zauważ, że w niektórych kontekstach plik zawierający instrukcje bajtowe lub instrukcje języka skryptowego może być również uznany za wykonywalny.


Plik biblioteki

Niektóre kody są kompilowane w tej formie z różnych powodów, takich jak możliwość ponownego użycia, a później wykorzystywane przez pliki wykonywalne.

Bertram Gilfoyle
źródło
1
Twierdziłbym , że nie całe zgromadzenie jest tak naprawdę źródłem w najściślejszym znaczeniu kodu napisanego i / lub utrzymywanego przez ludzi. Często jest generowany maszynowo ze źródła i nigdy nie jest przeznaczony do spożycia przez ludzi (na przykład gcc naprawdę tworzy tekst asm, który podaje do osobnego asemblera, zamiast mieć wbudowany asembler w cc1pliku wykonywalnym). Myślę, że okrąg asm powinien wystawać z lewej strony koła „źródłowego”, ponieważ niektóre asm to tylko asm, a nie źródło. Oczywiście nigdy nie jest to kod obiektowy , ale niektóre asm są krokiem na drodze od plików źródłowych do obiektów obiektowych.
Peter Cordes,
@PeterCordes Dziękuję bardzo za komentarz. Nie byłem świadomy tego, co powiedziałeś o działaniu gcc. Obawiam się jednak, czy mogę całkowicie się z tobą zgodzić. Mam na myśli to, że kod źródłowy jest czymś napisanym przy użyciu języka programowania czytelnego dla człowieka. Może być napisany lub utrzymywany przez ludzi. Jestem pewien, że będziesz świadomy transkompilatorów. Z twojego punktu widzenia, do jakiej kategorii umieścisz produkt takiego kompilatora? Kod źródłowy czy coś innego? Proszę popraw mnie jeżeli się mylę. Dalsze komentarze są zawsze mile widziane.
Bertram Gilfoyle,
1

Kod zestawu jest omawiany tutaj .

„Język asemblera jest językiem niskiego poziomu do programowania komputerów. Implementuje symboliczną reprezentację numerycznych kodów maszynowych i innych stałych potrzebnych do zaprogramowania konkretnej architektury procesora”.

Kod maszynowy omówiono tutaj .

„Kod maszynowy lub język maszynowy to system instrukcji i danych wykonywanych bezpośrednio przez komputerową jednostkę centralną.”

Zasadniczo kod asemblera jest językiem i jest tłumaczony na kod obiektowy (natywny kod uruchamiany przez CPU) przez asembler (analogicznie do kompilatora).

rbrayb
źródło
1

Myślę, że to są główne różnice

  • czytelność kodu
  • kontrola nad tym, co robi Twój kod

Z drugiej strony czytelność kodu może poprawić lub zastąpić kod 6 miesięcy po jego stworzeniu, ale jeśli wydajność ma krytyczne znaczenie, możesz użyć języka niskiego poziomu do ukierunkowania na konkretny sprzęt, który będziesz mieć na produkcji, aby uzyskać szybsze wykonanie.

Dzisiaj IMO komputery są wystarczająco szybkie, aby umożliwić programistom szybkie wykonanie z OOP.

Alberto Zaccagni
źródło
1

Zestawienie to krótkie opisowe terminy, które ludzie mogą zrozumieć, które można bezpośrednio przełożyć na kod maszynowy faktycznie wykorzystywany przez procesor.

Choć nieco zrozumiały dla ludzi, Asembler jest wciąż na niskim poziomie. Wykonanie czegokolwiek pożytecznego wymaga dużo kodu.

Zamiast tego używamy języków wyższego poziomu, takich jak C, BASIC, FORTAN (OK, wiem, że sam się umawiałem). Po skompilowaniu tworzą kod obiektowy. Wczesne języki miały język maszynowy jako kod obiektowy.

Obecnie wiele języków, takich jak JAVA i C #, zwykle kompiluje się do kodu bajtowego, który nie jest kodem maszynowym, ale taki, który można łatwo zinterpretować w czasie wykonywania w celu wygenerowania kodu maszynowego.

Jim C.
źródło
Twój komentarz na temat Java i C # - oba używają kompilacji Just In Time, aby kody bajtowe nie były interpretowane. C # (.NET ogólnie) kompiluje się do Intermediate Language (IL), który jest następnie JIT w natywnym języku maszynowym dla docelowego procesora.
Craig Shearer
-1

Pliki źródłowe twoich programów są kompilowane w pliki obiektowe, a następnie linker łączy te pliki obiektowe razem, tworząc plik wykonywalny zawierający kody maszynowe twojej architektury.

Zarówno plik obiektowy, jak i plik wykonywalny obejmuje kod maszynowy architektury w postaci drukowalnych i niedrukowalnych znaków, gdy jest otwierany przez edytor tekstowy.

Niemniej jednak dychotomia między plikami polega na tym, że pliki obiektowe mogą zawierać nierozwiązane odwołania zewnętrzne (takie jak printfna przykład). Może być konieczne powiązanie go z innymi plikami obiektowymi. Oznacza to, że nierozwiązane odwołania zewnętrzne muszą zostać rozwiązane, aby uzyskać przyzwoity plik wykonywalny, łącząc się z innymi plikami obiektowymi, takimi jak biblioteka środowiska wykonawczego C / C ++ .

snr
źródło