装配编号更改错误

Assembly number change error

我试图制作一个汇编程序,它取一个数字,然后打印出来。但是当我写 1 时,它写了 4171。为什么,我该如何解决?我正在使用 64 位汇编,我用 nasm -f macho64 scanf.asm 汇编它,并用 gcc -o scanf scanf.o -Wl,-no-pie 链接它。我尝试在扫描宏中的数字周围使用方括号(作为指向变量数字的指针),但是 nasm mach-o 不允许这样做,所以我没有那样做。

这是我的代码:

; lib.asm
extern _printf
extern _scanf

%macro print 2

    push rbp

    mov rdi, %1
    mov rsi, %2

    xor rax, rax

    call _printf

    pop rbp

%endmacro

%macro scan 2

    push rbp

    mov rdi, %1
    mov rsi, %2

    mov rax, 0
    call _scanf

    pop rbp

%endmacro

; scanf.asm

%INCLUDE "lib.asm"

section .bss
    number resd 1
section .text
    global _main
_main:

    print str_out, qst
    scan int_in, number

    print ans, number

exit:

    mov rax, 0x2000001
    xor rbx, rbx
    syscall

section .data
    str_out db '%s', 0xa, 0
    int_in db '%d', 0
    int_out db '%d', 0xa, 0


    qst db 'Enter a number: ', 0

    ans db 'You wrote: %d', 0xa, 0

打印答案的宏不正确。

print ans, number

展开宏后,您将得到:

push rbp

mov rdi, ans      ; RDI = Address of ans
mov rsi, number   ; RSI = Address of number

xor rax, rax

call _printf

pop rbp

我已经评论了上面的两行及其含义。 'You wrote: %d' 的格式字符串表示打印一个整数。您已将 number 的地址传递给它。要解决此问题,请从 number 获取 32 位值并将其放入可用寄存器并将该寄存器传递给您的宏。

为此,您可以替换:

print ans, number

与:

mov eax, [rel number] ; Get the 32-bit number from number and store in eax
                      ; Using RIP relative addressing 
print ans, rax        ; Print the 32-bit word in the bottom half of RAX.

这将扩展为:

push rbp

mov rdi, ans      ; RDI = Address of ans
mov rsi, rax      ; RSI = number to print in RAX

xor rax, rax

call _printf

pop rbp

注意:我们使用 mov eax, [rel number]rel 指令来将默认的绝对地址行为更改为 RIP 相对寻址。如果您希望使用 mov eax, [number] 并避免必须指定 rel,您可以覆盖默认寻址并将 default rel 放在程序集文件的顶部。默认为 default abs.


你可能会问我为什么建议:

mov eax, [rel number]   ; Get the 32-bit number from number and store in eax
                        ; Using RIP relative addressing 
print ans, rax          ; Print the 32-bit word in the bottom half of RAX.

而不是:

print ans, [rel number]

最终宏会尝试这样做:

mov rsi, [rel number]   ; Get the 64-bit number from number and store in RDI

您这样定义 number

number resd 1

这是一个 32 位值,不是 64 位值。 mov rsi, [rel number] 会尝试将 8 个字节从内存位置 number 移动到 RSI。这可能不会在您的示例代码中造成任何问题,但它被认为是错误的形式。尽管它可能有效,但我认为它是一个错误。