在 nasm 程序集中调用 scanf 时如何使用存储在寄存器中的数据
How to use data stored in register when calling scanf in nasm assembly
在下文中,我尝试获取用户的选择并使用它来调用其他功能。我将选择推入堆栈,然后推入格式行,然后调用 scanf,但我似乎无法使用输入的内容。
;nasm -f elf64 fib.asm -o fib.o
;gcc -S -masm=intel fib.c -o fib.s
;./fib
bits 64
global main
extern puts
extern printf
extern scanf
section .data
errormsg: db 'Invalid Input. Enter N,F, or X',0x0D,0x0a,0
numequalsmsg: db 'Number equals: '
LC2: db "%d",0
menuprompt: db 0x0D,0x0a,'Enter N to enter an integer from 0 to 20',0x0D,0x0a,'Enter F to display the first N+1 numbers (beginning with zero) on the console',0x0D,0x0a,'Enter X to quit the program',0x0D,0x0a,0
choicemsg: db "Your Choice: ",0
LC5: db "%s",0
enterintmsg: db "Enter and integer 0-20: ",0
enternummsg: db 'Enter a valid number between 0 and 20',0x0D,0x0a,0
LC8: db " , ",0
LC9: db 'Success!',0x0D,0x0a,0
LC10: db 'In L10!',0x0D,0x0a,0
LC11: db 'In L12!',0x0D,0x0a,0
LC13: db 'In compare to zero section',0x0D,
value: dw 0
choice: dw 0
section .text
main:
menu:
push rbp
mov rbp, rsp
sub rsp, 16
mov edi, menuprompt
call puts ;display menu
mov edi,choicemsg
mov eax, 0
call printf ;display "Your choice: "
;call getn
push choice
push LC5 ;string format
call scanf ;stores input in choice
;GetLInt [choice]
mov ebx, choice
cmp ebx, 78
je correct
correct:
mov edi, ebx
mov eax,0
call printf
(编者注:section.data
只是像 foo.bar:
一样的标签声明,.code
也是如此。可能你想要 section .data
和 section .text
将所有内容都放在只读 .text
部分中,因为您希望 scanf 在那里存储结果。我为您解决了这个问题,因为这个老问题和答案与这些错误无关。)
您使用了错误的约定。显然你知道你应该做什么,因为你调用 printf
没有问题。您也应该使用相同的约定来调用 scanf
- 您使用的堆栈参数传递是 32 位约定,64 位使用寄存器。像这样:
lea rdi, [LC5] ; 1st arg = format
lea rsi, [choice] ; 2nd arg = address of buffer
xor eax, eax ; no xmm registers
call scanf ; stores input in choice
顺便说一句,使用 2 个字节 space 的无约束 %s
是个坏主意。
此外,按照弗兰克所说的去做,即。当你想处理输入时加载一个字节(mov bl, [choice]
)。
在下文中,我尝试获取用户的选择并使用它来调用其他功能。我将选择推入堆栈,然后推入格式行,然后调用 scanf,但我似乎无法使用输入的内容。
;nasm -f elf64 fib.asm -o fib.o
;gcc -S -masm=intel fib.c -o fib.s
;./fib
bits 64
global main
extern puts
extern printf
extern scanf
section .data
errormsg: db 'Invalid Input. Enter N,F, or X',0x0D,0x0a,0
numequalsmsg: db 'Number equals: '
LC2: db "%d",0
menuprompt: db 0x0D,0x0a,'Enter N to enter an integer from 0 to 20',0x0D,0x0a,'Enter F to display the first N+1 numbers (beginning with zero) on the console',0x0D,0x0a,'Enter X to quit the program',0x0D,0x0a,0
choicemsg: db "Your Choice: ",0
LC5: db "%s",0
enterintmsg: db "Enter and integer 0-20: ",0
enternummsg: db 'Enter a valid number between 0 and 20',0x0D,0x0a,0
LC8: db " , ",0
LC9: db 'Success!',0x0D,0x0a,0
LC10: db 'In L10!',0x0D,0x0a,0
LC11: db 'In L12!',0x0D,0x0a,0
LC13: db 'In compare to zero section',0x0D,
value: dw 0
choice: dw 0
section .text
main:
menu:
push rbp
mov rbp, rsp
sub rsp, 16
mov edi, menuprompt
call puts ;display menu
mov edi,choicemsg
mov eax, 0
call printf ;display "Your choice: "
;call getn
push choice
push LC5 ;string format
call scanf ;stores input in choice
;GetLInt [choice]
mov ebx, choice
cmp ebx, 78
je correct
correct:
mov edi, ebx
mov eax,0
call printf
(编者注:section.data
只是像 foo.bar:
一样的标签声明,.code
也是如此。可能你想要 section .data
和 section .text
将所有内容都放在只读 .text
部分中,因为您希望 scanf 在那里存储结果。我为您解决了这个问题,因为这个老问题和答案与这些错误无关。)
您使用了错误的约定。显然你知道你应该做什么,因为你调用 printf
没有问题。您也应该使用相同的约定来调用 scanf
- 您使用的堆栈参数传递是 32 位约定,64 位使用寄存器。像这样:
lea rdi, [LC5] ; 1st arg = format
lea rsi, [choice] ; 2nd arg = address of buffer
xor eax, eax ; no xmm registers
call scanf ; stores input in choice
顺便说一句,使用 2 个字节 space 的无约束 %s
是个坏主意。
此外,按照弗兰克所说的去做,即。当你想处理输入时加载一个字节(mov bl, [choice]
)。