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

Usunięta treść Dodana treść
{{Spis treści}}
optymalizacja
Linia 209:
xorl %edx,%edx
N1:
push %ebx
divl %ebx
shrl %ebx,%eax
addl $48,%ecx
andl %ebx,(%esp)
pop %ebx
addlorl $48,%ecx
decl %ecx
movl %ecx($msg),%dl
orl testl %ecx,%ecx
jnz N1
 
Linia 230 ⟶ 233:
</source>
 
Na pierwszy rzut oka wszystko wydaje się być w porządku. Kompilacja wraz z linkowaniem przebiegła pomyślnie. Próba wykonania programu daje jednak poniższybłąd wynik:wykonania.
 
Program nie miał wykonywać żadnych operacji zmiennoprzecinkowychbitowych. Przypuszczamy jednak, że problem może mieć miejsce w wierszu, w którym wykonujemy operację przesunięcia bitowego w prawo (dzielenia całkowitegoprzez potęgę dwójki):
<source lang=bash>
user@myhost:~$ ./decimalPrint
Floating point exception
user@myhost:~$
</source>
 
Program nie miał wykonywać żadnych operacji zmiennoprzecinkowych. Przypuszczamy jednak, że problem może mieć miejsce w wierszu, w którym wykonujemy operację dzielenia całkowitego:
 
<source lang=asm>
divl shrl %ebx,%eax
</source>
 
Linia 265 ⟶ 262:
# 0804809A BB0A000000 mov ebx, 0xa
# 0804809F B90A000000 mov ecx, 0xa
# 080480A4 31D2 xor edx, edx
# ...
# 080480A6:<N1> F7F3 divshr ebx, eax
# ...
# 080480A8 81C230000000 add or edx, 0x30
# 080480AE 49 dec ecx
# 080480AF 8891D8900408 mov byte [ecx+0x80490d8], dl
# 080480B5 81F900000000 cmptest ecx, 0x0ecx
# 080480BB 75E9 jne +0xe9 (0x80481a6)
# 080480BD B804000000 mov eax, 0x4
Linia 310 ⟶ 309:
 
 
# 080480A6:<N1> F7F3 divshr ebx, eax
</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 rejestrzei 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=bash>
Linia 325 ⟶ 324:
 
 
# 080480A8 81C230000000 addor edx, 0x30
</source>
 
DzieleniePrzesunięcie całkowitebitowe 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=bash>
Linia 341 ⟶ 340:
 
 
# 080480A6:<N1> F7F3 div# shr ebx, eax
</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:.
 
Widzimy, że operacja przesunięcia nie została wykonana.
<source lang=text>
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
</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=bash>
n
# Program terminated with signal SIGFPE (Arithmetic exception)
</source>
 
Po wprowadzeniu stosownych poprawek prawidłowy kod źródłowy będzie miał postać:
Linia 399 ⟶ 377:
N1:
xorl %edx,%edx
pushl %ebx
divl %ebx
addlshrl $48%ebx, %edxeax
andl %ebx, (%esp)
popl %ebx
orl $48,%edx
decl %ecx
movl %ecx(%msg),%eax
orl testl %ecx,%ecx
jnz N1