assembly - 减去两个字符
问题描述
我刚开始用汇编编程,所以我是初学者。
为了练习,我正在尝试在程序集中重写一个基本的 libc(NASM Intel 语法)。
但我被困在strcmp函数上:
;; Compare two C-style NUL-terminated strings
;; Inputs : ESI = address of s1, EDI = address of s2
;; Outputs : EAX = return an integer less than, equal to, or greater than zero if s1 is found, respectively, to be less than, to match, or be greater than s2
strcmp:
call strlen
mov ecx, eax ; ecx = length of the string in esi
repe cmpsb
sub esi, edi ; result = *esi - *edi
mov eax, esi
ret
对我来说,它应该像这样工作:
s1 db 'Hello World', 0
s2 db 'Hello Stack', 0
在repe cmpsb
指令之后,ESI
应该等于[s1 + 7]
和EDI
to [s2 + 7]
。
所以我只需要做EAX
= 'W' - 'S' = 87 - 83 = 4
问题是,它不起作用。我认为问题在于当我执行这条指令时:
sub esi, edi ; result = *esi - *edi
我不认为这意味着:减去and指向的字符EDI
ESI
。
有谁知道我该怎么做?
解决方案
您的代码几乎是正确的。剩下三个问题:
- 您不应该假设
strcmp
保留 and 的内容,esi
除非edi
您明确指定它这样做。之后很容易更改strcmp
然后忘记需求,从而导致各种烦人的问题。 - 不是返回和之间的差,而是返回
*edi
和之间的*esi
差。此外,作为前进和加一,最后比较的字符位于和处。edi
esi
cmpsb
esi
edi
edi[-1]
esi[-1]
- 你有一个非一的错误:
strlen
返回 NUL 字节之前的字符数,但你也需要比较 NUL 字节。否则,如果一个字符串是另一个字符串的前缀,您最终会发现两个字符串是相等的,因为您永远不会检查第二个字符串是否真的在第一个字符串结束时结束。
要解决第一个问题,我建议您保存和恢复esi
以及edi
调用strlen
. 最简单的方法是将它们压入堆栈:
push esi ; save ESI and EDI
push edi
call strlen ; compute the string length
pop edi ; restore ESI and EDI
pop esi
第二个问题是通过从内存加载要比较的字符,计算差异,然后将结果存储到eax
:
movzx eax, byte [esi-1] ; load byte from ESI[-1] and zero extend into EAX
movzx ecx, byte [edi-1] ; load byte from EDI[-1] and zero extend into ECX
sub eax, ecx ; compute the difference
这也通过立即使用正确的偏移量来解决第三个问题。请注意,movzx
这里需要,而不是稍微简单的
mov al, [esi-1] ; load byte from ESI[-1] into AL
sub al, [edi-1] ; subtract EDI[-1] from AL
因为我们希望减法的结果正确符号扩展为eax
.
推荐阅读
- python-3.x - 将列表的值分组到相等的距离箱中
- java - While循环被破坏,即使参数正确
- python - 在 python 中使用字典列表
- python - 接收和发送消息到特定类别(不和谐机器人)
- html - 从access数据库中读取数据并显示在html网页中
- python - 为什么使用多个条件进行过滤不起作用?
- html - 圆形图像作为html中的按钮
- powerbi - 如何在 Power Bi/DAX 中对代表在每个日期接听的电话总数进行排名?
- sql-server - Laravel MS SQL DB::RAW 查询返回“无效的列名”
- azure - Powershell 脚本继续要求我使用 Select-AzureSubscription 虽然我已经调用它