如何在程序集中打印数组?

时间:2017-12-13 09:38:24

标签: assembly

这是我为读取十六进制数而编写的函数:

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到屏幕。有人可以帮我解决这个问题吗?

1 个答案:

答案 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 - 两个问题:

  1. 这种情况发生在循环外,因此您将在循环内输出相同的char(幸运的是,esi不会修改writechar)。
  2. 这是在al之前完成的,所以你会cld,它会减少DF=1,然后在循环内esi是“迟到”切换到前进方向
  3. 实际上你的整个代码看起来好像它一直希望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