現在、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