title: Memory corruption in assembly?
body: <p>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.</p>
  
  <p>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.</p>
  
  <p>When the PrintLineNum function works, it prints the current line number to the left of the line</p>
  
  <pre><code>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.| 
  </code></pre>
  
  <p>However, when functionality for printing the hexadecimal string is re-enabled, it begins to "skip".</p>
  
  <pre><code>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.
  </code></pre>
  
  <p>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.</p>
  
  <p>Thanks for any assistance!</p>
  
  <pre><code>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 &lt;= 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
  </code></pre>