如何在装配NASM中打印数字?

AR8*_*R89 15 linux x86 assembly nasm

假设我在寄存器中有一个整数,我该如何打印?你能展示一个简单的示例代码吗?

我已经知道如何打印一个字符串,如"你好,世界".

我正在Linux上开发.

Bla*_*ear 13

你必须用字符串转换它; 如果你在谈论十六进制数字,这很容易.任何数字都可以这样表示:

0xa31f = 0xf * 16^0 + 0x1 * 16^1 + 3 * 16^2 + 0xa * 16^3
Run Code Online (Sandbox Code Playgroud)

因此,当你有这个数字时,你必须像我展示的那样拆分它,然后将每个"部分"转换为它的ASCII等价物.
获得这四个部分很容易完成一些魔术,特别是右移以在前四位移动我们感兴趣的部分,然后用0xf将结果与其余部分隔离.这就是我的意思(我们希望采用3):

0xa31f -> shift right by 8 = 0x00a3 -> AND with 0xf = 0x0003
Run Code Online (Sandbox Code Playgroud)

现在我们只有一个数字,我们必须将其转换为ASCII值.如果数字小于或等于9,我们可以添加0的ASCII值(0x30),如果它大于9,我们必须使用ASCII值(0x61).
在这里,现在我们只需编写代码:

    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
Run Code Online (Sandbox Code Playgroud)

PS:我知道这是16位代码,但我仍然使用旧的TASM:P

PPS:这是英特尔语法,虽然转换为AT&T语法并不困难,但请看这里.


Mar*_*tin 13

如果您已经在Linux上,则无需自行进行转换.只需使用printf代替:

;
; 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
Run Code Online (Sandbox Code Playgroud)

请注意,printf使用cdecl调用约定,因此我们需要在之后恢复堆栈指针,即每个传递给函数的参数添加4个字节.


Cir*_*四事件 8

带有 printf 的 Linux x86-64

主程序

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: "%#x\n" 
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
Run Code Online (Sandbox Code Playgroud)

GitHub 上游.

然后:

nasm -f elf64 -o main.o main.asm
gcc -no-pie -o main.out main.o
./main.out
Run Code Online (Sandbox Code Playgroud)

输出:

0x12345678
Run Code Online (Sandbox Code Playgroud)

笔记:

如果你想要没有 C 库的十六进制用汇编打印十六进制数字

在 Ubuntu 18.10、NASM 2.13.03 上测试。


归档时间:

查看次数:

29599 次

最近记录:

6 年,10 月 前