Linux 用户输入的Assember提示符不';行不通

Linux 用户输入的Assember提示符不';行不通,linux,assembly,nasm,x86-64,Linux,Assembly,Nasm,X86 64,今天我开始学习在linux上使用NASM进行x86_64汇编。 我成功地编写了一个hello world程序。 现在我想编写另一个简单的程序。 程序应该询问用户的姓名,然后打印“hi[name]”。 我的问题是程序没有要求提供名称。如果我启动程序,它不会打印任何内容,并且会停止,不会出现错误。 这是我的密码: section .data msg1 db "Type in ur Name? ", 10 len1 equ $ - msg1 ; Get the Size o

今天我开始学习在linux上使用NASM进行x86_64汇编。 我成功地编写了一个hello world程序。 现在我想编写另一个简单的程序。 程序应该询问用户的姓名,然后打印“hi[name]”。 我的问题是程序没有要求提供名称。如果我启动程序,它不会打印任何内容,并且会停止,不会出现错误。 这是我的密码:

section .data
    msg1 db "Type in ur Name? ", 10
    len1 equ $ - msg1       ; Get the Size of msg1

    msg2 db "Hi, "
    len2 equ $ - msg2       ;Get the Size of msg2

section .bss
    name resb 16            ;16 Bytes for name

section .text
    global _start

_start:

    ;Call Functions
    call _printMsg1
    call _getName
    call _printMsg2
    call _printName

    mov eax, 60
    mov ebx, 0
    int 0x80


_printMsg1:
    mov eax, 1
    mov ebx, 1
    mov ecx, msg1
    mov edx, len1
    int 0x80
    ret


_printMsg2:
    mov eax, 1
    mov ebx, 1
    mov ecx, msg2
    mov edx, len2
    int 0x80
    ret


_printName:
    mov eax, 1
    mov ebx, 1
    mov ecx, name
    mov edx, 16     ; reserve 16 Bytes for the name
    int 0x80
    ret


_getName:
    mov eax, 0      ;Syscall 0 = User Input
    mov ebx, 0
    mov ecx, name
    mov edx, 16     ;16 Bytes for the name
    int 0x80
    ret
谢谢你的帮助

编辑:我发现了问题。 如果我将以下寄存器替换为: eax至rax ebx到rdi ecx至rsi 从edx到rdx


似乎我使用了假寄存器。

x86-32和x86-64系统调用在数字、寄存器和syscall指令方面非常不同

x86-32系统调用使用
int 80h
,该数字和寄存器:

x86-64系统调用使用
syscall
,并且该数字和寄存器:


您正在使用x86-32系统调用,因此相应地更改
EAX
中的数字。

x86-32和x86-64系统调用在数字、寄存器和syscall指令方面有很大不同

x86-32系统调用使用
int 80h
,该数字和寄存器:

x86-64系统调用使用
syscall
,并且该数字和寄存器:


您正在使用x86-32系统调用,因此相应地更改
EAX
中的数字。

QUICK FIX
您对32位和64位寄存器以及系统调用号感到困惑
我刚刚为32位体系结构更改了错误的寄存器值

section .data
    msg1 db "Type in ur Name? ", 10
    len1 equ $ - msg1       ; Get the Size of msg1

    msg2 db "Hi, "
    len2 equ $ - msg2       ;Get the Size of msg2

section .bss
    name resb 16            ;16 Bytes for name

section .text
    global _start

_start:

    ;Call Functions
    call _printMsg1
    call _getName
    call _printMsg2
    call _printName

    mov eax, 1
    mov ebx, 0
    int 0x80


_printMsg1:
    mov eax, 4
    mov ebx, 1
    mov ecx, msg1
    mov edx, len1
    int 0x80
    ret


_printMsg2:
    mov eax, 4
    mov ebx, 1
    mov ecx, msg2
    mov edx, len2
    int 0x80
    ret


_printName:
    mov eax, 4
    mov ebx, 1
    mov ecx, name
    mov edx, 16     ; reserve 16 Bytes for the name
    int 0x80
    ret


_getName:
    mov eax, 3      ;Syscall 3 = Read from stdin
    mov ebx, 0  
    mov ecx, name
    mov edx, 16     ;16 Bytes for the name
    int 0x80
    ret
使用nasm和ld编译32位

nasm -f elf32 test.asm -o test.o
ld -m elf_i386 test.o -o test

快速修复
您对32位和64位寄存器以及系统调用号感到困惑
我刚刚为32位体系结构更改了错误的寄存器值

section .data
    msg1 db "Type in ur Name? ", 10
    len1 equ $ - msg1       ; Get the Size of msg1

    msg2 db "Hi, "
    len2 equ $ - msg2       ;Get the Size of msg2

section .bss
    name resb 16            ;16 Bytes for name

section .text
    global _start

_start:

    ;Call Functions
    call _printMsg1
    call _getName
    call _printMsg2
    call _printName

    mov eax, 1
    mov ebx, 0
    int 0x80


_printMsg1:
    mov eax, 4
    mov ebx, 1
    mov ecx, msg1
    mov edx, len1
    int 0x80
    ret


_printMsg2:
    mov eax, 4
    mov ebx, 1
    mov ecx, msg2
    mov edx, len2
    int 0x80
    ret


_printName:
    mov eax, 4
    mov ebx, 1
    mov ecx, name
    mov edx, 16     ; reserve 16 Bytes for the name
    int 0x80
    ret


_getName:
    mov eax, 3      ;Syscall 3 = Read from stdin
    mov ebx, 0  
    mov ecx, name
    mov edx, 16     ;16 Bytes for the name
    int 0x80
    ret
使用nasm和ld编译32位

nasm -f elf32 test.asm -o test.o
ld -m elf_i386 test.o -o test

根据说明,拨打
write
系统呼叫应该是
mov eax,4
。您好,谢谢您的回答!我添加了我的解决方案。我只是换一下寄存器。我从这里使用syscall表:您确定要在64位模式下编程吗?如果您仍然使用而不是
syscall
,则使用RDI、RSI和RDX将完全不起作用。您使用的是64位呼叫号码,但其他所有号码都是32位的。根据您的说明,呼叫
写入系统呼叫应该是
mov eax,4
。您好,谢谢您的回答!我添加了我的解决方案。我只是换一下寄存器。我从这里使用syscall表:您确定要在64位模式下编程吗?如果您仍然使用而不是
syscall
,则使用RDI、RSI和RDX将完全不起作用。您使用的是64位呼叫号码,但其他所有号码都是32位。您的
\u getName
有问题。它从stderr读取(fd=ebx=2)。这通常是可行的,因为通常情况下,fds 0、1和2都指向终端的同一读写打开文件描述,但如果用户重定向或关闭stderr而不是stdin,则会中断。Common Pete be pitty不是我的功能!getName函数中ebx的正确值应该是多少?你为什么向我抱怨?是您破坏了OP代码的一部分,该代码正确地将STDIN_FD(
0
)用于读取系统调用的第一个参数。您是否不知道应该从stdin读取输入,或者不知道stdin的文件描述符编号?我假设您知道EBX是
读取的fd参数(int-fd,void*buf,size\u t len)
。顺便说一句,如果你要发布这样的答案,用
这样的注释给代码添加一些价值会很有用;阅读(0,name,16)
。您还没有编辑您的答案来解决这个问题。但我想提出另一点:让问题在代码中不被纠正是一件坏事。有问题的代码应该假设被堆栈溢出的未来读者破坏了。但答案中的代码应该是有效的。通过将代码复制到您的答案中,您认可它是一个值得遵循的好例子。这就是为什么我对“代码不起作用”问题的回答通常会修复不相关的问题,甚至改进事情,以更好的方式做某事。(比如使用RIP相对寻址,或者在.rodata中放入常量)TL:DR:问题中的bug不是答案中bug的有效理由。这违背了堆栈溢出的目的:高质量的答案。从stderr读取并不总是100%错误的,所以它不属于这一类。e、 g.我想我见过一些现实世界的程序,比如说如果stdin没有连接到终端,那么可以用
less
来代替打开
/dev/tty
。(如
foo | less
)。但是,如果你没有做终端特定的东西,那么从FD而不是stdin读取数据仍然是不好的。但是没有大的评论是不行的。你的
\u getName
有问题。它从stderr读取(fd=ebx=2)。这通常是可行的,因为通常情况下,fds 0、1和2都指向终端的同一读写打开文件描述,但如果用户重定向或关闭stderr而不是stdin,则会中断。Common Pete be pitty不是我的功能!getName函数中ebx的正确值应该是多少?你为什么向我抱怨?是您破坏了OP代码的一部分,该代码正确地将STDIN_FD(
0
)用于读取系统调用的第一个参数。您是否不知道应该从stdin读取输入,或者不知道stdin的文件描述符编号?我假设您知道EBX是
读取的fd参数(int-fd,void*buf,size\u t len)
。顺便说一句,如果你要发布这样的答案,用
这样的注释给代码添加一些价值会很有用;阅读(0,name,16)
。您还没有编辑您的答案来解决这个问题。但我想再做一次