Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/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
Linux 如何使用NASM查找字符串的长度?_Linux_String_Assembly_X86_Nasm - Fatal编程技术网

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

Linux 如何使用NASM查找字符串的长度?,linux,string,assembly,x86,nasm,Linux,String,Assembly,X86,Nasm,我正在尝试使用NASM制作一个程序,该程序从命令行参数获取输入。因为没有提供字符串长度,所以我尝试创建一个函数来计算我自己的长度。下面是我的尝试,它获取指向ebx寄存器中字符串的指针,并返回ecx中字符串的长度: len: push ebx mov ecx,0 dec ebx count: inc ecx inc ebx cmp ebx,0 jnz count dec ecx pop

我正在尝试使用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

我的方法是逐个字符检查字符串,并检查它是否为null。如果不是,我将递增ecx并转到下一个字符。我认为问题在于
cmpebx,0
对于我正在尝试的操作是不正确的。如何正确地检查字符是否为空?另外,还有其他我可以做得更好的事情吗?

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

cmp byte[ebx], 0

另外,最后一个
推ebx
应该是
pop ebx

这里我将如何编码它

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中)。可能还有更好的方法。

下面是我如何在检查
argv[1]
的64位Linux可执行文件中执行的。内核使用堆栈上的
argc
argv[]
启动一个新进程,如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
这是缓慢和低效的,但容易理解

为了提高效率,你应该

  • 循环中只有1个分支()
  • 通过使用
    movzx
    加载,而不是合并到以前的RAX值()中,避免错误的依赖关系
  • 减去循环后的指针,而不是增加循环内的计数器

当然,SSE2在x86-64中总是可用的,所以我们应该使用它来签入16字节的块(在到达对齐边界之后)。请参阅glibc中的优化手写
strlen
实现。()。

cmp-ebx,0
是错误的,并且末尾的
推送ebx
可能是
弹出ebx
(否则会导致堆栈溢出!)。糟糕。我误将
pop ebx
手动复制为
push ebx
。试着养成复制和粘贴实际代码的习惯,而不是重新键入代码。另外,请编辑您的问题,使其与实际代码相匹配。@paul-r这是我通常做的。我在VirtualBox中工作,剪贴板共享设置不正确。指针增量更好,但糟糕的循环结构是许多CPU上的瓶颈。在每个循环迭代中有两个分支(一个执行,一个未执行),因此它只能在Haswell之前的CPU上每2个时钟运行一次迭代,即编写本文时存在的分支。(当然,对于使用SSE2的现代x86来说,一次只检查一个字节是非常糟糕的。)