2

我目前有一个汇编程序,它模仿 Linux 中的 hexdump 系统功能。本质上,它打印当前行号,将二进制值转换为十六进制字符串,并显示与十六进制字符串关联的当前 ASCII。

我的打印行号系统出现问题。该函数仅在代码的其他部分被注释掉时才起作用——否则会产生不正确的结果。但是,我不明白为什么代码的两部分应该相互影响,因为使用的寄存器已被清除。

当 PrintLineNum 函数工作时,它将当前行号打印到行的左侧

000000E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |r Linux, using N.| 
000000F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |ASM 2.05,.;    d.| 
0000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |emonstrating the.| 
0000011 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  | conversion of b.| 

但是,当重新启用打印十六进制字符串的功能时,它开始“跳过”。

000000E 72 20 4C 69 6E 75 78 2C 20 75 73 69 6E 67 20 4E  |r Linux, using N.| 
000000F 40 53 4D 20 32 2E 30 35 2C 0A 3B 20 20 20 20 64  |ASM 2.05,.;    d.| 
0000000 65 6D 6F 6E 73 74 72 60 74 69 6E 67 20 74 68 65  |emonstrating the.| 
0000000 20 63 6F 6E 76 65 72 73 69 6F 6E 20 6F 66 20 62  | conversion of b.| 
0000002 69 6E 60 72 79 20 76 60 6C 75 65 73 20 74 6F 20  |inary values to .| 
0000003 68 65 78 60 64 65 63 69 6D 60 6C 20 73 74 72 69  |hexadecimal stri.| 
0000004 6E 67 73 2E 0A 3B 20 20 20 20 49 74 20 60 63 74  |ngs..;    It act.

我不确定为什么打印十六进制字符串会影响行数——据我所知,这两个操作是独立的。任何建议、建议或改进都会有所帮助。请注意,其中一些代码来自 Duntemann 的“Assembly Language - Step by Step”。我刚刚添加了行号和 ASCII 打印输出。我在下面标记了有问题的代码部分。

感谢您的帮助!

SECTION .bss                    ; Section containing uninitialized data

        BUFFLEN equ 16          ; We read the file 16 bytes at a time
        Buff:   resb BUFFLEN    ; Text buffer itself

SECTION .data                   ; Section containing initialised data

        ; storage location for line number
        LineNStr: dd "000001"
        LINNLEN equ $-LineNStr

        LineNum: dd 1
        LINLEN equ $-LineNum

        ; storage location for ASCII string
        TextStr:        db " |................ | ",10
        TEXTLEN equ $-TextStr

        ; storage location for hex string
        HexStr: db " 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ",
        HEXLEN equ $-HexStr

        ; conversion tables
        Digits: db "0123456789ABCDEF"

        Ascii:  
                db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
                db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
                db 20h,21h,22h,23h,24h,25h,26h,27h,28h,29h,2Ah,2Bh,2Ch,2Dh,2Eh,2Fh
                db 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h,3Ah,3Bh,3Ch,3Dh,3Eh,3Fh
                db 40h,41h,42h,43h,44h,45h,46h,47h,48h,49h,4Ah,4Bh,4Ch,4Dh,4Eh,4Fh
                db 50h,51h,52h,53h,54h,55h,56h,57h,58h,59h,5Ah,5Bh,5Ch,5Dh,5Eh,5Fh
                db 60h,61h,62h,63h,64h,65h,66h,67h,68h,69h,6Ah,6Bh,6Ch,6Dh,6Eh,6Fh
                db 70h,71h,72h,73h,74h,75h,76h,77h,78h,79h,7Ah,7Bh,7Ch,7Dh,7Eh,2Eh
                db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
                db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
                db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
                db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
                db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
                db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
                db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
                db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh

SECTION .text                   ; Section containing code

; All done! Let's end this party:
Done:
        mov eax,1               ; Code for Exit Syscall
        mov ebx,0               ; Return a code of zero
        int 80H                 ; Make kernel call

global  _start                  ; Linker needs this to find the entry point!

_start:
        nop                     ; This no-op keeps gdb happy...

; Read a buffer full of text from stdin:
Read:
        mov eax,3               ; Specify sys_read call
        mov ebx,0               ; Specify File Descriptor 0: Standard Input
        mov ecx,Buff            ; Pass offset of the buffer to read to
        mov edx,BUFFLEN         ; Pass number of bytes to read at one pass
        int 80h                 ; Call sys_read to fill the buffer
        mov ebp,eax             ; Save # of bytes read from file for later
        cmp eax,0               ; If eax=0, sys_read reached EOF on stdin
        je Done                 ; Jump If Equal (to 0, from compare)

; Set up the registers for the process buffer step:
        mov esi,Buff            ; Place address of file buffer into esi
        mov edi,HexStr          ; Place address of line string into edi
        xor ecx,ecx             ; Clear line string pointer to 0

; Go through the buffer and convert binary values to hex digits:
Scan:
        xor eax,eax             ; Clear eax to 0

; Convert text into ASCII string:
        mov al,byte [esi+ecx]           ; Get current location into al
        mov bl,byte [Ascii+eax]         ; Use lookup table to perform conversions
        mov byte [TextStr+ecx+2],bl     ; Write to ASCII text block

; Here we calculate the offset into the line string, which is ecx X 3
        mov edx,ecx             ; Copy the pointer into line string into edx
;       shl edx,1               ; Multiply pointer by 2 using left shift
;       add edx,ecx             ; Complete the multiplication X3
        lea edx,[edx*2+edx]     ; The lea operation performs a combination of the two operations above

; Get a character from the buffer and put it in both eax and ebx:
        mov al,byte [esi+ecx]   ; Put a byte from the input buffer into al
        mov ebx,eax             ; Duplicate the byte in bl for second nybble

;;;;;;;;;;;;;;;;;; When this section is commented out, the line printout works properly
; Look up low nybble character and insert it into the string:
        and al,0Fh                 ; Mask out all but the low nybble
        mov al,byte [Digits+eax]   ; Look up the char equivalent of nybble
        mov byte [HexStr+edx+2],al ; Write the char equivalent to line string

; Look up high nybble character and insert it into the string:
        shr bl,4                ; Shift high 4 bits of char into low 4 bits
        mov bl,byte [Digits+ebx] ; Look up char equivalent of nybble
        mov byte [HexStr+edx+1],bl ; Write the char equivalent to line string
;;;;;;;;;;;;;;;;;; When this section is commented out, the line printout works properly

; Bump the buffer pointer to the next character and see if we're done:
        inc ecx         ; Increment line string pointer
        cmp ecx,ebp     ; Compare to the number of characters in the buffer
        jna Scan        ; Loop back if ecx is <= number of chars in buffer

; Print the current line number prior to printing any other information
        Call PrintLineNum ; print line number function

; Write the line of hexadecimal values to stdout:
        mov eax,4               ; Specify sys_write call
        mov ebx,1               ; Specify File Descriptor 1: Standard output
        mov ecx,HexStr          ; Pass offset of line string
        mov edx,HEXLEN          ; Pass size of the line string
        int 80h                 ; Make kernel call to display line string

; Write the line of ASCII values to stdout:
        mov eax,4               ; Specify sys_write call
        mov ebx,1               ; Specify File Descriptor 1: Standard output
        mov ecx,TextStr         ; Pass offset of line string
        mov edx,TEXTLEN         ; Pass size of the line string
        int 80h                 ; Make kernel call to display line string
        jmp Read                ; Loop back and load file buffer again

PrintLineNum:
; Clear out the registers
        xor eax,eax
        xor ebx,ebx

; Get data into registers
        mov al,byte [LineNum]   ; Put a byte from the input buffer into al
        mov ebx,eax             ; Duplicate the byte in bl for second nybble

; Look up low nybble character and insert it into the string:
        and al,0Fh                 ; Mask out all but the low nybble
        mov al,byte [Digits+eax]   ; Look up the char equivalent of nybble
        mov byte [LineNStr+6],al ; Write the char equivalent to line string

; Look up high nybble character and insert it into the string:
        shr bl,4                ; Shift high 4 bits of char into low 4 bits
        mov bl,byte [Digits+ebx] ; Look up char equivalent of nybble
        mov byte [LineNStr+5],bl ; Write the char equivalent to line string

; Increment line number
        mov eax,[LineNum]
        inc eax
        mov [LineNum],eax

; Write the line number to stdout:
        mov eax,4               ; Specify sys_write call
        mov ebx,1               ; Specify File Descriptor 1: Standard output
        mov ecx,LineNStr        ; Pass offset of line string
        mov edx,LINNLEN
        int 80h                 ; Make kernel call to display line string
        ret
4

1 回答 1

6

您的代码中有一个错误。

问题出在这一行:

    jna Scan        ; Loop back if ecx is <= number of chars in buffer

这意味着您将循环 17 次,而不是 16 次。 ruslik 的评论暗示了这一点(原始TextStr字符串是 16 个点后跟一个空格,那么为什么要替换空格?)。

它打破行号的原因是mov byte [HexStr+edx+2],al标记部分HexStr在第 17 次迭代时溢出,并写入Digits表中。它也破坏了十六进制转储(查看第一条虚线:aofdemonstrating已转储为60,而不是61)。

尝试:

    jb  Scan        ; Loop back if ecx is < number of chars in buffer

反而。

于 2010-10-08T00:12:04.863 回答