2011-11-07 8 views
6

Questa operazione deve essere eseguita in assembly puro (ovvero senza librerie o chiamate a C).Uscita di numeri interi in assembly su Linux

Comprendo l'essenza del problema: è necessario dividere il numero intero per 10, convertire il resto di una cifra in ASCII, emetterlo e quindi ripetere il processo con il quoziente.

Ma per qualche motivo, non funziona. Sto usando NASM su x86.

Ecco quello che ho fino ad ora (non emette nulla, ma non genera errori assembler o):

; integer to output is stored in eax 
mov ecx, 10 ; for base 10 

loop: 
div ecx ;EAX contains the quotient, EDX the remainder 

; Do something to EDX to convert it to ASCII, not sure if this is correct 
add edx, '0' 

push eax ;We'll be playing with EAX to output EDX, save EAX to the stack 

mov eax, 4    ; sys_write 
mov ebx, 1    ; to STDOUT 
mov ecx, edx 
mov edx, 1 
int 0x80 

pop eax ;restore EAX 

cmp eax, 0 ;If EAX is 0, our job is done 
jnz loop 

Ci sono una serie di domande simile a questo (vale a dire, this e this), ma mi sono perso nell'implementazione. This question (per DOS) è stato anche utile, ma sono ancora confuso.

Mi manca qualcosa qui. Pensieri?

+0

Non vedo la costante '10' da nessuna parte in questo codice, che sarebbe necessaria per stampare le cifre decimali. (È necessario ripetere ripetutamente 'div' e' mod' con '10', memorizzare le cifre, invertirle e produrle, oppure passare prima dalla 'big end' e dividere per' 100.000.000', quindi per '10.000.000' , ecc., ma potrebbe non essere meno complicato del metodo store-and-reverse.) – sarnold

+0

@sarnold Hai dimenticato di includere una riga nella parte superiore. Modificato la mia domanda per aggiungerla. –

+0

Eccellente! Grazie per l'aggiornamento. – sarnold

risposta

3

Ci sono almeno altri due problemi. al di là della corruzione del ecx che @sarnold menzionato:

  1. div ecx divide il valore a 64 bit edx:eax da ecx, quindi è necessario assicurarsi di aver impostato edx-0 prima della divisione.

  2. Il secondo argomento della chiamata di sistema write (in ecx) deve essere un puntatore a un buffer contenente il carattere che si desidera stampare, non il carattere stesso.

Un modo per risolvere il secondo problema è quello di spingere il registro contenente il carattere che si desidera stampare sullo stack, e quindi assegnare lo stack pointer esp a ecx (i punti di puntatore stack l'elemento più recente spinto e x86 memorizza valori little-endian, quindi il primo byte è il basso 8 bit). per esempio.

push edx   ; save value on stack 
mov eax, 4  ; sys_write 
mov ebx, 1  ; to STDOUT 
mov ecx, esp ; first byte on stack 
mov edx, 1  ; length = one byte 
int 0x80 
pop edx   ; remove what we pushed (or "add esp, 4" would do just as well here; 
       ;      we don't need the actual value again) 

Questo dovrebbe essere sufficiente per ottenere qualche uscita ...

(Ma a quel punto, si potrebbe notare una "caratteristica" del vostro algoritmo, e vuole ri-pensare a come si memorizzano le cifre che sono prodotti dalla divisione!)

+0

Questa è una grande spiegazione, grazie per averla chiarita. Come suggerisci, capisco perché questo algoritmo stampa gli interi al contrario. Qualche idea su aggiustarlo? –

+1

Riservare un po 'di spazio per le cifre (il numero intero senza segno a 32 bit è 4294967295, quindi 10 byte è sufficiente), in una sezione di dati (ad esempio usando la direttiva 'resb') o nello stack (basta sottrarre da' esp' , ma assicurati di sottrarre un multiplo di 4 per mantenere allineato correttamente lo stack). Quindi, memorizza le cifre nel buffer andando avanti, quindi passa al di sopra del buffer nella stampa inversa di ciascun carattere; o (meglio?) memorizza le cifre nel buffer partendo dall'ultimo byte del buffer e lavorando all'indietro, quindi puoi scrivere tutte le cifre con un singolo syscall 'scrivi'. –

2

impostato correttamente ecx-10 in cima alla vostra routine, ma sovrascrivere ecx tardi:

mov eax, 4    ; sys_write 
mov ebx, 1    ; to STDOUT 
mov ecx, edx ;;; oops -- lost the 10 
mov edx, 1 
int 0x80 

Provare a spostare la linea loop in uno, in modo ecx viene re-inizializzato per 10 ogni volta attraverso il ciclo .

+0

Buona cattura, risolto. Non ho ancora ricevuto alcun output, suppongo che aggiungendo edx, '0' non converta correttamente la singola cifra in decimale. –

Problemi correlati