Supponiamo di avere un numero intero in un registro, come posso stamparlo? Puoi mostrare un semplice codice di esempio?Come stampare un numero nell'assemblaggio NASM?
So già come stampare una stringa come "ciao, mondo".
Sto sviluppando su Linux.
Supponiamo di avere un numero intero in un registro, come posso stamparlo? Puoi mostrare un semplice codice di esempio?Come stampare un numero nell'assemblaggio NASM?
So già come stampare una stringa come "ciao, mondo".
Sto sviluppando su Linux.
Se si è già su Linux, non è necessario effettuare la conversione da soli. Basta usare printf invece:
;
; assemble and link with:
; nasm -f elf printf-test.asm && gcc -m32 -o printf-test printf-test.o
;
section .text
global main
extern printf
main:
mov eax, 0xDEADBEEF
push eax
push message
call printf
add esp, 8
ret
message db "Register = %08X", 10, 0
Nota che printf
utilizza il cdecl calling convention quindi abbiamo bisogno di ripristinare lo stack pointer dopo, vale a dire aggiungere 4 byte per il parametro passato alla funzione.
Grazie, sembra essere quello che stavo cercando. Sai se funziona anche su Mac os X? – AR89
Come compilarlo su 64 -bit? –
@ FigenGüngör http://stackoverflow.com/a/32853546/895245 –
Dipende dall'architettura/dall'ambiente che si sta utilizzando.
Ad esempio, se voglio visualizzare un numero su linux, il codice ASM sarà diverso da quello che userei su Windows.
Edit:
È possibile fare riferimento a THIS per un esempio di conversione.
Devi convertirlo in una stringa; se stai parlando di numeri esadecimali è piuttosto facile. Qualsiasi numero può essere rappresentato in questo modo:
0xa31f = 0xf * 16^0 + 0x1 * 16^1 + 3 * 16^2 + 0xa * 16^3
Quindi, quando si dispone di questo numero bisogna dividerla come ho mostrato poi convertire ogni "sezione" al suo equivalente ASCII.
Ottenere le quattro parti è facile con un po 'di magia, in particolare con uno spostamento verso destra per spostare la parte a cui siamo interessati nei primi quattro bit E il risultato con 0xf per isolarlo dal resto. Ecco quello che voglio dire (soppose vogliamo prendere la 3):
0xa31f -> shift right by 8 = 0x00a3 -> AND with 0xf = 0x0003
Ora che abbiamo un unico numero che dobbiamo convertirlo in suo valore ASCII. Se il numero è minore o uguale a 9, possiamo semplicemente aggiungere il valore ASCII di 0 (0x30), se è maggiore di 9 dobbiamo usare il valore ASCII di una (0x61).
Qui è, ora non ci resta che codificarlo:
mov si, ??? ; si points to the target buffer
mov ax, 0a31fh ; ax contains the number we want to convert
mov bx, ax ; store a copy in bx
xor dx, dx ; dx will contain the result
mov cx, 3 ; cx's our counter
convert_loop:
mov ax, bx ; load the number into ax
and ax, 0fh ; we want the first 4 bits
cmp ax, 9h ; check what we should add
ja greater_than_9
add ax, 30h ; 0x30 ('0')
jmp converted
greater_than_9:
add ax, 61h ; or 0x61 ('a')
converted:
xchg al, ah ; put a null terminator after it
mov [si], ax ; (will be overwritten unless this
inc si ; is the last one)
shr bx, 4 ; get the next part
dec cx ; one less to do
jnz convert_loop
sub di, 4 ; di still points to the target buffer
PS: So che questo è a 16 bit di codice, ma ho ancora utilizzare il vecchio TASM: P
PPS: questo è sintassi Intel, la conversione in AT & T sintassi non è difficile però, guarda here.
x86-64 Linux con printf
extern printf, exit
section .data
format db "%x", 10, 0
section .text
global main
main:
sub rsp, 8
mov rsi, 0x12345678
mov rdi, format
xor rax, rax
call printf
mov rdi, 0
call exit
Poi:
nasm -f elf64 main.asm
gcc main.o
./a.out
I "punti duri" del System V AMD64 ABI convenzione di chiamata:
sub rsp, 8
: How to write assembly language hello world program for 64 bit Mac OS X using printf?mov rax, 1
: Why is %eax zeroed before a call to printf?Se si desidera esadecimale senza la libreria C: https://stackoverflow.com/a/32756303/895245
Sono relativamente nuovo per il montaggio, e questo, ovviamente, non è la soluzione migliore, ma sta funzionando. La funzione principale è _iprint, in primo luogo controlla se il numero in eax è negativo e stampa un segno meno se così, che procede stampando i singoli numeri chiamando la funzione _dprint per ogni cifra. L'idea è la seguente, se abbiamo 512 di quanto sia uguale a: 512 = (5 * 10 + 1) * 10 + 2 = Q * 10 + R, quindi possiamo trovare l'ultima cifra di un numero dividendolo per 10, e ottenendo il promemoria R, ma se lo facciamo in un ciclo di cifre saranno in un ordine inverso , quindi usiamo lo stack per spingerli, e dopo che quando scrivendoli a stdout vengono visualizzati in ordine corretto.
; Build : nasm -f elf -o baz.o baz.asm
; ld -m elf_i386 -o baz baz.o
section .bss
c: resb 1 ; character buffer
section .data
section .text
; writes an ascii character from eax to stdout
_cprint:
pushad ; push registers
mov [c], eax ; store ascii value at c
mov eax, 0x04 ; sys_write
mov ebx, 1 ; stdout
mov ecx, c ; copy c to ecx
mov edx, 1 ; one character
int 0x80 ; syscall
popad ; pop registers
ret ; bye
; writes a digit stored in eax to stdout
_dprint:
pushad ; push registers
add eax, '0' ; get digit's ascii code
mov [c], eax ; store it at c
mov eax, 0x04 ; sys_write
mov ebx, 1 ; stdout
mov ecx, c ; pass the address of c to ecx
mov edx, 1 ; one character
int 0x80 ; syscall
popad ; pop registers
ret ; bye
; now lets try to write a function which will write an integer
; number stored in eax in decimal at stdout
_iprint:
pushad ; push registers
cmp eax, 0 ; check if eax is negative
jge Pos ; if not proceed in the usual manner
push eax ; store eax
mov eax, '-' ; print minus sign
call _cprint ; call character printing function
pop eax ; restore eax
neg eax ; make eax positive
Pos:
mov ebx, 10 ; base
mov ecx, 1 ; number of digits counter
Cycle1:
mov edx, 0 ; set edx to zero before dividing otherwise the
; program gives an error: SIGFPE arithmetic exception
div ebx ; divide eax with ebx now eax holds the
; quotent and edx the reminder
push edx ; digits we have to write are in reverse order
cmp eax, 0 ; exit loop condition
jz EndLoop1 ; we are done
inc ecx ; increment number of digits counter
jmp Cycle1 ; loop back
EndLoop1:
; write the integer digits by poping them out from the stack
Cycle2:
pop eax ; pop up the digits we have stored
call _dprint ; and print them to stdout
dec ecx ; decrement number of digits counter
jz EndLoop2 ; if it's zero we are done
jmp Cycle2 ; loop back
EndLoop2:
popad ; pop registers
ret ; bye
global _start
_start:
nop ; gdb break point
mov eax, -345 ;
call _iprint ;
mov eax, 0x01 ; sys_exit
mov ebx, 0 ; error code
int 0x80 ; край
È possibile aggiungere '0' e memorizzare le cifre in un buffer mentre le si produce. Utilizzare 'dec' spostare l'indicatore verso il basso. Quando hai finito, hai un puntatore all'ultima cifra memorizzata, quindi puoi passarlo a 'sys_write()' (insieme al numero di cifre) .Questo è molto più efficiente di una chiamata di sistema separata per ogni byte e in realtà non richiede più codice. È facile allocare un buffer sufficientemente lungo da contenere la più lunga stringa di cifre possibile e iniziare alla fine, perché si conosce il numero di cifre decimali 2^32. –
related: Ho scritto un intero -> loop di stringhe come parte di questa [risposta codice-golf Fibonacci a precisione estesa] (https://codegolf.stackexchange.com/questions/133618/extreme-fibonacci/135618#135618). Vedi il ciclo '.toascii_digit:'. Ovviamente, questo è ottimizzato per le dimensioni, quindi usa un lento 'div' [invece di un trucco multiplo] (https://stackoverflow.com/questions/41183935/why-does-gcc-use-multiplication-by-a- strana-numero-in-attuazione-integer-divi). –
Grazie, è decisamente preferibile che chiamare sys_write per ogni cifra :) – baz
Specificare il sistema operativo in cui verrà eseguito il programma. –
Correlato: [convertire un numero intero in una stringa decimale ASCII in un buffer nello stack e stamparlo con la chiamata di sistema 'write' di Linux] (https://stackoverflow.com/a/46301894/224132), non usando' printf' o qualsiasi altra funzione. Con commenti e spiegazioni. –