Linux x86 NASM - Podprogram: Wydrukuj dword z EAX
Uczę się więc montażu Linuxa x86 ze składnią NASM (O Boże, nie to znowu, wszyscy myślicie). Próbuję utworzyć podprogram, który po prostu wydrukuje wartość w EAX na standardowe wyjście. Kod działa i kończy się bez błędu, ale nic nie drukuje. Nie mogę zrozumieć dlaczego. Po pierwsze, oto plik, w którym pracuję:
segment .bss
to_print: resd 1
segment .text
global print_eax_val
print_eax_val: ; (top)
push dword ebx ;Stack: edx
push dword ecx ; ecx
push dword edx ; ebx
; (bot)
mov ecx,eax ;ecx = eax
mov [to_print],ecx ;to_print = ecx
mov eax, 4 ;sys_write
mov ebx, 1 ;to stdout
add ecx, 47 ;add 47 for ASCII numbers
mov edx, 2 ;double word = 2 bytes
int 0x80
mov eax, [to_print] ;eax = original val
pop edx ;pop the registers back from the stack
pop ecx
pop ebx ;Stack: empty
ret
Jest to wywoływane z mojego głównego pliku, który wygląda tak (prawdopodobnie nie ma to znaczenia, chyba że brakuje mi czegoś drastycznego).
segment .data
hello db "Hello world!", 0
newline db 0xA
len equ $ - hello
len2 equ $ - newline
segment .text
extern print_nl
extern print_eax_val
global main
main:
enter 0,0
call print_nl
mov eax, 1
call print_eax_val
mov ebx, 0 ;exit code = 0 (normal)
mov eax, 1 ;exit command
int 0x80 ;ask kernel to quit
print_nl
to kolejny podprogram, który definiuje i drukuje nową linię. Uruchomi się pomyślnie i wydrukuje nową linię zgodnie z oczekiwaniami.
Czy problem ma związek z parametrem długości dla mojegosys_write
połączenie? Daję mu 2, który ma rozmiar adword
, który jest wielkością obuEAX
zarejestruj się i mójto_print
etykieta, którą zarezerwowałemresd 1
. Próbowałem zmienić długość na 1, 4, 8, 16 i 32 z desperacji ... Nic nie działało.
EDYTOWAĆ: Dla każdego, kto się zastanawia, oto jak naprawiłem kod: (wstawię gwiazdki w liniach, które zmieniłem):
segment .bss
to_print: resd 1
segment .text
global print_eax_val
print_eax_val: ; (top)
push dword ebx ;Stack: edx
push dword ecx ; ecx
push dword edx ; ebx
; (bot)
mov ecx,eax ;ecx = eax
mov [to_print],ecx ;to_print = ecx
**** add dword [to_print], 48
mov eax, 4 ;sys_write
mov ebx, 1 ;to stdout
**** mov ecx, to_print
mov edx, 2
int 0x80
**** sub dword [to_print], 48
mov eax, [to_print] ;eax = original val
pop edx ;pop the registers back from the stack
pop ecx
pop ebx ;Stack: empty
ret
Gruntownie,ecx
musi zawieraćadres bloku, który chcesz wydrukować, NIE samą wartość. Jak zaznaczono w wybranej odpowiedzi, będzie totylko działa, jeśli eax jest w zakresie 0-9.
EDYCJA 2: Byłem trochę zmieszany co do drugiego parametru dla sys_write (tego przechowywanego wedx
). Myślę, że odnosi się to po prostu do liczby bajtów. Więc nadword
, tak jak użyłem, właściwe byłoby użycie 4, ponieważ podwójne słowo ma 4 bajty lub 32 bity. Zgaduję, że zadziałało, ponieważ x86 jest małym endianem. Tak więc w pamięci wartość szesnastkowato_print
wyglądałoby to tak:
90 00 00 00
A przy podanej długości dwóch sys_write pobiera:
90 00
Więc wartość na szczęście nie ulega uszkodzeniu.
Później zmieniłem kod do przechowywaniato_print
zamiast bajtu, używającresb 1
i dostęp do niego za pomocąbyte
zamiastdword
... Tu jest bajt, bo wiem, że nie damto_print
wartość powyżej 9.