Dlaczego kompilatory produkują kod asemblera?

19

Język asemblera jest konwertowany na język maszynowy przez asembler. Dlaczego kompilator miałby konwertować język wysokiego poziomu na asembler? Czy nie można go bezpośrednio przekonwertować z języka wysokiego poziomu na kod maszynowy?

CODERSAM
źródło

Odpowiedzi:

22

Innym powodem, dla którego kompilatory produkują zestaw zamiast właściwego kodu maszynowego są:

  • Adresy symboliczne używane przez asemblery zamiast adresów maszynowych kodujących znacznie ułatwiają przenoszenie kodu .
  • Łączenie kodu może obejmować kontrole bezpieczeństwa, takie jak sprawdzanie typu, a łatwiej jest to zrobić z nazwami symbolicznymi.
  • Małe zmiany w kodzie maszynowym są łatwiejsze do dostosowania, zmieniając asembler zamiast generatora kodu.
Martin Berger
źródło
dlaczego język asemblerowy jest tak wydajny, chociaż jest również napisany w języku angielskim i jak procesor go rozumie?
CODERSAM
3
@CODERSAM Zgromadzenie jest językiem formalnym, a nie językiem naturalnym. Jest bardzo zbliżony do języka maszynowego. Tak więc tłumaczenie nie wprowadza nieefektywności.
Martin Berger
kiedy mówisz „bardzo blisko języka maszynowego”, co to oznacza? Jestem z tym naprawdę zmieszany!
CODERSAM
2
@CODERSAM Dokładne znaczenie jest skomplikowane, ale coś w rodzaju homomorfizmu w algebrze. Kiedy tłumaczysz, powiedz „dodaj eax, nr 2”, który jest zestawem x86, możesz przetłumaczyć go na d7f5 (lub cokolwiek innego może być kod operacyjny), od razu, bez patrzenia na kontekst, bez dodawania kolejnych rzeczy. Zgromadzenie nie ma abstrakcji.
Martin Berger,
1
„Asembler nie ma abstrakcji” - powiedziałbym, że nazwy etykiet są już abstrakcją (od przesunięć). Również kontekst odgrywa rolę: np. add eax,2Może być przetłumaczony na 83 c0 02lub w 66 83 c0 02zależności od ostatnio wydanej dyrektywy, takiej jak use16.
Ruslan
15

Kompilator zwykle konwertuje kod wysokiego poziomu bezpośrednio na język maszynowy, ale można go zbudować modułowo, tak aby jeden back-end emitował kod maszynowy, a drugi kod asemblera (np. GCC). W fazie generowania kodu powstaje „kod”, który jest pewną wewnętrzną reprezentacją kodu maszynowego, który następnie musi zostać przekonwertowany na użyteczny format, taki jak język maszynowy lub kod asemblera.

Yuval Filmus
źródło
Ponadto, jeśli źródło może zawierać kod asemblera, to musi być dostępny mechanizm, który i tak tłumaczy ten wbudowany zestaw.
Paul A. Clayton
dlaczego język asemblerowy jest tak wydajny, chociaż jest również napisany w języku angielskim i jak procesor go rozumie?
CODERSAM
1
Język asemblera to „angielski” opis kodu maszynowego.
Yuval Filmus
11

Historycznie wiele znaczących kompilatorów wyprowadzało kod maszynowy bezpośrednio. Są jednak pewne trudności. Zasadniczo komuś, kto próbuje potwierdzić, że kompilator działa poprawnie, łatwiej będzie sprawdzić dane wyjściowe kodu asemblera niż kod maszynowy. Ponadto możliwe jest (i było to historycznie powszechne) użycie jednoprzebiegowego kompilatora C lub Pascal w celu utworzenia pliku w asemblerze, który można następnie przetworzyć za pomocą dwuprzebiegowego asemblera. Bezpośrednie generowanie kodu wymagałoby albo użycia dwuprzebiegowego kompilatora C lub Pascal, albo kompilatora jednoprzebiegowego, po którym następowałyby pewne sposoby poprawiania adresów przeskakiwania w przód [jeśli środowisko wykonawcze udostępnia rozmiar uruchomionego programu w stałe miejsce, kompilator może napisać listę poprawek na końcu kodu i pozwolić, aby kod startowy zastosował te poprawki w czasie wykonywania; takie podejście zwiększyłoby rozmiar pliku wykonywalnego o około cztery bajty na punkt łaty, ale poprawiłoby szybkość generowania programu].

Jeśli celem jest szybki kompilator, bezpośrednie generowanie kodu może działać dobrze. Jednak w przypadku większości projektów koszt wygenerowania kodu w języku asemblera i jego złożenia naprawdę nie jest obecnie poważnym problemem. Posiadanie kompilatorów do tworzenia kodu w formie, która może ładnie współdziałać z kodem produkowanym przez inne kompilatory, jest na ogół wystarczająco dużą korzyścią, aby uzasadnić wydłużenie czasu kompilacji.

supercat
źródło
1

Nawet platformy korzystające z tego samego zestawu instrukcji mogą mieć różne formaty plików obiektów relokowalnych. Mogę wymyślić „a.out” (wczesny UNIX), OMF, MZ (MS-DOS EXE), NE (16-bitowy system Windows), COFF (UNIX System V), Mach-O (OS X i iOS) i ELF (Linux i inne), a także ich warianty, takie jak XCOFF (AIX), ECOFF (SGI) i Portable Executable (PE) oparty na COFF w 32-bitowym systemie Windows. Kompilator, który tworzy język asemblera, nie musi wiele wiedzieć o formatach plików obiektowych, umożliwiając asemblerowi i linkerowi zgromadzenie tej wiedzy w osobnym procesie.

Zobacz także Różnica między OMF i COFF na temat przepełnienia stosu.

Damian Yerrick
źródło
1

Zwykle kompilatory działają wewnętrznie z sekwencjami instrukcji. Każda instrukcja będzie reprezentowana przez strukturę danych reprezentującą jej nazwę operacji, operandy i tak dalej. Kiedy argumenty są adresami, adresy te będą zwykle symbolicznymi odniesieniami, a nie konkretnymi wartościami.

Wyjście asemblera jest stosunkowo proste. To w zasadzie kwestia wzięcia wewnętrznej struktury danych kompilatora i zrzucenia go do pliku tekstowego w określonym formacie. Dane wyjściowe asemblera są również stosunkowo łatwe do odczytania, co jest przydatne, gdy trzeba sprawdzić, co robi kompilator.

Wyprowadzanie plików obiektów binarnych to znacznie więcej pracy. Autor kompilatora musi wiedzieć, w jaki sposób kodowane są wszystkie instrukcje (co może być dalekie od trywialnych w przypadku niektórych CPUS), musi przekonwertować niektóre odwołania symboliczne na adresy względne licznika programu, a inne na jakąś formę metadanych w pliku obiektu binarnego . Muszą napisać wszystko w formacie ściśle zależnym od systemu.

Tak, absolutnie można stworzyć kompilator, który może wyprowadzać obiekty binarne bezpośrednio, bez zapisywania asemblera jako kroku pośredniego. Pytanie, podobnie jak wiele innych rzeczy w tworzeniu oprogramowania, brzmi: czy skrócenie czasu kompilacji jest warte dodatkowych prac rozwojowych i konserwacyjnych?

Kompilator, którego znam najlepiej (freepascal) może wyświetlać asembler na wszystkich platformach, ale może wysyłać tylko obiekty binarne bezpośrednio na podzestawie platform.

Peter Green
źródło
1

Kompilator powinien być w stanie wygenerować wyjście asemblera oprócz normalnego kodu relokowalnego dla dobra programisty.

Pewnego razu po prostu nie znalazłem błędu w programie C uruchomionym na Unix System V na maszynie LSI-11. Wydawało się, że nic nie działa. Wreszcie w desperacji kazałem protilowanemu kompilatorowi C wydalić wersję asemblera jego tłumaczenia. W końcu znalazłem błąd! Kompilator przydzielał więcej rejestrów niż istniało w maszynie! (Kompilator przypisał rejestry od R0 do R8 na maszynie z tylko rejestrami od R0 do R7.) Udało mi się obejść błąd w kompilatorze i mój program działał.

Kolejną korzyścią z posiadania wyjścia asemblera jest próba użycia „standardowych” bibliotek, które używają różnych protokołów przekazywania parametrów. Późniejsze kompilatory C pozwalają mi ustawić protokół z parametrem („pascal” spowoduje, że kompilator doda parametry w podanej kolejności, w przeciwieństwie do standardu C odwracania kolejności).

Kolejną korzyścią jest umożliwienie programistowi zobaczenia, jakie przerażające zadanie wykonuje jego kompilator. Prosta instrukcja C wymaga około 44 instrukcji maszyny. Wartości są ładowane z pamięci, a następnie szybko odrzucane. etc, etc, etc ...

Osobiście uważam, że posiadanie kompilatora zamiast relokowalnego modułu obiektowego jest naprawdę głupie. Podczas kompilacji programu kompilator zbiera wiele informacji o Twoim programie. Zazwyczaj przechowuje wszystkie te informacje w czymś zwanym tablicą symboli. Po wydaleniu kodu asemblera wyrzuca całą tę tabelę informacyjną. Asembler następnie analizuje wydalony kod i ponownie zbiera niektóre informacje, które kompilator już miał. Jednak asembler nie wie nic o instrukcjach If instrukcji For lub instrukcji While. Brakuje więc wszystkich tych informacji. Następnie asembler produkuje relokowalny moduł obiektowy, czego nie zrobił kompilator.

Dlaczego???

Robert Pearson
źródło