Asembler x86/Jak używać debuggera ALD: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
DrJolo (dyskusja | edycje)
DrJolo (dyskusja | edycje)
Linia 322:
ald>
</source>
 
Przede wszystkim interesują nas zawartości rejestrów EAX, EBX oraz EDX, gdyż tylko one są argumentami powyższej instrukcji. Dzielna znajduje się w rejestrach EDX:EAX, natomiast dzielnik umieszczony jest w rejestrze EBX. Na tym etapie nie widać żadnych potencjalnych problemów, możemy więc kontynuować wykonanie programu krok po kroku używając polecenia '''n''':
 
<source lang=text>
ald> n
eax = 0x00000000 ebx = 0x0000000A ecx = 0x0000000A edx = 0x00000007
esp = 0xBFC9251C ebp = 0x00000000 esi = 0x00000000 edi = 0x00000000
ds = 0x007B es = 0x007B fs = 0x0000 gs = 0x0000
ss = 0x007B cs = 0x0073 eip = 0x080480A8 eflags = 0x00000246
 
Flags: PF ZF IF
 
 
080480A8 81C230000000 add edx, 0x30
ald>
</source>
 
Dzielenie całkowite zostało wykonane poprawnie. Wynik dzielenia znajduje się w rejestrze EAX, natomiast reszta z dzielenia w rejestrze EDX. Być może w następnym przebiegu pętli ujawnią się jakieś problemy. Kontynuujemy zatem wykonanie programu poleceniem '''continue''' (lub w skrócie '''c'''):
 
<source lang=text>
ald> c
Breakpoint 1 encountered at 0x080480A6
eax = 0x00000000 ebx = 0x0000000A ecx = 0x00000009 edx = 0x00000037
esp = 0xBFC9251C ebp = 0x00000000 esi = 0x00000000 edi = 0x00000000
ds = 0x007B es = 0x007B fs = 0x0000 gs = 0x0000
ss = 0x007B cs = 0x0073 eip = 0x080480A6 eflags = 0x00000206
 
Flags: PF IF
 
 
080480A6:<N1> F7F3 div ebx
ald>
</source>
 
Na pierwszy rzut oka tym razem również wszystko jest w porządku. Jednak po wnikliwej analizie zawartości rejestrów zauważymy, że w rejestrze EDX znajdują się pozostałości z poprzedniego obiegu pętli. Aby uniknąć błędnych wyników, należy poprawić kod tak, aby zerowanie rejestru EDX przeprowadzać na początku każdego obiegu pętli przed wykonaniem operacji dzielenia. Spróbujemy mimo wszystko kontynuować działanie programu krok po kroku:
 
<source lang=text>
ald> n
 
Program received signal SIGFPE (Arithmetic exception)
Location: 0x080480A6
eax = 0x00000000 ebx = 0x0000000A ecx = 0x00000009 edx = 0x00000037
esp = 0xBFBA9ADC ebp = 0x00000000 esi = 0x00000000 edi = 0x00000000
ds = 0x007B es = 0x007B fs = 0x0000 gs = 0x0000
ss = 0x007B cs = 0x0073 eip = 0x080480A6 eflags = 0x00010206
 
Flags: PF IF RF
 
 
080480A6:<N1> F7F3 div ebx
ald>
</source>
 
Widzimy, że operacja dzielenia nie została wykonana i zgłoszony jest wyjątek za pomocą sygnału ''SIGFPE''. Kolejna próba wykonania operacji skończy się zamknięciem programu wraz ze zwróceniem kodu błędu:
 
<source lang=text>
ald> n
Program terminated with signal SIGFPE (Arithmetic exception)
ald>
</source>
 
Po wprowadzeniu stosownych poprawek prawidłowy kod źródłowy będzie miał postać:
 
<source lang=asm>
;;
;; Wypisuje zawartość EAX w systemie dziesiętnym
;;
 
segment .text
global _start
_start:
mov eax,0x0007
call _printEAXdecimal
;wyjscie
mov eax,1
mov ebx,5
int 0x80
 
 
 
segment .data
msg db ' '
 
segment .text
 
_printEAXdecimal:
push edx
push ecx
push ebx
push eax
 
mov ebx,10
mov ecx,10
N1:
xor edx,edx
div ebx
add edx,48
dec ecx
mov [msg+ecx],dl
cmp ecx,0
jne N1
 
mov eax,4
mov ebx,1
mov ecx,msg
mov edx,10
int 0x80
 
pop eax
pop ebx
pop ecx
pop edx
ret
</source>
 
Po udanej kompilacji i linkowaniu możemy uruchomić program:
 
<source lang=text>
user@myhost:~$ ./decimalPrint
0000000007user@myhost:~$
</source>
 
Możemy także przetestować go z innymi wartościami rejestru EAX. W tym celu zmieniamy linijkę kodu:
 
<source lang=asm>
mov eax,0x0007
</source>
 
na inną przykładową:
 
<source lang=asm>
mov eax,0xffffffff
</source>
 
Po udanej kompilacji i linkowaniu możemy znowu uruchomić program:
 
<source lang=text>
user@myhost:~$ ./decimalPrint
4294967295user@myhost:~$
</source>
 
Skoro odnaleźliśmy i usunęliśmy przyczynę błędu wykonania, możemy przystąpić do rozbudowy naszego programu tak, aby pomijane były zera wiodące, ewentualnie aby za wyświetlaną liczbą umieszczany był dodatkowo znak końca linii.