如何使用 NASM 查找字符串的长度?

发布于 2024-11-17 04:03:40 字数 440 浏览 2 评论 0原文

我正在尝试使用 NASM 编写一个程序,该程序从命令行参数获取输入。由于未提供字符串长度,我正在尝试创建一个函数来计算我自己的字符串长度。这是我的尝试,它获取指向 ebx 寄存器中字符串的指针,并返回 ecx 中字符串的长度:

len:
    push ebx
    mov ecx,0
    dec ebx
    count:
        inc ecx
        inc ebx
        cmp ebx,0
        jnz count
    dec ecx
    pop ebx
    ret

我的方法是遍历字符串,逐个字符,检查是否为空。如果不是,我会增加 ecx 并转到下一个字符。我相信问题在于 cmp ebx,0 对于我想要做的事情来说是不正确的。我将如何正确地检查该字符是否为空?另外,还有其他我可以做得更好的事情吗?

I'm trying to make a program using NASM that takes input from command line arguments. Since string length is not provided, I'm trying to make a function to compute my own. Here is my attempt, which takes a pointer to a string in the ebx register, and returns the length of the string in ecx:

len:
    push ebx
    mov ecx,0
    dec ebx
    count:
        inc ecx
        inc ebx
        cmp ebx,0
        jnz count
    dec ecx
    pop ebx
    ret

My method is to go through the string, character by character, and check if it's null. If it's not, I increment ecx and go to the next character. I believe the problem is that cmp ebx,0 is incorrect for what I'm trying to do. How would I properly go about checking whether the character is null? Also, are there other things that I could be doing better?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

沒落の蓅哖 2024-11-24 04:03:40

您正在将 ebx 中的值与 0 进行比较,这不是您想要的。 ebx 中的值是内存中字符的地址,因此应该像这样取消引用:

cmp byte[ebx], 0

此外,最后一个push ebx 应该是pop ebx >。

You are comparing the value in ebx with 0 which is not what you want. The value in ebx is the address of a character in memory so it should be dereferenced like this:

cmp byte[ebx], 0

Also, the last push ebx should be pop ebx.

不打扰别人 2024-11-24 04:03:40

以下是我在检查 argv[1] 的 64 位 Linux 可执行文件中执行此操作的方法。内核使用堆栈上的 argcargv[] 启动一个新进程,如 x86-64 System V ABI 中所述。

_start:
    pop    rsi              ; number of arguments (argc)
    pop    rsi              ; argv[0] the command itself (or program name)
    pop    rsi              ; rsi = argv[1], a pointer to a string
    mov    ecx, 0           ; counter
.repeat:
    lodsb                   ; byte in AL
    test   al,al            ; check if zero
    jz     .done            ; if zero then we're done
    inc    ecx              ; increment counter
    jmp    .repeat          ; repeat until zero
.done:
    ; string is unchanged, ecx contains the length of the string


; unused, we look at command line args instead
section .rodata
    asciiz:    db    "This is a string with 36 characters.", 0

这是缓慢且低效的,但很容易理解。

为了提高效率,您只需要

当然,SSE2 在 x86-64 中始终可用,因此我们应该使用它来检查 16 字节的块(在达到对齐边界后)。查看优化的手写 strlen 实现,例如 glibc 中的实现。 (https://code.woboq.org/userspace/glibc /sysdeps/x86_64/strlen.S.html)。

Here is how I do it in a 64-bit Linux executable that checks argv[1]. The kernel starts a new process with argc and argv[] on the stack, as documented in the x86-64 System V ABI.

_start:
    pop    rsi              ; number of arguments (argc)
    pop    rsi              ; argv[0] the command itself (or program name)
    pop    rsi              ; rsi = argv[1], a pointer to a string
    mov    ecx, 0           ; counter
.repeat:
    lodsb                   ; byte in AL
    test   al,al            ; check if zero
    jz     .done            ; if zero then we're done
    inc    ecx              ; increment counter
    jmp    .repeat          ; repeat until zero
.done:
    ; string is unchanged, ecx contains the length of the string


; unused, we look at command line args instead
section .rodata
    asciiz:    db    "This is a string with 36 characters.", 0

This is slow and inefficient, but easy to understand.

For efficiency, you'd want

And of course SSE2 is always available in x86-64, so we should use that to check in chunks of 16 bytes (after reaching an alignment boundary). See optimized hand-written strlen implementations like in glibc. (https://code.woboq.org/userspace/glibc/sysdeps/x86_64/strlen.S.html).

濫情▎り 2024-11-24 04:03:40

这是我如何编码的

len:
      push ebx
      mov  eax, ebx
lp:
        cmp byte [eax], 0
        jz  lpend
        inc eax
        jmp lp
lpend:
        sub eax, ebx

      pop ebx
      ret

(结果在 eax 中)。可能有更好的方法。

Here how I would have coded it

len:
      push ebx
      mov  eax, ebx
lp:
        cmp byte [eax], 0
        jz  lpend
        inc eax
        jmp lp
lpend:
        sub eax, ebx

      pop ebx
      ret

(The result is in eax). Likely there are better ways.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文