String 程序集x86:LEA和MOVSB是否更改我的源字符串?
我正在用汇编程序x86(Windows中的英特尔32位)编写一个程序。我正在做一个程序(用于家庭作业),在这个程序中我必须对字符串进行加密,我将用两个字符组成的块进行迭代。我使用EBX移动源字符串,将其增加2。现在,我没有进入程序的密码部分,因为我遇到了比这更小的问题。问题是,当一个块有相同的字符时,比如“AA”,它不需要经过加密过程,所以我必须按原样将“AA”复制到结果字符串中。我就是这样做的:String 程序集x86:LEA和MOVSB是否更改我的源字符串?,string,assembly,x86,nasm,String,Assembly,X86,Nasm,我正在用汇编程序x86(Windows中的英特尔32位)编写一个程序。我正在做一个程序(用于家庭作业),在这个程序中我必须对字符串进行加密,我将用两个字符组成的块进行迭代。我使用EBX移动源字符串,将其增加2。现在,我没有进入程序的密码部分,因为我遇到了比这更小的问题。问题是,当一个块有相同的字符时,比如“AA”,它不需要经过加密过程,所以我必须按原样将“AA”复制到结果字符串中。我就是这样做的: CypheLoop: call VerifyBlock cmp byte[caracblock],
CypheLoop:
call VerifyBlock
cmp byte[caracblock], 0
je End
cmp byte[caracblock], 1
je AddLastCharacter
cmp byte[caracblock], 2
je AddNoCiphedBlock
jmp CipheLoop
VerifyBlock负责查看块的一致性,它根据其特征将“caracblock”更改为数字。0表示块为空(表示字符串已结束),1表示块中只有一个字符(例如“ABC”将有一个只带“C”的块),2表示块中的字符必须按原样复制(如前所述,另一种情况是如果块中有空格),或3表示块需要加密。
到目前为止,一切都很顺利!程序添加字符并按预期完成,但是,AddNoCiphedBlock有一些意外行为,,如下所示:
AddNoCiphedBlock:
mov esi, 0
mov edi, 0
mov ecx, 2
lea esi, [sourcestring + ebx]
lea edi, [resultstring + ebx]
rep movsb
add ebx, 2
jmp CipheLoop
问题不在于它返回什么(尽管我得到的不是我所期望的),而在于,出于某种原因,源字符串被改变了。如果我写“AA”,我会得到“AA”,对吗。如果我写“AABB”,我会得到“AABB”,这是正确的。如果我写“AABBCC”,我会得到“AABBAA”。源字符串在使用AddNoCiphedBlock后,会更改为“AABBAA”,并且情况会继续恶化这是源字符串在处理过程中发生的情况
AABBCC
AABBAA
AABBAA
AABBAABB
AABBAABB
AABBAABBAA
为什么会这样?我只是从源代码中复制了一些东西!“我的源字符串”和“结果字符串”在.bss部分中都是“sourcestring resd 1”和“resultstring resd 1”。我使用_get获取源字符串。我试图给出尽可能多的解释和细节,我甚至不能理解它出错的原因。您使用的
获取并且缓冲区只有4个字节长(resd 1
),而您使它们溢出。
当字符串为4个输入字符或更长时,终止的0
字节在缓冲区之外。(获取
总共存储5个字节:数据加上一个终止符。4个'a'
字节放入源字符串:resd 1
,终止的0
是结果字符串:resd 1
的第一个字节
如果它们相邻,则将src的前2个字节复制到dst会覆盖src的0
字节,因为它也是dst的第一个字节
使用(大得多的)缓冲区,和/或使用以读取字节数为上限的函数(缓冲区大小)
如何调试: 一旦您知道某个字节正在更改,而您希望它不会更改,请在调试器中对该地址设置一个监视点。然后它将在更改它的指令处停止 在您的例子中,这将是
“AABB”
末尾的终止0
字节。地址是sourcestring+4
,因为它位于4个ASCII字节之后。然后让它运行,您将看到它在rep movsb
处停止
此外,在执行此操作时,您可能会注意到缓冲区只有4字节长,因此sourcestring+4
位于4字节缓冲区之外,和/或地址与resultstring
的地址相同
守则检讨:
movesi,0
是无用的;您已经使用lea
覆盖了EDI。另外,使用rep movsb
进行固定大小的2字节拷贝也非常复杂
movzx eax, word [sourcestring + ebx] ; 2-byte load
mov [resultstring + ebx], ax ; 2-byte store
或者,如果您坚持使用
movs
,请使用movsw
一次。(不要rep movsw
,这样您就不必设置ECX)。可能源字符串和结果字符串重叠。您是否只为db 0
或其他内容保留了1字节的空间?查看LEA后面的指针值,以确保绝对值(EDI-ESI)>=ECX
,否则您的副本会重叠。(无关:movesi,0
无效,您已经在用lea
覆盖旧值)我将.bss中的两个字符串声明为resd 1。我注意到,最终,如果这是您的代码块的一部分,则会更容易查看。对此,我很抱歉,我是该站点的新用户,并且我仍然在尝试,在编程方面还不是很专业。我按照您的要求做了。没关系,EDI-ESI>=ECX。您不必是专家在编程时,你可以问一个问题,但你必须从读者的角度来思考。试着让你的示例代码块自包含。