文件的简单汇编十六进制转储实用程

时间:2015-09-13 21:15:43

标签: assembly nasm

我正在读这本书(由Jeff Duntemann一步一步地提出汇编语言),在第9章中有这个例子:

;  Executable name : hexdump1
;  Version         : 1.0
;  Created date    : 4/4/2009
;  Last update     : 4/4/2009
;  Author          : Jeff Duntemann
;  Description     : A simple program in assembly for Linux, using NASM 2.05,
;    demonstrating the conversion of binary values to hexadecimal strings.
;    It acts as a very simple hex dump utility for files, though without the
;    ASCII equivalent column.
;
;  Run it this way:
;    hexdump1 < (input file)  
;
;  Build using these commands:
;    nasm -f elf -g -F stabs hexdump1.asm
;    ld -o hexdump1 hexdump1.o
;


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
HexStr: db " 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",10
HEXLEN equ $-HexStr
Digits: db “0123456789ABCDEF“

SECTION .text           ; Section containing code
global  _start          ; Linker needs this to find the entry point!
_start:
nop

; 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

; 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

; 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

; 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

; 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

; 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
jmp Read        ; Loop back and load file buffer again

; 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

假设我们已读取16个字节且缓冲区已满。 我有两个问题:

  1. 在我们扫描缓冲区中的所有字节后,ecx为16。 当jna Scan指令执行时,ecx等于ebp,我们跳转到Scanmov al,byte [esi+ecx]移入al的内容是什么,因为缓冲区的长度为16,最高的偏移数可能是15?

  2. 当我们阅读时会发生什么,让我们说10个字节,然后我们将它们写入stdout?它只是打印HexStr有10个新值,还有前一次写入的最后6个值?

1 个答案:

答案 0 :(得分:1)

在我看来,你已经为这本书找到了两本勘误表(看起来它是第3版,是你的早期吗?)。

的确,jna很可能是jl。否则垃圾会被转移到al,毫无疑问,你已经意识到循环正在通过17,而不是16字节。

你的第二点也是正确的。作者使用16的常量值,因此“尾部”逻辑甚至不存在。除非本书讨论了此示例的调试,否则您一次找到两个。是的,它将包括前一个读取的字符,除非输入本身只有10个字节,这是第一个也只是通过例程,此时这6个字节将是垃圾无意义(校正,第一个传递将显示零)因为这是初始化 - 感谢罗斯里奇。