我目前有一个汇编程序,它是在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的“汇编语言 - 循序渐进”。我刚刚添加了行号和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
答案 0 :(得分:5)
您的代码中有一个错误的错误。
问题在于这一行:
jna Scan ; Loop back if ecx is <= number of chars in buffer
这意味着你将围绕循环17次,而不是16次。这是由ruslik的评论暗示的(原始的TextStr
字符串是16个点后跟一个空格,所以为什么空间被替换?)。
它打破行号的原因是标记部分中的mov byte [HexStr+edx+2],al
在第17次迭代时溢出HexStr
,并写入Digits
表。它也会破坏十六进制转储(请查看第一个折断的行:a
的{{1}}已被转储为demonstrating
,而不是60
。)
尝试:
61
代替。