Intel x86 Assembly Language & Microarchitecture
Asemblery
Szukaj…
Microsoft Assembler - MASM
Biorąc pod uwagę, że 8086/8088 był używany w komputerze IBM, a system operacyjny na nim najczęściej pochodzi od Microsoftu, asembler MASM Microsoftu był de facto standardem na wiele lat. Śledził ściśle składnię Intela, ale dopuszczał pewną wygodną, ale „luźną” składnię, która (z perspektywy czasu) powodowała jedynie zamieszanie i błędy w kodzie.
Doskonały przykład jest następujący:
MaxSize EQU 16 ; Define a constant
Symbol DW 0x1234 ; Define a 16-bit WORD called Symbol to hold 0x1234
MOV AX, 10 ; AX now holds 10
MOV BX, MaxSize ; BX now holds 16
MOV CX, Symbol ; ????
Czy ostatnia instrukcja MOV umieszcza zawartość Symbol w CX , czy adres Symbol w CX ? Czy CX kończy się na 0x1234 lub 0x0102 (lub cokolwiek innego)? Okazuje się, że CX kończy się na 0x1234 - jeśli chcesz adres, musisz użyć specyfikatora OFFSET
MOV AX, [Symbol] ; Contents of Symbol
MOV CX, OFFSET Symbol ; Address of Symbol
Asembler Intel
Intel napisał specyfikację języka asemblera 8086, pochodnej wcześniejszych procesorów 8080, 8008 i 4004. W związku z tym asembler, który napisali, dokładnie przestrzegał własnej składni. Jednak ten asembler nie był szeroko stosowany.
Intel zdefiniował swoje kody operacyjne tak, aby miały zero, jeden lub dwa operandy. Instrukcje z dwoma operandami zostały zdefiniowane w kolejności dest , source , która różniła się w tym czasie od innych asemblerów. Ale niektóre instrukcje wykorzystywały rejestry niejawne jako operandy - wystarczyło wiedzieć, co to są. Intel zastosował także koncepcję „prefiksów” kodów - jeden kod będzie miał wpływ na następną instrukcję.
; Zero operand examples
NOP ; No parameters
CBW ; Convert byte in AL into word in AX
MOVSB ; Move byte pointed to by DS:SI to byte pointed to by ES:DI
; SI and DI are incremented or decremented according to D bit
; Prefix examples
REP MOVSB ; Move number of bytes in CX from DS:SI to ES:DI
; SI and DI are incremented or decremented according to D bit
; One operand examples
NOT AX ; Replace AX with its one's complement
MUL CX ; Multiply AX by CX and put 32-bit result in DX:AX
; Two operand examples
MOV AL, [0x1234] ; Copy the contents of memory location DS:0x1234 into AL register
Intel złamał również konwencję używaną przez inne asemblery: dla każdego kodu operacyjnego wynaleziono inną mnemonikę. Wymagało to subtelnie lub wyraźnie różnych nazw dla podobnych operacji: np. LDM dla „Load from Memory” i LDI dla „Load Natychmiastowe”. Intel użył jednego mnemonicznego MOV - i spodziewał się, że asembler obliczy, który kod operacji ma być użyty z kontekstu. To spowodowało wiele pułapek i błędów dla programistów w przyszłości, gdy asembler nie mógł zrozumieć, czego tak naprawdę chciał programista ...
Asembler AT&T - as
Chociaż 8086 był najczęściej używany w komputerach IBM wraz z Microsoftem, wiele innych komputerów i systemów operacyjnych również z niego korzystało: przede wszystkim Unix. To był produkt AT&T i miał już system Unix działający na wielu innych architekturach. W tych architekturach zastosowano bardziej konwencjonalną składnię asemblera - zwłaszcza, że instrukcje składające się z dwóch argumentów określały je w kolejności source , dest .
Konwencje asemblera AT&T zastąpiły konwencje dyktowane przez Intela i wprowadzono zupełnie nowy dialekt dla zakresu x86:
- Nazwy rejestrów były poprzedzone przez
%:
%al,%bxitp. - Natychmiastowe wartości były poprzedzone przez
$:
$4 - Operandy były w kolejności
source,dest - Opcodes zawierały rozmiary operandów:
movw $4, %ax ; Move word 4 into AX
Borland's Turbo Asembler - TASM
Borland zaczął od kompilatora Pascal, który nazwali „Turbo Pascal”. Następnie pojawiły się kompilatory dla innych języków: C / C ++, Prolog i Fortran. Wyprodukowali również asembler o nazwie „Turbo Asembler”, który zgodnie z konwencją nazewnictwa Microsoftu nazwali „TASM”.
TASM próbował rozwiązać niektóre problemy z pisaniem kodu za pomocą MASM (patrz wyżej), zapewniając bardziej ścisłą interpretację kodu źródłowego w określonym trybie IDEAL . Domyślnie zakładał tryb MASM , więc mógł bezpośrednio składać źródło MASM - ale potem Borland stwierdził, że muszą być kompatybilne z błędami z bardziej „dziwacznymi” QUIRKS MASM - więc dodali również tryb QUIRKS .
Ponieważ TASM był (znacznie) tańszy niż MASM, miał dużą bazę użytkowników - ale niewiele osób korzystało z trybu IDEAL, pomimo jego reklamowanych zalet.
Asembler GNU - gaz
Kiedy projekt GNU potrzebował asemblera dla rodziny x86, wybrał wersję AT&T (i jej składnię), która była powiązana z Uniksem, a nie z wersją Intel / Microsoft.
Netwide Assembler - NASM
NASM jest zdecydowanie najbardziej portowanym asemblerem dla architektury x86 - jest dostępny dla praktycznie każdego systemu operacyjnego opartego na x86 (nawet dołączony do MacOS) i jest dostępny jako asembler dla wielu platform na innych platformach.
Ten asembler używa składni Intela, ale różni się od innych, ponieważ mocno koncentruje się na swoim własnym języku „makro” - pozwala to programiście tworzyć bardziej złożone wyrażenia przy użyciu prostszych definicji, umożliwiając tworzenie nowych „instrukcji”.
Niestety ta potężna funkcja ma swoją cenę: typ danych przeszkadza w uogólnionych instrukcjach, więc typowanie danych nie jest wymuszane.
response: db 'Y' ; Character that user typed
cmp response, 'N' ; *** Error! Unknown size!
cmp byte response, 'N' ; That's better!
cmp response, ax ; No error!
Jednak NASM wprowadził jedną cechę, której innym brakowało: nazwy symboli o zasięgu. Kiedy definiujesz symbol w innych asemblerach, nazwa ta jest dostępna w pozostałej części kodu - ale to „zużywa” tę nazwę, „zanieczyszczając” globalną przestrzeń nazw symbolami.
Na przykład (przy użyciu składni NASM):
STRUC Point
X resw 1
Y resw 1
ENDSTRUC
Po tej definicji X i Y są na zawsze zdefiniowane. Aby uniknąć „używania” nazw X i Y , musisz użyć bardziej określonych nazw:
STRUC Point
Pt_X resw 1
Pt_Y resw 1
ENDSTRUC
Ale NASM oferuje alternatywę. Wykorzystując koncepcję „zmiennej lokalnej”, możesz zdefiniować pola struktury, które wymagają nominowania struktury zawierającej w przyszłych odniesieniach:
STRUC Point
.X resw 1
.Y resw 1
ENDSTRUC
Cursor ISTRUC Point
ENDISTRUC
mov ax,[Cursor+Point.X]
mov dx,[Cursor+Point.Y]
Niestety, ponieważ NASM nie śledzi typów, nie można użyć bardziej naturalnej składni:
mov ax,[Cursor.X]
mov dx,[Cursor.Y]
Yet Another Asembler - YASM
YASM to kompletne przepisanie NASM, ale jest kompatybilne zarówno ze składniami Intela, jak i AT&T.