Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 程序集x86_64:从用户获取输入整数并打印它_Assembly_Nasm_X86 64 - Fatal编程技术网

Assembly 程序集x86_64:从用户获取输入整数并打印它

Assembly 程序集x86_64:从用户获取输入整数并打印它,assembly,nasm,x86-64,Assembly,Nasm,X86 64,我正在尝试编写一个程序,其工作方式如下: 获取用户输入的数字->除以,例如2->打印结果(商) divide-by-The-number-2部分似乎没有太大的难度,所以我初步编写了一个程序,由用户输入一个整数并打印该整数 这意味着我试图编写一个程序,将用户的字符串整数转换为实整数,然后将其转换回字符串并打印出来 但是在编译之后,我最终进入了一个无限循环(在点击Enter之后,什么也没有发生) 我使用以下命令进行编译: nasm -f elf64 ascii.asm -o ascii.o ld

我正在尝试编写一个程序,其工作方式如下:

获取用户输入的数字
->
除以,例如2
->
打印结果(商)

divide-by-The-number-2
部分似乎没有太大的难度,所以我初步编写了一个程序,由用户输入一个整数并打印该整数

这意味着我试图编写一个程序,将用户的字符串整数转换为实整数,然后将其转换回字符串并打印出来

但是在编译之后,我最终进入了一个无限循环(在点击
Enter
之后,什么也没有发生)

我使用以下命令进行编译:

nasm -f elf64 ascii.asm -o ascii.o

ld ascii.o -o ascii

./ascii
在下面的代码中,子程序
\u getInteger
用于从字符串到整数的转换,子程序
\u appendEOL
\u loopDigit
用于从整数到字符串的整个转换

section .bss
        ascii resb 16           ; holds user input
        intMemory resb 100      ; will hold the endline feed 
        intAddress resb 8       ; hold offset address from the intMemory

section .data
        text db "It's not an integer", 10
        len equ $-text

section .text

        global _start

_start:

        call _getText
        call _toInteger
        call _appendEOL

mov rax, 60
        mov rdi, 0
        syscall

_getText:
        mov rax, 0
        mov rdi, 0
        mov rsi, ascii
        mov rdx, 16
        syscall
        ret

_toInteger:
        mov rbx,10      ; for decimal scaling
        xor rax, rax    ; initializing result
        mov rcx, ascii  ; preparing for working with input
        movzx rdx, byte [rcx]   ; getting first byte (digit)
        inc rcx         ; for the next digit

        cmp rdx, '0'    ; if it's less than '0' is not a digit
        jb _invalid

        cmp rdx, '9'    ; if it's greater than '9' is not a digit
        ja _invalid

        sub rdx, '0'    ; getting decimal value
        mul rbx         ; rax = rax*10
        add rax, rdx    ; rax = rax + rdx
        jmp _toInteger  ; repeat
        ret

_invalid:
        mov rax, 1
        mov rdi, 1
        mov rsi, text
        mov rdx, len
        syscall
        ret

_appendEOL:
        ; getting EOL
        mov rcx, intMemory
        mov rbx, 10 ; EOL
        mov [rcx], rbx
        inc rcx
        mov [intAddress], rcx

_loopDigit:
        xor rdx, rdx
        mov rbx, 10
        div rbx
        push rax
        add rdx, '0'
        mov rcx, [intAddress]
        mov [rcx], dl
        inc rcx
        mov [intAddress], rcx
        pop rax
        cmp rax, 0
        jne _loopDigit

_printDigit:
        mov rcx, [intAddress]

        mov rax, 1
        mov rdi, 1
        mov rsi, rcx
        mov rdx, 1
        syscall
        mov rcx, [intAddress]
        dec rcx
        mov [intAddress], rcx
        cmp rcx, intMemory
        jge _printDigit

        ret
你的“无限循环”在你的_-toInteger函数中

$ ./jazz_001
12
It's not an integer
20
RDX将为0或第一个元素或ASCII输入的值,因为您要通过跳回标签_-toInteger来重置指向第一个元素的指针。因此,您永远不能离开或跳出循环

我们怎么强调都不过分;您应该始终使用调试器

 mov rcx, ascii  ; preparing for working with input
但是,即使解决了这个问题,_-toInteger函数似乎也存在其他问题

$ ./jazz_001
12
It's not an integer
20

\u toInteger
是一个无止境的循环,它永远检查第一个数字。您需要更好的循环入口和中断条件

下一个问题是
mul-rbx
。此指令也会更改
EDX
,需要将其添加到
RAX
下面的一行中。如果您不想使用
IMUL rax,rax,10
,您可以使用
LEA的算术能力:

add rax, rax                ; RAX = RAX * 2
lea rax, [rax + rax * 4]    ; RAX = (former RAX * 2) + (former RAX * 8)
另一个问题是
SYS\u READ
syscall在
\u getText
中的棘手行为。您不会得到带有空终止符的C样式字符串
SYS\u READ
在缓冲区末尾填充
\n
-如果根据
RDX
有足够的位置。有时
\n
,有时不-这不是
\u-toInteger
的有用中断条件。woirkaround是将
系统读取的最后一个字节置零,无论它是
\n
还是数字。这会将可用缓冲区缩短1

_getText:
    mov rax, 0
    mov rdi, 0
    mov rsi, ascii
    mov rdx, 16
    syscall
    mov byte [ascii-1+rax], 0
    ret
SYS\u READ
带给您的更多惊喜做好准备。中断条件现在为空。让我们开始吧:

_toInteger:
    mov rbx,10      ; for decimal scaling
    xor rax, rax    ; initializing result
    mov rcx, ascii  ; preparing for working with input

    .LL1:           ; loops the bytes
    movzx rdx, byte [rcx]   ; getting current byte (digit)

    test rdx, rdx   ; RDX == 0?
    jz .done        ; Yes: break

    inc rcx         ; for the next digit

    cmp rdx, '0'    ; if it's less than '0' is not a digit
    jb _invalid

    cmp rdx, '9'    ; if it's greater than '9' is not a digit
    ja _invalid

    sub rdx, '0'    ; getting decimal value

    ; mul rbx         ; rax = rax*10
    add rax, rax
    lea rax, [rax + rax * 4]

    add rax, rdx    ; rax = rax + rdx

    ;jmp _toInteger  ; repeat
    jmp .LL1  ; repeat

    .done:
    ret

请注意:
\u toInteger
返回
RAX
中的整数,但不保存此值。
EAX
上的下一个写操作将破坏它。

听起来似乎是时候了解GDB(或其他调试器)@tommyle2k这意味着什么(:?我在上面的代码中有什么错误吗?我花了两周的时间来模拟汇编,所以我对汇编几乎一无所知。我没有完全理解你的意思):。这意味着,如果您试图证明代码的正确性,那么源代码是否编译几乎是无关紧要的(除非任何编译时失败都会立即排除)。实际上,即使运行可执行文件并收到预期结果,也离证明正确性还有很长的路要走。为了至少更接近这个难以捉摸的乌托邦目标,您应该使用调试器逐条执行代码指令,根据您的期望/设计测试每个执行指令后的当前机器状态,并测试不同的输入,如null/empty/large/…很抱歉回复太晚,但是我对GDB有点熟悉了(真的是一件很不错的事情)。我有4个问题,所以我很感谢您的指导:
1)
在这个预定的程序中,除了由于乘法后的溢出之外,
mul-rbx
可以通过什么方式更改
edx
寄存器?(也许在这个问题中我没有考虑字节的某些方面)
2)
我知道
lea-rax,[rax+rax*4]
在每个循环之后,将
rax 2
位的值向左移动,以便为下一个数字留出一些空间。正确吗?
3)
您指出的
SYS\u READ
问题是因为我任意设置了用户输入的字符串长度,对吗
4)
我读到
imul
清除溢出(如果我没有错的话,这意味着
edx
不会被更改),但是为什么要使用
imul
的三个操作数形式,而不仅仅是一个操作数(或两个操作数)。@Jazz:这是一个世界性的网站。即使是24小时的延迟也不是不礼貌的。1)
mul-rbx
EDX:EAX
中生成64位结果,而不仅仅是溢出。2) 该
LEA
行与前一行一起只是执行EAX=EAX*10的一种方法。它不会改变EDX,也不会改变标志。3) SYS_READ的问题是SYS_READ的问题。你完全是无辜的。关于SYS_READ,我问了三个问题。单击标记,然后单击“活动”,您将看到这些问题直接位于您的问题下方(由我修改)…@Jazz:4)
IMUL
的一个操作数形式也会发生变化
EDX
。当然,也可以使用双操作数形式。你是在集会的世界里。这里不存在一个标准、意识形态或宗教——如果它起作用,那就好了。你需要一份详细的参考资料,哇。有很多很酷的东西要学。谢谢你回答这些问题。我正在仔细阅读关于SYS_READ的文章。我希望在这几天内解决这些问题。如果没有,我将创建另一个问题xD(但希望有更好的基础)。再次感谢您抽出时间。