W przypadku AL / AX / EAX należy używać kodowania skróconego specjalnego przypadku oraz innych krótkich formularzy i instrukcji jednobajtowych
Przykłady zakładają tryb 32/64-bitowy, w którym domyślny rozmiar operandu to 32 bity. Prefiks wielkości argumentu zmienia instrukcję na AX zamiast EAX (lub odwrotnie w trybie 16-bitowym).
inc/decrejestr (inny niż 8-bitowy): inc eax/ dec ebp. (Nie x86-64: 0x4xbajty opcode zostały zmienione na prefiksy REX, więc inc r/m32jest to jedyne kodowanie).
8-bitowy inc bljest 2 bajty, z użyciem inc r/m8kodu operacji / M + Modr argumentu operacji kodowania . Więc używać inc ebxdo przyrostu bl, czy jest to bezpieczne. (np. jeśli nie potrzebujesz wyniku ZF w przypadkach, gdy górne bajty mogą być niezerowe).
scasd: e/rdi+=4, wymaga, aby rejestr wskazywał na czytelną pamięć. Czasami przydatne, nawet jeśli nie obchodzi cię wynik FLAGI (jak cmp eax,[rdi]/ rdi+=4). W trybie 64-bitowym scasbmoże działać jako 1-bajtowyinc rdi , jeśli lodsb lub stosb nie są przydatne.
xchg eax, r32: To gdzie 0x90 NOP pochodzi z: xchg eax,eax. Przykład: ponownie ułóż 3 rejestry z dwiema xchginstrukcjami w pętli cdq/ dla GCD w 8 bajtach, gdzie większość instrukcji jest jednobajtowa, w tym nadużycie / zamiast /idivinc ecxlooptest ecx,ecxjnz
cdq: znak rozszerza EAX do EDX: EAX, tzn. kopiuje wysoki bit EAX do wszystkich bitów EDX. Aby utworzyć zero ze znanymi nieujemnymi lub uzyskać 0 / -1, aby dodać / sub lub maskować. Lekcja historii x86: cltqvs.movslq oraz mnemoniki AT&T vs. Intel dla tego i pokrewnych cdqe.
lodsb / d : like mov eax, [rsi]/ rsi += 4without clobbering flags. (Zakładając, że DF jest jasne, jakie standardowe konwencje wywoływania wymagają przy wprowadzaniu funkcji.) Również stosb / d, czasami scas, a rzadziej movs / cmps.
push/ pop reg. np. w trybie 64-bitowym push rsp/ pop rdima 2 bajty, ale mov rdi, rsppotrzebuje prefiksu REX i ma 3 bajty.
xlatbistnieje, ale rzadko jest użyteczny. Dużej tabeli odnośników należy unikać. Nigdy też nie znalazłem zastosowania dla instrukcji AAA / DAA lub innych instrukcji BCD lub 2-ASCII.
1 bajt lahf/ sahfrzadko są przydatne. Ty mógł lahf / and ah, 1jako alternatywa setc ah, ale nie jest to zwykle użyteczne.
A konkretnie w przypadku CF sbb eax,eaxjest 0 / -1, a nawet nieudokumentowany, ale powszechnie obsługiwany 1-bajtowy salc(zestaw AL z Carry), który skutecznie działa sbb al,albez wpływu na flagi. (Usunięte w x86-64). Użyłem SALC w Wyzwaniu uznania użytkownika nr 1: Dennis ♦ .
1-bajtowy cmc/ clc/ stc(odwrócenie („uzupełnienie”), wyczyszczenie lub zestaw CF) są rzadko przydatne, chociaż znalazłem zastosowaniecmc w dodawaniu o rozszerzonej precyzji z podstawowymi fragmentami 10 ^ 9. Aby bezwarunkowo ustawić / wyczyścić CF, zwykle należy to zrobić jako część innej instrukcji, np. xor eax,eaxCzyści CF, a także EAX. Nie ma równoważnych instrukcji dla innych flag stanu, tylko DF (kierunek ciągu) i IF (przerwania). Flaga przenoszenia jest specjalna dla wielu instrukcji; shift ustawia to, adc al, 0może dodać go do AL w 2 bajtach, a wspomniałem wcześniej o nieudokumentowanej SALC.
std/ cldrzadko wydaje się tego warte . Zwłaszcza w kodzie 32-bitowym lepiej jest po prostu użyć decwskaźnika i movoperandu źródła pamięci w instrukcji ALU zamiast ustawiać DF so lodsb/ stosbgo w dół zamiast w górę. Zazwyczaj jeśli trzeba w dół w ogóle, trzeba jeszcze inny wskaźnik idzie w górę, tak że trzeba więcej niż jeden std, a cldw całej funkcji do wykorzystania lods/ stosdla obu stron. Zamiast tego po prostu użyj instrukcji strunowych dla kierunku w górę. (Standardowe konwencje wywoływania gwarantują DF = 0 przy wprowadzaniu funkcji, więc można założyć, że za darmo bez użycia cld.)
Historia 8086: dlaczego te kodowania istnieją
W oryginalnym 8086, AX był wyjątkowy: instrukcje jak lodsb/ stosb, cbw, mul/ divi inni używają go w sposób dorozumiany. Oczywiście nadal tak jest; obecny x86 nie upuścił żadnego z kodów 8086 (przynajmniej żadnego z oficjalnie udokumentowanych). Ale później procesory dodały nowe instrukcje, które dały lepsze / bardziej wydajne sposoby robienia rzeczy bez uprzedniego kopiowania lub zamiany ich na AX. (Lub do EAX w trybie 32-bitowym.)
np. 8086 brakowało później dodatków takich jak movsx/ movzxaby załadować lub przenieść + przedłużyć znak lub 2 i 3 operand imul cx, bx, 1234, które nie dają wyniku w połowie i nie mają żadnych ukrytych argumentów.
Ponadto głównym wąskim gardłem 8086 było pobieranie instrukcji, więc optymalizacja pod kątem rozmiaru kodu była wtedy ważna dla wydajności . Projektant ISA z 8086 (Stephen Morse) poświęcił dużo miejsca na kodowanie opcodu na specjalne przypadki dla AX / AL, w tym specjalne (E) AX / AL-docelowe kody dla wszystkich podstawowych instrukcji ALU natychmiast-src , po prostu opcode + natychmiast bez bajtu ModR / M. 2 bajty add/sub/and/or/xor/cmp/test/... AL,imm8lub AX,imm16lub (w trybie 32-bitowym) EAX,imm32.
Ale nie ma specjalnego przypadku EAX,imm8, więc zwykłe kodowanie ModR / M add eax,4jest krótsze.
Zakładamy, że jeśli będziesz pracować nad niektórymi danymi, będziesz chciał mieć je w AX / AL, więc zamiana rejestru na AX była czymś, co możesz chcieć zrobić, może nawet częściej niż kopiowanie rejestru do AX za pomocą mov.
Wszystko w kodowaniu instrukcji 8086 obsługuje ten paradygmat, od instrukcji takich jak lodsb/wdo wszystkich kodowań specjalnych przypadków dla bezpośrednich znaków w EAX po ich niejawne użycie nawet do mnożenia / dzielenia.
Nie daj się ponieść emocjom; nie jest automatycznie wygraną zamiana wszystkiego na EAX, szczególnie jeśli potrzebujesz natychmiastowego dostępu do rejestrów 32-bitowych zamiast 8-bitowych. Lub jeśli potrzebujesz przeplatać operacje na wielu zmiennych w rejestrach jednocześnie. Lub jeśli korzystasz z instrukcji z 2 rejestrami, w ogóle nie następuje to natychmiast.
Ale zawsze należy pamiętać: czy robię coś, co byłoby krótsze w EAX / AL? Czy mogę zmienić układ, aby mieć to w AL, lub czy obecnie lepiej wykorzystuję AL z tym, do czego już go używam.
Swobodnie miksuj operacje 8-bitowe i 32-bitowe, aby czerpać korzyści, gdy tylko jest to bezpieczne (nie musisz przeprowadzać operacji w pełnym rejestrze ani nic takiego).
push 200; pop edx- 3 bajtów do inicjalizacji.