Saltar al contenido

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

Posterior a de una larga compilación de datos pudimos solucionar este disgusto que pueden tener muchos de nuestros usuarios. Te brindamos la respuesta y nuestro deseo es servirte de mucha ayuda.

Solución:

Si ya está en Linux, no es necesario que haga la conversión usted mismo. Simplemente 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 usa la convención de llamada cdecl, por lo que necesitamos restaurar el puntero de la pila después, es decir, agregar 4 bytes por parámetro pasado a la función.

Tienes que convertirlo en un string; si estás hablando de números hexadecimales, es bastante fácil. Cualquier número se puede representar de esta manera:

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

Entonces, cuando tenga este número, debe dividirlo como se muestra y luego convertir cada “sección” a su equivalente ASCII.
Obtener las cuatro partes se hace fácilmente con un poco de magia, en particular con un desplazamiento a la derecha para mover la parte que nos interesa en los primeros cuatro bits y luego Y el resultado con 0xf para aislarlo del resto. 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 solo número, tenemos que convertirlo a su valor ASCII. Si el número es menor o igual a 9, simplemente podemos agregar el valor ASCII de 0 (0x30), si es mayor que 9, debemos usar el valor ASCII de a (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 este es un código de 16 bits, pero sigo usando el antiguo TASM: P

ppd: esta es la sintaxis de Intel, sin embargo, la conversión a la sintaxis de AT&T no es difícil, mire aquí.

Linux x86-64 con impresión

principal.asm

default rel            ; make [rel format] the default, you always want this.
extern printf, exit    ; NASM requires declarations of external symbols, unlike GAS
section .rodata
    format db "%#x", 10, 0   ; C 0-terminated string: "%#xn" 
section .text
global main
main:
    sub   rsp, 8             ; re-align the stack to 16 before calling another function

    ; Call printf.
    mov   esi, 0x12345678    ; "%x" takes a 32-bit unsigned int
    lea   rdi, [rel format]
    xor   eax, eax           ; AL=0  no FP args in XMM regs
    call  printf

    ; Return from main.
    xor   eax, eax
    add   rsp, 8
    ret

GitHub en sentido ascendente.

Entonces:

nasm -f elf64 -o main.o main.asm
gcc -no-pie -o main.out main.o
./main.out

Producción:

0x12345678

Notas:

  • sub rsp, 8: ¿Cómo escribir el programa hello world en lenguaje ensamblador para Mac OS X de 64 bits usando printf?
  • xor eax, eax: ¿Por qué %eax se pone a cero antes de una llamada a printf?
  • -no-pie: plano call printf no funciona en un ejecutable PIE (-pie), el enlazador solo genera automáticamente un código auxiliar PLT para ejecutables de estilo antiguo. Tus opciones son:

    • call printf wrt ..plt llamar a través del PLT como tradicional call printf

    • call [rel printf wrt ..got] no usar un PLT en absoluto, como gcc -fno-plt.

    Como la sintaxis de GAS call *[email protected](%rip).

    Cualquiera de estos también está bien en un ejecutable que no sea PIE, y no causa ninguna ineficiencia a menos que esté vinculando estáticamente libc. En ese caso call printf puede resolver un call rel32 directamente a libc, porque el desplazamiento de su código a la función libc se conocería en static tiempo de enlace.

    Ver también: No se puede llamar a la función de biblioteca estándar de C en Linux de 64 bits desde el código ensamblador (yasm)

Si desea hexadecimal sin la biblioteca C: Impresión de dígitos hexadecimales con ensamblaje

Probado en Ubuntu 18.10, NASM 2.13.03.

Tienes la posibilidad recomendar este enunciado si te fue útil.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *