x86-64位程序集Linux输入

x86-64位程序集Linux输入,linux,assembly,64-bit,x86-64,Linux,Assembly,64 Bit,X86 64,我正在尝试输入我的程序。。。它所做的只是运行并在屏幕上打印一个“0”。我很确定PRINTDECI函数是有效的,我在不久前做的,它是有效的。我是否只需要循环输入代码,并且只在输入某个值时退出?我不知道我会怎么做。。。除非它是由ACSII的值,这可能会吸。。。。无论如何,这是我的代码(Yasm(nasm克隆),英特尔语法): 谢谢你的帮助! -凯尔 作为旁注,根据DDD,RCX中的指针指向一个非常大的数字。。。因此,我想我必须让它暂停并等待我输入,但我不知道如何做…在x86\u 64系统上调用sys

我正在尝试输入我的程序。。。它所做的只是运行并在屏幕上打印一个“0”。我很确定PRINTDECI函数是有效的,我在不久前做的,它是有效的。我是否只需要循环输入代码,并且只在输入某个值时退出?我不知道我会怎么做。。。除非它是由ACSII的值,这可能会吸。。。。无论如何,这是我的代码(Yasm(nasm克隆),英特尔语法):

谢谢你的帮助! -凯尔


作为旁注,根据DDD,RCX中的指针指向一个非常大的数字。。。因此,我想我必须让它暂停并等待我输入,但我不知道如何做…

在x86\u 64系统上调用
syscall 0
(读取)的“设置”是:

@xenon:~$ syscalls_lookup read
read:
        rax = 0  (0x0)
        rdi = unsigned int fd
        rsi = char *buf
        rdx = size_t count
因此,您的
\u start
代码应该类似于:

_start:
    mov  rax, 0         ; READ
    mov  rdi, 0         ; stdin
    mov  rsi, SCORE     ; buffer
    mov  rdx, SCORELEN  ; length
    syscall
x86_64的寄存器约定和系统调用号与i386的寄存器约定和系统调用号完全不同

您似乎有一些概念问题:

  • READ不会对您键入的内容进行任何解释,您似乎希望它允许您键入一个数字(例如,57),并让它返回值57。不。它将返回“5”、“7”、“回车”、“垃圾”。。。您的SCORELEN可能是8(resq 1的长度),因此您最多只能读取8个字节。或者角色,如果你想这样称呼他们的话。除非键入EOF字符(^D),否则在READ调用返回到代码之前,您需要键入这8个字符

  • 您必须将收到的字符转换为值。。。您可以用简单的方法完成,并在C库中链接ATOI(),或者编写自己的解析器,通过加法和乘法将字符转换为值(这并不难,请参见下面的代码)

以下用作参考:

@xenon:~$ syscalls_lookup write
write:
        rax = 1  (0x1)
        rdi = unsigned int fd
        rsi = const char *buf
        rdx = size_t count
啊。。。。这么多。。。我将重写以下内容:

    global _start
    section .text

PRINTDECI:
; input is in RAX
    lea  r9, [NUMBER + NUMBERLEN - 1 ]  ; + space for \n
    mov  r10, r9            ; save end position for later
    mov  [r9], '\n'         ; store \n at end
    dec  r9
    mov  rbx, 10            ; base10 divisor

DIV_BY_10:
    xor  rdx, rdx       ; zero rdx for div
    div  rbx            : rax = rdx:rax / rbx, rdx = remainder
    or   dl, 0x30       ; make REMAINDER a digit
    mov  [r9], dl
    dec  r9
    or   rax, rax
    jnz  DIV_BY_10

PRINT_BUFFER:
    sub  r10, r9        ; get length (r10 - r9)
    inc  r9             ; make r9 point to initial character
    mov  rax, 1         ; WRITE (1)
    mov  rdi, 1         ; stdout
    mov  rsi, r9        ; first character in buffer
    mov  rdx, r10       ; length
    syscall
    ret

MAKEVALUE:
; RAX points to buffer
    mov  r9, rax        ; save pointer
    xor  rcx, rcx       ; zero value storage

MAKELOOP:
    mov  al, [r9]       ; get a character
    or   al, al         ; set flags
    jz   MAKEDONE       ; zero byte? we're done!
    and  rax, 0x0f      ; strip off high nybble and zero rest of RAX (we're lazy!)
    add  rcx, rcx       ; value = value * 2
    mov  rdx, rcx       ; save it
    add  rcx, rcx       ; value = value * 4
    add  rcx, rcx       ; value = value * 8
    add  rcx, rdx       ; value = value * 8 + value * 2 (== value * 10)
    add  rcx, rax       ; add new digit
    jmp  MAKELOOP       ; do it again

MAKEDONE:
    mov  rax, rcx       ; put value in RAX to return
    ret

_start:
    mov  rax, 0         ; READ (0)
    mov  rdi, 0         ; stdin
    mov  rsi, SCORE     ; buffer
    mov  rdx, SCORELEN  ; length
    syscall

; RAX contains HOW MANY CHARS we read!
; -OR-, -1 to indicate error, really
; should check for that, but that's for
; you to do later... right? (if RAX==-1,
; you'll get a segfault, just so you know!)

    add  rax, SCORE     ; get position of last byte
    movb [rax], 0       ; force a terminator at end

    mov  rax, SCORE     ; point to beginning of buffer
    call MAKEVALUE      ; convert from ASCII to a value

; RAX now should have the VALUE of the string of characters
; we input above. (well, hopefully, right?)

    mov  [VALUE], rax   ; store it, because we can!

; it's stored... pretend it's later... we need value of VALUE!

    mov  rax, [VALUE]   ; get the VALUE
    call PRINTDECI      ; convert and display value

; all done!
    mov  rax, 60        ; EXIT (60/0x3C)
    mov  rdi, 0         ; exit code = 0
    syscall

    section .bss
SCORE:  resb 11   ; 10 chars + zero terminator
SCORELEN equ $-SCORE
NUMBER: resb 19   ; 18 chars + CR terminator
NUMBERLEN equ $-NUMBER
我要说的是,这个应该是第一次起作用,它对我来说是现成的,还没有测试过,但应该是好的。我们最多读取10个字符,以零结尾,转换成一个值,然后转换成ascii并写出

更恰当的是,您应该将寄存器保存到每个子例程的堆栈中,好吧,某些寄存器,而且实际上,只有在您要与库进行接口的情况下。。。自己动手让你拥有所有想要玩寄存器的自由,你只需要记住你把什么放在哪里

是的,有人会说:“你为什么不直接乘以10而不是奇怪的加法?”。。。UH因为它在寄存器上更容易,而且我不必在rdx:rax中设置它。此外,它同样可读和易懂,尤其是在评论方面。加油!这不是竞赛,而是学习

机器代码很有趣!不过你得把脑子里所有的蛋都变戏法。。。这里没有编译器的帮助

从技术上讲,您应该检查系统调用的读写返回结果(RAX),适当地处理错误。。。。学习使用您的调试器(gdb或其他)


希望这有帮助。

您不应该在64位模式下使用吗?其他参数似乎也在错误的寄存器中。我真的应该检查字符是否是MAKEVALUE中的数字。输入“5”、“7”、“ENTER”可能会计算出5*100+7*10+10(ENTER是一个\n或0x0a值)。嗯,给学生做运动?谢谢!这正是我一直在寻找的答案!您知道Linux系统调用的好参考吗?非常感谢。是一个不错的参考,请尝试搜索
linux系统调用列表
或类似内容。记住,找一个合适的
i386
syscalls与
x86\u 64
syscalls完全不同。如果你给我发电子邮件,我有一些参考资料可以分享。(如上面的“系统调用查找”功能)
    global _start
    section .text

PRINTDECI:
; input is in RAX
    lea  r9, [NUMBER + NUMBERLEN - 1 ]  ; + space for \n
    mov  r10, r9            ; save end position for later
    mov  [r9], '\n'         ; store \n at end
    dec  r9
    mov  rbx, 10            ; base10 divisor

DIV_BY_10:
    xor  rdx, rdx       ; zero rdx for div
    div  rbx            : rax = rdx:rax / rbx, rdx = remainder
    or   dl, 0x30       ; make REMAINDER a digit
    mov  [r9], dl
    dec  r9
    or   rax, rax
    jnz  DIV_BY_10

PRINT_BUFFER:
    sub  r10, r9        ; get length (r10 - r9)
    inc  r9             ; make r9 point to initial character
    mov  rax, 1         ; WRITE (1)
    mov  rdi, 1         ; stdout
    mov  rsi, r9        ; first character in buffer
    mov  rdx, r10       ; length
    syscall
    ret

MAKEVALUE:
; RAX points to buffer
    mov  r9, rax        ; save pointer
    xor  rcx, rcx       ; zero value storage

MAKELOOP:
    mov  al, [r9]       ; get a character
    or   al, al         ; set flags
    jz   MAKEDONE       ; zero byte? we're done!
    and  rax, 0x0f      ; strip off high nybble and zero rest of RAX (we're lazy!)
    add  rcx, rcx       ; value = value * 2
    mov  rdx, rcx       ; save it
    add  rcx, rcx       ; value = value * 4
    add  rcx, rcx       ; value = value * 8
    add  rcx, rdx       ; value = value * 8 + value * 2 (== value * 10)
    add  rcx, rax       ; add new digit
    jmp  MAKELOOP       ; do it again

MAKEDONE:
    mov  rax, rcx       ; put value in RAX to return
    ret

_start:
    mov  rax, 0         ; READ (0)
    mov  rdi, 0         ; stdin
    mov  rsi, SCORE     ; buffer
    mov  rdx, SCORELEN  ; length
    syscall

; RAX contains HOW MANY CHARS we read!
; -OR-, -1 to indicate error, really
; should check for that, but that's for
; you to do later... right? (if RAX==-1,
; you'll get a segfault, just so you know!)

    add  rax, SCORE     ; get position of last byte
    movb [rax], 0       ; force a terminator at end

    mov  rax, SCORE     ; point to beginning of buffer
    call MAKEVALUE      ; convert from ASCII to a value

; RAX now should have the VALUE of the string of characters
; we input above. (well, hopefully, right?)

    mov  [VALUE], rax   ; store it, because we can!

; it's stored... pretend it's later... we need value of VALUE!

    mov  rax, [VALUE]   ; get the VALUE
    call PRINTDECI      ; convert and display value

; all done!
    mov  rax, 60        ; EXIT (60/0x3C)
    mov  rdi, 0         ; exit code = 0
    syscall

    section .bss
SCORE:  resb 11   ; 10 chars + zero terminator
SCORELEN equ $-SCORE
NUMBER: resb 19   ; 18 chars + CR terminator
NUMBERLEN equ $-NUMBER