|
Kiedy natknąłem się na poniższy kod podczas nauki asemblera, pomyślałem, że program nie może się zakończyć normalnie. Jednak po debugowaniu jednokrokowym śledzeniu okazało się, że program może zakończyć się normalnie, co wywołało dziwne zjawisko: gdy program zaczął wykonywać kod:0005 do kod:0014, nadal przeskakiwał do kod:0008 za pomocą polecenia jmp. Jednak podczas kontynuowania wykonywania kroku do przodu program przeskakuje bezpośrednio do kodu:0 zamiast kod:0018 (czyli segmentu oznacznika S1). Na początku nie rozumiałem, co się dzieje, ale po wielu jednokrokowych obserwacjach nadal czułem się dziwnie. Po dokładnym przeanalizowaniu użycia instrukcji JMP w podręczniku [1], a następnie analizie programu w połączeniu z kodem maszynowym, zyskałem nowe zrozumienie instrukcji JMP. instrukcje maszyny do składania kodu przesunięcia adresów (IP) Załóżmy CS:Code (jednostka: H) Segment kodu mov ax, 4c00h 0000 B8004C int 21h 0003 CD21 start: mov ax,0 0005 B80000 s: NOP 0008 90 nop 0009 90 mov di,offset s 000A BF0800 mov si, offset s2 000D BE2000 mov ax,cs:[si] CS:0020=F6EB mov cs:[di],ax CS:0008=9090 s0: jmp short s 0016 EBF0 s1: mov ax,0 0018 B80000 int 21h 001B CD21 mov ax,0 001D B80000 S2: JPP Short S1 0020 EBF6 nop 0022 90 Koniec kodu koniec startu 1. Należy jasno zrozumieć następujące dwa punkty 1. Proces wykonywania instrukcji CPU wygląda następująco: <1>. Odczytać instrukcję z jednostki pamięci wskazanej przez CS:IP i umieścić ją w buforze instrukcji. <2>. IP=IP+Długość instrukcji aktualnie odczytywanej do bufora, czyli IP wskazuje na kolejną instrukcję. <3>. Wykonaj bieżące polecenie w buforze. Przejdź do kroku <1> 2. Znaczenie krótkiego polecenia jmp do przeniesienia segmentu wewnętrznego <1>. IP to offset, czyli adres w IP-= oznaczniku – adres pierwszego bajtu po poleceniu jmp. <2>. Funkcją tego polecenia jest modyfikacja wartości IP, a po wykonaniu polecenia IP = IP + 8-bitowy offset < bity 3> i 8 mają zakres przemieszczenia -128~127, a przesunięcie wyraża się w postaci dopełnienia [2]. 2. Analiza kodu 1. Krok 1: Program rozpoczyna wykonywanie od początku wejściowego (code:0005), gdy wykonane zostanie wykonanie polecenia code:0013~0014, kod maszynowy instrukcji jmp short S1 na oznaczce S2 jest kopiowany do code:0008, a adres IP to 0016. W tym momencie, zakładając, że nie ma instrukcji jmp short s, program zostanie wykonany do s2:jmp short s1, odczyta jmp short s1 do bufora instrukcji i IP=0022; a transfer z s2 do s1 to transfer wewnątrzsegmentowy, format kodu maszynowego to EB disp, a disp=oznaczenie s1-oznaczenie s2=(00018-0022) complement=F6, więc kod maszynowy polecenia jmp short s1 powinien być EBF6. W związku z tym EBF6 jest kopiowany do jednostki kod:0008~code:0009. 2. Krok 2: Odczytaj instrukcję jmp short s (EBF0) do bufora instrukcji, IP=IP+0002=0018; kod uzupełniający oznaczenia s-oznaczenia s0=(0008-0018) = F0, a transfer z s0 do s to transfer wewnątrzsegmentowy, a format kodu maszynowego to EB disp (czyli EBF0) 3. Krok 3: Polecenie jmp short s(EBF0) to polecenie modyfikujące adres IP, po wykonaniu polecenia EBF0, IP=IP+(oznaczenie s-s0)=0008, wskazując na jednostkę kod:0008. 4. Krok 4: Przeczytaj treść kodu jednostki:0008. Ponieważ polecenie jmp short s1 (EBF6) w s2 jest kopiowane do jednostki kod:0008~code:0009, po odczytaniu zawartości jednostki, IP=IP+0002=000A 5. Krok 5: Instrukcja jmp short s1 (EBF6) to polecenie zmiany IP, po wykonaniu polecenia EBF6, IP=IP+(oznaczenie s1-oznaczenie s2)=0000, wskazując na jednostkę kod:0000. 6. Krok 6: Program przechodzi do kod:0000, aby wykonać zadanie, czyli normalne zakończenie zostaje zakończone. 3. Dodatek Poprawnie przeanalizuj ten kod: Musisz zrozumieć proces wykonywania instrukcji CPU i skrótu jmp? (obliczane przez modyfikację IP). Ponadto kluczowym elementem jest kod uzupełnienia wyniku obliczeń offsetu. Po analizie tego pozornie nienormalnego kodu zyskałem głębsze zrozumienie instrukcji JMP w asemblerze.
|