Cómo imprimir un número en el ensamblado NASM?

Supongamos que tengo un número entero en un registro, ¿cómo puedo imprimirlo? ¿Puedes mostrar un código de ejemplo simple?

Ya sé cómo imprimir una cadena como “hola, mundo”.

Estoy desarrollando en Linux.

Si ya está en Linux, no es necesario que haga la conversión usted mismo. Solo use printf en su lugar:

 ; ; 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 

Tenga en cuenta que printf utiliza la convención de llamadas cdecl, por lo que debemos restaurar el puntero de stack después, es decir, agregar 4 bytes por parámetro pasado a la función.

Tienes que convertirlo en una cadena; si estás hablando de números hexadecimales, es bastante fácil. Cualquier número puede ser representado de esta manera:

 0xa31f = 0xf * 16^0 + 0x1 * 16^1 + 3 * 16^2 + 0xa * 16^3 

Entonces, cuando tenga este número, tendrá que dividirlo como lo he mostrado y luego convertir cada “sección” a su equivalente ASCII.
Conseguir las cuatro partes se hace fácilmente con un poco de magia, en particular con un cambio a la derecha para mover la parte que nos interesa en los primeros cuatro bits, y luego el resultado con 0xf para aislarlo del rest. Esto es lo que quiero decir (supongamos que queremos tomar el 3):

 0xa31f -> shift right by 8 = 0x00a3 -> AND with 0xf = 0x0003 

Ahora que tenemos un número único, debemos convertirlo en su valor ASCII. Si el número es menor o igual a 9, podemos simplemente agregar el valor ASCII de 0 (0x30), si es mayor que 9, tenemos que usar el valor ASCII de un (0x61).
Aquí está, ahora solo tenemos que 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 

PD: Sé que esto es código de 16 bits, pero todavía uso el viejo TASM: P

PPS: esta es la syntax Intel, la conversión a syntax AT & T no es difícil, mira aquí .

Linux x86-64 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 

Entonces:

 nasm -f elf64 main.asm gcc main.o ./a.out 

Los “puntos fuertes” de la convención de llamadas de System V AMD64 ABI:

  • sub rsp, 8 : ¿Cómo escribir el lenguaje ensamblador hello world program para 64 bits Mac OS X usando printf?
  • mov rax, 1 : ¿Por qué% eax se pone a cero antes de una llamada a printf?

Si quiere hexadecimal sin la biblioteca C: https://stackoverflow.com/a/32756303/895245

Depende de la architecture / entorno que esté utilizando.

Por ejemplo, si quiero mostrar un número en Linux, el código ASM será diferente del que usaría en Windows.

Editar:

Puede consultar esto para obtener un ejemplo de conversión.

Soy relativamente nuevo en ensamblaje, y obviamente esta no es la mejor solución, pero está funcionando. La función principal es _iprint, primero comprueba si el número en eax es negativo, e imprime un signo menos si es así, de lo que procede al imprimir los números individuales llamando a la función _dprint para cada dígito. La idea es la siguiente, si tenemos 512 que es igual a: 512 = (5 * 10 + 1) * 10 + 2 = Q * 10 + R, entonces podemos encontrar el último dígito de un número dividiéndolo por 10, y obteniendo el recordatorio R, pero si lo hacemos en un bucle, los dígitos estarán en orden inverso, entonces usaremos la stack para empujarlos, y después de eso cuando los escribamos en stdout aparecerán en el orden correcto.

 ; 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 ; restre 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 ; край