如何解决汇编中字符串的长度对程序的工作方式感到困惑
我有一个汇编程序,该程序将一个字符串的长度写入ax寄存器中,但是我对某些指令有些困惑。
include \masm32\include64\masm64rt.inc
.data
string db "mama",0 ; so here I declared a string "mama". What happens in memory?
.code
main proc
xor ax,ax ; here I initialize ax with 0.
lea rsi,string ; here,I move in rsi register the adress of string,right? But how the string is stored in memory? Now in rsi I have the adress of the first char "m" of "mama" string?
@@: ; this sign creates an anonymous label
cmp byte ptr [rsi],0 ; so this says compare 0 with with 1 byte found at the adress pointed to by rsi,right? But I still don't get it. Why 1 byte? rsi is pointing to the first char or to the whole string?
jz @F ; jump if zero to the nearest @@ (forward)
inc ax ; so now i'm pointing to the first character so ax=1
inc rsi ; here what happen? The pointer is incremented to point to the second char from string?
jmp @B ; jump to the nearest @@ (backward)
@@:
invoke ExitProcess,0 ; invoke ExitProcess API
ret
main endp
end
我的困惑是我不确定我是否在考虑该程序的正确工作方式。我在想这个吗?
解决方法
inc ax
将16位值加1-处理器不知道ax
用于什么,但它知道这是16位加法。
inc rsi
将64位值加1-处理器不“知道”这是整数还是指针,但它确实知道这是64位加法。
此程序(尽管只是一个main
而没有任何功能)类似于一个strlen
函数:
short strlen ( char *p ) {
short count = 0;
while ( *p != '\0' ) {
count++; // increment 16-bit counter
p++; // increment 64-bit pointer by adding 1 to it
}
return count;
}
处理器将指针视为整数。取消引用时引用内存位置的整数。用汇编语言将指针递增1使其指向内存的下一个字节-内存位置具有整数编号的地址,因此两个连续的内存地址的值将相差1。
请注意,由于长度计数器使用了短的16位数据类型,如果字符串的实际长度> = 32768(如果已理解带符号的short
,则此程序将出现溢出错误)或> = 65536(如果使用unsigned short
代替short
)。
string db "mama",0
4个字节的0x6d 0x61 0x6d 0x61
('妈妈')存储在程序内存的数据段中的某个位置。 string
将第一个字节的地址存储在数据段中,即“ m”。
xor ax,ax
lea rsi,string
我认为操作应为lea rsi,[string]
。
(编辑:正如下面的评论中的Peter Cordes一样,在MASM汇编程序中,这种语法很好)
string
指向第一个字符的地址。现在rsi
指向相同的地址。
@@: ; this sign creates an anonymous label
cmp byte ptr [rsi],0
rsi指向整个字符串的开头。比较操作将rsi处的一个字节与零进行比较。如果为零,则假定字符串的结尾并跳转以退出:
jz @F ; jump if zero to the nearest @@ (forward)
如果rsi的值不为零:
inc ax
请记住,我们将字符串的长度存储在ax中。因此,对于每个有效字符,我们将ax
加1。
inc rsi
jmp @B ; jump to the nearest @@ (backward)
将rsi
指向下一个字符('a'),然后跳转到@@。第一个@@之后的代码将再次检查下一个字符('a')是否为零,并将计数(ax
)加1,因此ax
将变为2。这将继续直到到达0时,程序假定字符串结尾。
@@:
invoke ExitProcess,0 ; invoke ExitProcess API
ret
main endp
end
退出代码。
旁注:您可以在开头使用带有断点的gdb之类的程序来完成每个步骤。使用info registers
命令可以检查它们的值。向Google询问更高级的命令/方法。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。