Memory corruption in assembly?
I currently have an assembly program which is modeled after the hexdump system function in Linux. Essentially, it prints the current line number, converts the binary values to hexadecimal strings and also shows the current ASCII associated with the hexadecimal string.
I'm experiencing a problem with my system of printing line numbers. The function will only work when other parts of the code are commented out -- otherwise it produces incorrect results. However, I don't see why the two parts of code should have any effect on each other, since the registers utilized are cleared.
When the PrintLineNum function works, it prints the current line number to the left of the line
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.|
However, when functionality for printing the hexadecimal string is re-enabled, it begins to "skip".
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.
I'm not sure why printing the hexadecimal string affects the line count -- the two operations are independent as far as I can tell. Any advice, suggestions or improvements would help. Please note that some of this code is from Duntemann's "Assembly Language - Step by Step". I have just added the line numbers and ASCII printout. I have marked the problematic section of code below.
Thanks for any assistance!
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 th开发者_如何转开发e 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
You have an off-by-one error in your code.
The problem is on this line:
jna Scan ; Loop back if ecx is <= number of chars in buffer
which means that you will go round the loop 17 times, rather than 16. This is hinted at by ruslik's comment (the original TextStr
string is 16 dots followed by a space, so why does the space gets replaced?).
The reason it breaks the line numbering is that mov byte [HexStr+edx+2],al
in the marked section overflows HexStr
on the 17th iteration, and writes into the Digits
table. It breaks the hex dump as well (look at the first broken line: the a
of demonstrating
has been dumped as 60
, not 61
).
Try:
jb Scan ; Loop back if ecx is < number of chars in buffer
instead.
精彩评论