2013-06-10 12 views
11

Dlaczego instrukcja nopl w pliku wykonywalnym x86 przyjmuje operand? Czy ludzie nie po prostu robią, cóż, nic?Dlaczego instrukcja nopl x86 przyjmuje operand?

nopl 0x0(%rax)

+2

Możliwy duplikat http://stackoverflow.com/questions/12559475/what-does-nopl-do-in-x86-system – Hazzit

+0

Możesz "nic nie robić" z argumentem, prawda? '90 nop' również ma argumenty, to naprawdę' xchg eax, eax'. – harold

+1

Pytam, ponieważ dekompilator, którego używam, klasyfikuje go jako instrukcję oddziału. Jakiś powód, dlaczego tak się dzieje? – RouteMapper

Odpowiedz

6

Wiele binarne zestawy instrukcji przetwórców mieć wiele sposobów przedstawiania funkcjonalnie identyczne instrukcje. Na przykład oryginalny zestaw instrukcji ARM zawiera instrukcje ładowania R0 z dowolną wartością formularza b << n, gdzie b jest wartością od 0 do 255, a n jest liczbą parzystą od 0 do 24. Jeśli chcemy załadować R0 o wartości 256 , można załadować instrukcję, która ładuje ją z 1<<8, lub można użyć instrukcji dla 4<<6, 16<<4 lub 64<<2. Instrukcje ładowania tych różnych wartości mają różne kodowania binarne, mimo że wszystkie cztery instrukcje mają taki sam efekt.

Asemblery dla niektórych kompilatorów robią wszystko co w ich mocy, aby zapewnić, że z jakichś pozornie identycznych instrukcji powinien korzystać fragment kodu. Chociaż zwykle nie jest to ważne, czasami może być pożądane unikanie użycia pewnych wartości bajtów w obrębie fragmentu kodu, lub mogą wystąpić sytuacje, w których modyfikacje niektórych bajtów w kodzie będą miały szczególny skutek. Na przykład osiem bitów w instrukcjach ARM, które zostały podane, służy do określenia wartości b. Jeśli kod miałby zastąpić część jednej z powyższych instrukcji wartością b z wartością 12, wartość załadowana do R0 zależałaby od tego, która z oryginalnych czterech instrukcji była użyta; może to być 0x0C00, 0x0300, 0x00C0 lub 0x0030.

Mimo że asemblery dla 8x86 zasadniczo nie umożliwiają wyraźnego rozróżnienia wszystkich możliwych kodowań instrukcji, mogą istnieć pewne konteksty, w których przydatna może być możliwość określenia wartości bajtów zawartych w instrukcji. Na przykład, jednym podejściem do obsługi wyjątków byłoby rutynowe sprawdzenie, kiedy wystąpi wyjątek, czy instrukcja pod adresem zwrotnym jest jakąś szczególną formą NOP i, jeśli tak jest, interpretuje jej operand jako adres struktury danych przechowywanie informacji związanych z wyjątkiem. W praktyce większość języków 8x86, które obsługują wyjątki, używa innych sposobów ich obsługi, ale wyżej wymieniona metoda spowolniłaby normalną funkcję zwracania przez czas wymagany do pobrania i wykonania długiego NOP, ale byłaby w stanie poradzić sobie z wyjątkowymi wyjściami stosunkowo skutecznie (większość języki używają wolniejszego podejścia do obsługi przerwań w celu uniknięcia kosztu wykonania NOP w przypadku bez wyjątku, ale inne języki mogą zdecydować się na robienie różnych rzeczy).

+1

Prawda, w tym przypadku jest bardziej użyteczna, ponieważ operand zmienia długość instrukcji, jak pokazuje [odpowiedź nrz] (http://stackoverflow.com/a/12564044/) w duplikacie linku w komentarzach . – ughoavgfhw

+0

@ughoavgfhw: Jeśli potrzebowałeś tylko arbitralnego NOP o odpowiedniej długości, można by po prostu zdefiniować 'nop',' nop2', 'nop3', itp. Lub też mieć mnemonik dla" generowania najszybszej n-bajtowej sekwencji nop " którego argument był wymaganego rozmiaru. Jeśli ktoś potrzebował np. 7-bajtowy NOP nie byłoby potrzeby określenia wartości, aby przejść do czterech z tych bajtów. – supercat

2

Czasami używam nops podczas debugowania. Jeśli wiem, jak coś idzie nie tak, ale wymaga to tysięcy breakpoint breaks, aby odkryć, piszę kod, który testuje to. Może to wyglądać mniej więcej tak (kod C-style):

if (condition_occurred) 
{ 
    asm("nop"); 
} 

Kiedy ustawić punkt przerwania na linii „asm” debugger ustanowi DRX rejestracji z adresem (fizyczną) liniowego (odpowiadający adres wirtualny) nop. Po osiągnięciu tej lokalizacji nastąpi przerwanie punktu przerwania i nastąpi przejście do debuggera. Jeśli wykonujesz polecenie bez debuggera, nop zostanie przetworzony (nic się nie dzieje). Więc tutaj chcę instrukcji, która nie robi dokładnie nic i ma sens, że to robi (nie robi).


Oto przykład tego, gdzie instrukcja "nie rób nic" faktycznie coś robi ... choć pośrednio.

Patrz strona 8 w pozycji this paper i zwróć uwagę na pierwszą (górną) instrukcję pętli w przykładzie 3 (która jest rozwinięciem przykładu 2).Również przypis w prawym dolnym rogu strony.

Autor wskazuje, że dodatkowe nopy mogłyby przyspieszyć ten proces.

Nosiciele zdecydowanie mają swoje zastosowania.

Powiązane problemy