asembler - kodowanie rozkazu - procesor 8086

0

Wpisuję w edytorze instrukcję, która po kompilacji i uruchomieniu ląduje w segmencie kodu, skąd instrukcje są pobierane i przetwarzane.

Moje pytanie dotyczy instrukcji:
add ax,30

Ten rozkaz ma 2 bajty, bezpośrednio wpisuje do rejestru ax wartość 30, interesuje mnie jak zostanie zakodowany i w jakiej postaci wpisany do segmentu kodu w pamięci.
Bajt kodu operacji (mnemonik) to 0x81 (100000001), pozostaje drugi bajt w którym 2 najstarsze bity to modyfikator trybu adresowania, 3 bity to jeden operand czyli rejestr ax (000). Pozostają 3 bity na drugi czyli 30 ale ta liczba binarnie to 11110.
W jaki sposób taki rozkaz zostanie zakodowany i zapisany w pamięci skoro liczba powinna zostać pobrana bezpośrednio z rozkazu, czy jest jakoś doklejona jako kolejne bajty czy jest to zrealizowane jakoś inaczej?

1

nasm kompiluje mi go do 4 bajtów, z czego pierwszy to prefix 66, więc go pomińmy. Tak czy siak mamy 3 bajty:
83 C0 1E
83 to opcode
C0 to bajt ModR/M, binarnie 11000000; 11 oznacza, że mamy do czynienia po prostu z rejestrem, pierwsze 000 to numer opcodu w grupie opcodu, a drugie 000 to numer rejestru.
1E to drugi parametr (to 30).

1

Przekonaj się sam!

add ax, 30
add ax, 30
add ax, 30

Teraz kompilujemy i dekompilujemy:
nasm add.asm && ndisasm add

00000000  83C01E            add ax,byte +0x1e
00000003  83C01E            add ax,byte +0x1e
00000006  83C01E            add ax,byte +0x1e
0

Hah, przekonałem się i zrozumiałem :)

a drugie 000 to numer opcodu w grupie opcodu.

Mógłbyś rozwinąć?

Do identyfikacji instrukcji korzystam z:
http://ref.x86asm.net/coder32-abc.html#modrm_byte_16

2

Mógłbyś rozwinąć?

Otóż niektóre opcody mają przypisany ten sam numer opcodu, lecz tak naprawdę są to kompletnie inne instrukcje.
Przykład:
opcodes.png
(http://ref.x86asm.net/coder32.html)
Wszystkie osiem instrukcji ma ten sam opcode: 83.
Zatem jak je odróżnić?
Tutaj właśnie przychodzi z pomocą bajt ModR/M - spójrz na liczby od zera do siedmiu znajdujące w tej tabeli: oznaczają one właśnie numer opcodu w grupie opcodu (nie jestem pewien, jak to się fachowo nazywa - Gynavel Coldwind w swoich poradnikach tak to nazywa(ł), więc ja też przyjąłem taką konwencję).
Dla zobrazowania tego spójrzmy na instrukcje maszynowe tych kodów:

add eax, 10

83 C0 0A
C0 -> 11 000 000; pierwsze 000 oznacza numer naszego opcodu: 0 w tabeli to add - zgadza się.

or eax, 10

83 C8 0A
C8 -> 11 001 000; 001 to w dziesiętnym 1, patrzymy do tabeli i widzimy or - czyli jest ok.

adc ecx, 10

83 D0 0A
D0 -> 11 010 000; 010 to w dziesiętnym 2, w tabeli widnieje adc - również się zgadza.

Teraz zmieńmy rejestr na ecx:

or ecx, 10

83 C9 0A
C9 -> 11 001 001; pierwsze 001 wskazuje, że mowa o opcodzie or, a drugie, że chodzi o rejestr ecx.


Nieco się w moim pierwszym poście pomyliłem, ponieważ - jak widać - numer opcodu w grupie opcodu jest tą środkową wartością, a nie ostatnią (już fixnąłem).
0

Dzięki wielkie za wyjaśnienia :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1