【问题标题】:Assembly(Intel x86) function to find the length of a string, why am I getting extra characters?汇编(Intel x86)函数来查找字符串的长度,为什么我会得到额外的字符?
【发布时间】:2019-10-01 04:19:41
【问题描述】:

我是汇编初学者,我有这个作业,我必须创建一个 strlen 函数来查找任何字符串的长度。

我尝试从edx 中减去 4,因为最后我看到了 4 个额外的字符,但这并没有解决任何问题。他们还在那里。

section .data   
text: db "Hello world, trying to find length of string using function."     ;our string to be outputted

section .text
global _start   ;declared for linker

_start:     
    mov eax, 4      ;system call number (sys write)
    mov ebx, 1      ;file descriptor to write-only
    mov ecx, text   ;message to output
    call strlen
    mov edx, len    ;length of string to print
    int 80h         ;interrupt

exit:       
    mov eax, 1  ;system call number (sys exit)
    mov ebx, 0  ;file descriptor to read-only
    int 80h     ;interrupt

strlen: 
    push ebp        ;prologue, save base pointer
    mov ebp, esp    ;copy esp to ebp
    push edi        ;push edi for use

                    ;body
    mov edi, text   ;save text to edi, and i think when i do that edi expands? if text = 5 bytes, and edi was originally 4, then edi becomes 5?
    sub edi, esp    ;subtract edi starting point by the esp starting point to get len. ex: edi = 100, esp = 95
    mov [len], edi  ;copy value of edi onto len

    pop edi         ;epilogue, pop edi out of stack
    mov esp, ebp    ;return esp back to top of stack
    pop ebp         ;pop ebp back to original
    ret             ;return address



section .bss    
len: resb 4 ;4 byte to integer

假设我在.data 部分中有以下代码:

section .data   
text: db "Hello world, trying to find length of string using function."

预期的输出应该是 “Hello world,尝试使用函数查找字符串的长度。”,但是我得到 “Hello world,尝试使用函数查找字符串的长度。 ####" 其中# 是任意随机字符。

这是终端输出:

谢谢。

【问题讨论】:

  • 您不是在查看字符串中的字节,而是在计算 .data 部分和堆栈之间的距离。如果您想查找一个,Stack Overflow 上有大量 strlen 函数示例,否则请从头开始重新启动您的 strlen 函数,因为您当前的尝试完全走错了轨道。您甚至没有使用 ecx 中的 arg 您传入调用者,而是将其硬编码为采用 text 的 strlen。
  • @Peter Cordes 谢谢,这是我的第一个作业(教授只是要求我们在 .data 中查找文本的长度而没有指定它),在我意识到我是查看 .data 部分之间的距离,而不是字节。我现在把它作为我的code,它似乎输出了我想要的东西。如果有什么我可以解决的,请告诉我。
  • 大多数汇编程序不会将终止 0 添加到使用 db "..." 声明的字符串中。要处理此问题,请使用 db "...",0 附加终止 0。
  • 是的,您只是在为长度计算一些随机垃圾大值,而不是在字节上循环,直到找到终止的 0 字节。 (您必须确保数据中有 db "foo", 0). Then write()` 将数据向上写入,直到它进入未映射的页面并返回 -EFAULT,但将有效字节复制到标准输出文件描述符已经发生了。可能你的字符串后面的字节都是 0 巧合,所以你不会在终端上注意到它们。'\0' 打印为零宽度。
  • 对我之前的评论的补充:除了计算垃圾之外,您还使用len 的绝对地址 作为长度而不是该内存的内容。因此,有两个引人注目的错误,其中一个只是语法,另一个基于明显的基本误解。 :/(Sep 的回答指出了这一点;我在评论时没有看来电者。)

标签: assembly x86 nasm


【解决方案1】:

在调用strlen 之前,您已经为ECX 加载了您希望知道其长度的字符串的地址。然后直接在你的函数中使用ECX
你不需要在这个小任务上使用 prolog/epilog 代码。

strlen: push    ecx
        dec     ecx
.loop:  inc     ecx
        cmp     byte ptr [ecx], 0
        jne     .loop
        sub     ecx, [esp]
        mov     [len], ecx         ; Save length
        pop     ecx
        ret

此代码遍历字符串,直到找到零。此时,从找到零的地址(在ECX)中减去起始地址(它在堆栈上[esp])。这会产生长度。

您可以选择将结果返回到EDX 寄存器中,而不是将结果放入内存变量中 - 准备好下一步使用!

此版本的 strlen 只有在您确保字符串实际上是零终止的情况下才能工作。只需附加零。

section .data   
text: db "Hello world, trying to find length of string using function.",0

这是 NASM

call strlen
mov edx, len    ;length of string to print
int 80h         ;interrupt

您需要 len 周围的方括号来获取存储在该位置的长度。

call    strlen
mov     edx, [len]    ; Length of string to print
int     80h

【讨论】:

  • 我看到这是一个循环但我认为当堆栈增加时,内存地址是下降的?例如ECX 的第一个字符可能在内存地址900 并且它的结尾会在某处<900?还是我错了?如果它是上升的,但如果它是下降的,代码在我的脑海中是有意义的。例如:ECX 的范围从900910,我们不断增加ECX 直到它达到0ESP 保持在900,所以,910 - 900 = 10 的长度?
  • @Jeeong:取消第一次迭代的inc ecx。另一种选择是使用jmp 进入循环到cmp/jne 循环条件以检查第一个字节。即根据do{}while(*++p);实现while(*p++){}
猜你喜欢
  • 2015-06-20
  • 2016-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
  • 1970-01-01
  • 1970-01-01
  • 2019-01-18
相关资源
最近更新 更多