【问题标题】:String length counter in NASMNASM 中的字符串长度计数器
【发布时间】:2013-06-26 07:58:17
【问题描述】:

每个人。我在 NASM 中编写了一个程序,计算作为变量提供的字符串的长度:

section .data
    ; str1 db '12345678901'
    str1 db '123456789012'

section .text
    global _start

_start:
    mov eax, str1
    mov ecx, -1

.loop:
    inc ecx
    cmp byte [eax + ecx], 0
    jne .loop

.done:
    mov eax, 1
    mov ebx, ecx
    int 80h

当我使用第一个字符串(在此清单中注释)运行程序时,它返回正确的值 11。使用第二个字符串,它比应有的值多 13 - 1。我不知道为什么会这样。它是在 64 位机器上组装的。我尝试使用 GDB 对其进行检查,但我没有看到重点...

【问题讨论】:

    标签: assembly 64-bit nasm


    【解决方案1】:
    str1 db '123456789012'
    ....    
    cmp byte [eax + ecx], 0
    

    您的字符串没有 NUL 终止符。将其更改为str1 db '123456789012',0

    【讨论】:

    • 这很好用。谢谢,迈克尔。不过,我仍然想知道,是什么导致了这两种情况下的输出差异。
    • 可能是“机会”。在一种情况下,您恰好在字符串中的最后一个字符之后得到一个值为 0 的字节,而在另一种情况下,您没有。根据情况,这根本不是机会。例如,您可能有一个可执行格式,其中填充了节以满足特定的对齐约束,以及一个链接器,它用某些值填充节中未使用的字节。但总的来说,最好不要依赖此类特定于实现的细节。
    【解决方案2】:

    计算字符串长度最快的方法是使用 scasb 指令:

    xor   rax,rax      ;so all of ax is 0 for return value
    mov   ecx,0x03fff  ;limit scan length
    cld
    repne scasb
    sub   ecx,0x03fff  ;sub by the scan length
    neg   ecx
    dec   ecx          ;minus one for rep going too far by one
    mov   eax,ecx      ;C functions return in ax register
    

    0x3fff 是我的限制值,因此scasb 不会在没有0 终止的字符串的情况下走得太远。您可以将其设置为您喜欢的任何值,实际上许多库使用ecx 的最大值为0xffffffff。但是你必须始终确保你给它的字符串是0 终止的!如果不是,它将返回限制值作为字符串的长度(如果它没有首先出错)。

    【讨论】:

    • 谢谢,鲍勃。我会检查一下。我的例子并不是一个真实的长度计数器,只是一个玩具程序:)
    【解决方案3】:

    你可以在 ecx: 中使用 mov -1 而不是 sub 和 neg: 然后不使用

    xor al, al      ; the byte that the scan will compare to is zero
    
    mov ecx, -1     ; underfow will set the maximum number of bytes
    
    cld             ; CLD (STD) clears (sets) the Direction flag, data goes onwards (backwards).
    repne scasb     ; while [rdi] != al, keep scanning
    ; The REPNZ prefix (which is more readable in the REPNE form) repeats the scas as long as the comparison is false (REPeat while Not Equal) and ECX > 0. It also decrements ECX automatically in every iteration. ECX has been initialized to the longest possible string so that it doesn't terminate the loop early.
    
    not ecx         ; Since ECX counts down from 0xffffffff (also known as -1), the resulting length will be -1-ECX
    sub ecx, 1      ; len--
    
    mov eax, ecx    ; ret = len
    
    ret
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-05
      • 2011-09-22
      • 2020-03-12
      • 2016-01-01
      • 1970-01-01
      • 2016-10-05
      • 1970-01-01
      • 2017-06-12
      相关资源
      最近更新 更多