assembly 如何在x86_64程序集NASM中循环遍历字符串?

14ifxucb  于 2022-11-30  发布在  其他
关注(0)|答案(1)|浏览(119)

我要求用户给予我一个数字。我收到的数字是一个字符串,我想遍历字符串中的每个字符以检查其内容。我写了下面的代码,其中 numero_a_convertir 是指向用户给我的字符串的指针:

;* BASE 8 A BINARIO
convertir_octal_a_base2:
    mov rbx, 0

    cmp dword[numero_a_convertir + rbx], "0"
    je imprimir

    cmp dword[numero_a_convertir + rbx], "1"
    je imprimir

    cmp dword[numero_a_convertir + rbx], "2"
    je imprimir

    cmp dword[numero_a_convertir + rbx], "3"
    je imprimir

    cmp dword[numero_a_convertir + rbx], "4"
    je imprimir

    cmp dword[numero_a_convertir + rbx], "5"
    je imprimir

    cmp dword[numero_a_convertir + rbx], "6"
    je imprimir

    cmp dword[numero_a_convertir + rbx], "7"
    je imprimir

    jmp fin_conversion
imprimir:
    mov     rcx, MENSAJE_A_IMPRIMIR_CHAR 
    mov     rdx, [numero_a_convertir + rbx]      
    sub     rsp, 32
    call    printf
    add     rsp, 32
fin_conversion:
ret

如果用户输入一个只有1个字符的字符串,例如“1”,它将工作,因为RBX设置为0。但是如果用户输入一个以上的字符,例如“12”或“12345”,它将不再工作。
同样的事情,如果我设置RBX在2上。如果输入是“123”,它工作。如果输入是“12345”,它打破。
为什么我无法访问5个字符的字符串中的第3个字符?

uelo1irk

uelo1irk1#

我收到了一个字符串形式数字,我想遍历字符串中的每个字符以检查其内容。
字符串由其地址(numero_a_convertir)和长度定义,长度可以是直接值(RCX)或字符串终止字节(0)。
验证输入字符的有效性以及将文本转换为(无符号)整数不需要单独的步骤。
每个八进制数需要3位的RAX寄存器,rol rax, 3test al, 7对确保有一个空的三位数可用,以便or rax, rdx可以将最新的数填入其中。

RCX中已知长度的字符串

; IN (rbx,rcx) OUT (rax) MOD (rbx,rcx,rdx)
convertir_octal_a_base2:
    xor   eax, eax        ; RAX = 0
.Loop:
    movzx edx, byte [rbx] ; -> RDX = ["0","7"] (NewDigit) ?
    sub   edx, 48
    cmp   dl, 7
    ja    .NotDigit
    inc   rbx             ; Next character
    rol   rax, 3          ; Result = Result * 8
    test  al, 7
    jnz   .Overflow
    or    rax, rdx        ; Result = Result + NewDigit
    dec   rcx
    jnz   .Loop
    ret
.NotDigit:
    ???
.Overflow:
    ???

当代码偶然发现一个不是八进制的字符时,你可以选择不接受整个输入,或者只返回到那个点的值。后者是像BASIC这样的高级语言中经常使用的方法。
这取决于你是否会考虑溢出与否,以及在发生溢出的情况下该怎么做。

以零终止符结尾的字符串

; IN (rbx) OUT (rax) MOD (rbx,rdx)
convertir_octal_a_base2:
    xor   eax, eax        ; RAX = 0
    movzx edx, byte [rbx] ; -> RDX = ["0","7"] (NewDigit) ?
    sub   edx, 48
    cmp   dl, 7
    ja    .CouldBeNULL
.Loop:
    inc   rbx             ; Next character
    rol   rax, 3          ; Result = Result * 8
    test  al, 7
    jnz   .Overflow
    or    rax, rdx        ; Result = Result + NewDigit
    movzx edx, byte [rbx] ; -> RDX = ["0","7"] (NewDigit) ?
    sub   edx, 48
    cmp   dl, 8
    jb    .Loop           ; It's an octal digit
.CouldBeNULL:
    cmp   dl, -48
    jne   .NotDigit
    ret
.NotDigit:
    ???
.Overflow:
    ???

当代码读取最后一个零终止符时,sub edx, 48指令将产生DL=-48,这与我们从无效字符得到的结果不同。因为这个测试位于循环之外,所以循环效率更高。
当代码偶然发现一个不是八进制的字符时,你可以选择不接受整个输入,或者只返回到那个点的值。后者是像BASIC这样的高级语言中经常使用的方法。
这取决于你是否会考虑溢出与否,以及在发生溢出的情况下该怎么做。

相关问题