这是我为读取十六进制数而编写的函数:
readhex:
xor ebx,ebx
.nextchar:
call readchar ;function to read a char and store it in al
;jumps to the end if Enter
cmp al,13
je .end
call writechar ;function to print a char from al
cmp al,'A'
jb .dec ;it might be a number
cmp al,'F'
ja .error
inc ebx ;counts size of the array
jmp .next
.dec:
cmp al,48
jb .error
cmp al,57
ja .error
inc ebx
.next:
;stores the character
stosb
jmp .nextchar
.error:
call writeln ;function for linebreak
mov eax, errormessage
call writestr ;function to print a string on the screen
call writeln
xor ebx,ebx
jmp .nextchar
.end:
ret
以下是打印此号码的功能:
printhex:
push edx
push esi
;prints the 0X prefix for a hex number
mov eax, prefix ;prefix is a string containing "0X"
call writestr ;function to print a string
mov ecx,ebx
lodsb
.print:
call writechar ;function to print a char from al
cld
loop .print
call writeln
pop esi
pop edx
ret
主要功能:
;reads a hex number
mov eax,readahexnumber ;displays a message asking for a hex input
call writeln
call writestr
lea di,[string]
call readhex ;function to read a hexadecimal number
call writeln
;prints the hex number
lea esi,[string]
call printhex
call writeln
ret
程序要求输入一个数字,读取它然后显示0x前缀和数字,但在其末尾添加额外的字符。即如果输入为AB1,程序将打印0xAB1AAA到屏幕。有人可以帮我解决这个问题吗?
答案 0 :(得分:1)
一般答案是,必须学会使用调试器,您必须能够单步执行指令,并随时检查任何寄存器值和任何内存值,以便您可以验证/推理您的每一个假设/期望。从那里可以很容易地找到这样的问题,在调试器中很明显你的代码有什么问题以及输出AAA
的原因。
在没有调试器的情况下进行汇编编程就像组装机器人蒙上眼睛一样。你可以做到这一点,但需要付出更多的努力(如果你才华横溢,大约100倍以上,1000 + x或者如果你没有天赋就让你完全无法完成你的任务 - 而且我并不夸张这个,100x从我的经验来看是非常保守的估计,因为我不得不在没有调试器的情况下修改我的代码多年(没有计算机,只需要用纸和笔),所以我可以比较一下。
一些注释......你的函数几乎不是“readhex”和“printhex”,更像是“readstring_only0to9AtoF_valid”“writestring_with_hex_prefix”。 “读/写十六进制”听起来更像是将转换为/来自二进制值。
lea di,[string]
应该是lea edi,[string]
,让我有点奇怪,为什么代码在没有它的情况下适合你,你可能已经将edi
设置为{{1}中的其他有效地址之前,所以高32位已经正常,或者汇编器正在静默地将其修复为.data
,或者地址是值< 65536(最不可能),如果你真的edi
,请在调试器中检查反汇编程序,lea di
之前edi
中的值是多少。所以你知道确切的原因,为什么它偶然为你工作,即使有bug(这个bug实际上很难在调试器中发现 - 只要它偶然起作用 - 如果你不是推理关于每一条指令都很深入。)
lea
问题:
printhex:
加载输入的第一个字符,并调整 mov ecx,ebx
lodsb
- 两个问题:
esi
不会修改writechar
)。al
之前完成的,所以你会cld
,它会减少DF=1
,然后在循环内esi
是“迟到”切换到前进方向实际上你的整个代码看起来好像它一直希望DF = 0,所以把单cld
放在代码开头附近的地方,然后忘了它(除非你要添加一些函数cld
,然后它应该在退出之前恢复std
。
cld
Why loop
is slow - 而是使用.print:
call writechar ;function to print a char from al
cld
loop .print
dec ecx
。但是,您可以使用jnz .print
作为计数器,这样您也可以删除ebx
并保持mov ecx,ebx
完好无损,使用ecx
循环播放。
而dec ebx + jnz
在循环内部毫无用处。如果您需要,应在第一次cld
之前使用。
我只是猜测的另一个问题,因为你没有显示你的数据定义(在关于装配,数据 - 值和结构的问题中非常糟糕 - 通常更重要比代码,所以把它们排除在外是错误的,不要再这样做了。)
lodsb
mov eax, prefix ;prefix is a string containing "0X"
call writestr ;function to print a string
字符串可能缺少nul终止符,prefix
缓冲区就在它之后定义。所以这个string
将输出整个call writestr
内存,然后意外地找到一些零来停止。
剩余的0XAB1
输出来自您的角色循环。再次出现一个错误,从调试器中可以看出,就像AAA
显示前缀之后你在屏幕上已经有整数,而不仅仅是预期的“0X”。
call writestr
无效处理无效字符,它会重置readhex:
计数器,但不会重置输入缓冲区指针,因此ebx
之类的输入会将输入缓冲区设置为ABx1
},但仅返回AB1
中的1
。
我可能会重新安排整个检查:
ebx