Quindi sto imparando l'assembly x86 Linux con la sintassi NASM (Oh dio, non di nuovo questo, state tutti pensando). Sto provando a creare una subroutine che stamperà semplicemente il valore in EAX sullo stdout. Il codice viene eseguito ed esce senza errori, ma non viene stampato nulla. Non riesco a capire perché. Prima di tutto, qui è il file su cui sto lavorando in:Linux x86 NASM - Subroutine: stampa un dword da EAX
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
Questo è chiamato dal mio file principale, che assomiglia a questo (questo è probabilmente irrilevante, a meno che non mi manca qualcosa di drastico).
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
è solo un'altra subroutine che definisce e stampa un ritorno a capo. Questo funziona correttamente e stampa una nuova riga come previsto.
Il problema ha a che fare con il parametro di lunghezza per la mia chiamata sys_write
? Sto dando 2, che è la dimensione di un dword
, che è la dimensione sia del registro EAX
sia della mia etichetta to_print
, che ho riservato con resd 1
. Ho provato a cambiare la lunghezza a 1, 4, 8, 16 e 32 per disperazione ... Niente ha funzionato.
EDIT: Per chi sta chiedendo, ecco come ho corretto il codice: (Io porrò asterischi su linee che ho cambiato):
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
In sostanza, ecx
deve contenere l'indirizzo del blocco che si desidera stampare, NON il valore stesso. Come indicato nella risposta selezionata, questo sarà solo funziona se eax è compreso nell'intervallo 0-9.
EDIT 2: Quindi ero un po 'confuso riguardo il 2 ° parametro per sys_write (quello memorizzato in edx
). Penso che si riferisca solo a un numero di byte. Quindi per uno dword
, come stavo usando, sarebbe corretto usare 4 lì, perché una doppia parola è di 4 byte o 32 bit. Immagino che abbia funzionato perché x86 è little-endian. Così nella memoria, il valore esadecimale di to_print
sarebbe simile a questa:
90 00 00 00
E con una lunghezza fornito di due, sys_write ottiene:
90 00
Quindi il valore non lo fa per fortuna essere corrotto
poi ho cambiato il codice per memorizzare to_print
come un byte, invece, utilizzando resb 1
e accedere utilizzando byte
invece di dword
... Un byte è bene qui, perché so che non ho intenzione di dare to_print
un valore superiore 9.
Grazie mille! La tua risposta è stata molto utile. Sì, mi rendo conto che funzionerà solo da 0 a 9, sto solo cercando di ottenere alcune delle nozioni di base. Forse inizierò con qualche business array-pointer int-to-string alla fine. Modificherò il mio post con il codice aggiornato, per chiunque altro voglia sapere. –
Ti applaudo per aver affrontato il linguaggio dell'assemblaggio e ti auguro buona fortuna. A proposito, la tua domanda è una domanda prototipo di SO buono. Hai fornito esattamente le informazioni necessarie, hai mostrato ciò che avevi provato e hai fatto una domanda specifica. +1 –
Grazie ancora, e classificherei sicuramente la tua risposta come una risposta "prototipo buono SO". Ho deciso di imparare alcuni assembly x86 dopo un gigantesco tracollo di segfault/pointer C++ in un progetto su cui sto lavorando. Prima di tutto, è un bel diversivo, in secondo luogo, voglio sapere cosa sto * effettivamente * facendo scrivendo il codice. –