2

現在、Linux の hexdump システム関数をモデルにしたアセンブリ プログラムがあります。基本的に、現在の行番号を出力し、バイナリ値を 16 進文字列に変換し、16 進文字列に関連付けられている現在の ASCII も表示します。

行番号を印刷するシステムで問題が発生しています。この関数は、コードの他の部分がコメント アウトされている場合にのみ機能します。コメント アウトされていない場合、正しくない結果が生成されます。ただし、使用されているレジスタがクリアされるため、コードの 2 つの部分が互いに影響を与える理由がわかりません。

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.| 

ただし、16 進文字列を出力する機能を再度有効にすると、「スキップ」が開始されます。

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.

16 進数の文字列を出力すると行数に影響する理由はわかりません。2 つの操作は、私が知る限り独立しています。アドバイス、提案、または改善があれば役立ちます。このコードの一部は 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

コードに off-by-one エラーがあります。

問題は次の行にあります。

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

これは、16 回ではなく 17 回ループすることを意味します。これは ruslik のコメントによって示唆されています (元のTextStr文字列は 16 ドットの後にスペースが続くのに、なぜスペースが置き換えられるのですか?)。

行番号付けを中断する理由はmov byte [HexStr+edx+2],al、マークされたセクションで 17 回目の繰り返しでオーバーフローHexStrし、Digitsテーブルに書き込むためです。これは 16 進ダンプも壊します (最初の破線を見てください: the aof demonstratinghas been dumped as 60, not 61)。

試す:

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

代わりは。

于 2010-10-08T00:12:04.863 に答える