stabs->dwarf
[staff/goc4/2018bti7061.git] / asm-7-procedures / examples / hexdump2 / hexdump2.asm
CommitLineData
462e967d
CG
1; Executable name : hexdump2
2; Version : 1.0
3; Created date : 4/15/2009
4; Last update : 4/20/2009
5; Author : Jeff Duntemann
6; Modified by : Emmanuel Benoist
7; Date modification: 11/14/2016
8; Description : A simple hex dump utility demonstrating the use of
9; assembly language procedures
10;
11; Modification : Adapatation for 64-bit architecture
12;
13; Build using these commands:
14; nasm -f elf64 -g -F stabs hexdump2.asm
15; ld -o hexdump2 hexdump2.o
16;
17
18SECTION .bss ; Section containing uninitialized data
19
20 BUFFLEN EQU 10
21 Buff resb BUFFLEN
22
23SECTION .data ; Section containing initialised data
24
25; Here we have two parts of a single useful data structure, implementing
26; the text line of a hex dump utility. The first part displays 16 bytes in
27; hex separated by spaces. Immediately following is a 16-character line
28; delimited by vertical bar characters. Because they are adjacent, the two
29; parts can be referenced separately or as a single contiguous unit.
30; Remember that if DumpLin is to be used separately, you must append an
31; EOL before sending it to the Linux console.
32
33DumpLin: db " 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
34DUMPLEN EQU $-DumpLin
35ASCLin: db "|................|",10
36ASCLEN EQU $-ASCLin
37FULLLEN EQU $-DumpLin
38
39; The HexDigits table is used to convert numeric values to their hex
40; equivalents. Index by nybble without a scale: [HexDigits+eax]
41HexDigits: db "0123456789ABCDEF"
42
43; This table is used for ASCII character translation, into the ASCII
44; portion of the hex dump line, via XLAT or ordinary memory lookup.
45; All printable characters "play through" as themselves. The high 128
46; characters are translated to ASCII period (2Eh). The non-printable
47; characters in the low 128 are also translated to ASCII period, as is
48; char 127.
49DotXlat:
50 db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
51 db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
52 db 20h,21h,22h,23h,24h,25h,26h,27h,28h,29h,2Ah,2Bh,2Ch,2Dh,2Eh,2Fh
53 db 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h,3Ah,3Bh,3Ch,3Dh,3Eh,3Fh
54 db 40h,41h,42h,43h,44h,45h,46h,47h,48h,49h,4Ah,4Bh,4Ch,4Dh,4Eh,4Fh
55 db 50h,51h,52h,53h,54h,55h,56h,57h,58h,59h,5Ah,5Bh,5Ch,5Dh,5Eh,5Fh
56 db 60h,61h,62h,63h,64h,65h,66h,67h,68h,69h,6Ah,6Bh,6Ch,6Dh,6Eh,6Fh
57 db 70h,71h,72h,73h,74h,75h,76h,77h,78h,79h,7Ah,7Bh,7Ch,7Dh,7Eh,2Eh
58 db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
59 db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
60 db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
61 db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
62 db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
63 db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
64 db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
65 db 2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh,2Eh
66
67
68SECTION .text ; Section containing code
69
70;-------------------------------------------------------------------------
71; ClearLine: Clear a hex dump line string to 16 0 values
72; UPDATED: 4/15/2009
73; IN: Nothing
74; RETURNS: Nothing
75; MODIFIES: Nothing
76; CALLS: DumpChar
77; DESCRIPTION: The hex dump line string is cleared to binary 0 by
78; calling DumpChar 16 times, passing it 0 each time.
79
80ClearLine:
81 push rax ; Save all used registers
82 push rdx
83 mov edx,15 ; We're going to go 16 pokes, counting from 0
84.poke: mov eax,0 ; Tell DumpChar to poke a '0'
85 call DumpChar ; Insert the '0' into the hex dump string
86 sub edx,1 ; DEC doesn't affect CF!
87 jae .poke ; Loop back if EDX >= 0
88 pop rdx ; Restore all used registers
89 pop rax ;
90 ret ; Go home
91
92
93;-------------------------------------------------------------------------
94; DumpChar: "Poke" a value into the hex dump line string.
95; UPDATED: 4/15/2009
96; IN: Pass the 8-bit value to be poked in EAX.
97; Pass the value's position in the line (0-15) in EDX
98; RETURNS: Nothing
99; MODIFIES: EAX, ASCLin, DumpLin
100; CALLS: Nothing
101; DESCRIPTION: The value passed in EAX will be put in both the hex dump
102; portion and in the ASCII portion, at the position passed
103; in EDX, represented by a space where it is not a
104; printable character.
105
106DumpChar:
107 push rbx ; Save caller's RBX
108 push rdi ; Save caller's RDI
109; First we insert the input char into the ASCII portion of the dump line
110 mov bl,byte [DotXlat+eax] ; Translate nonprintables to '.'
111 mov byte [ASCLin+edx+1],bl ; Write to ASCII portion
112; Next we insert the hex equivalent of the input char in the hex portion
113; of the hex dump line:
114 mov ebx,eax ; Save a second copy of the input char
115 lea edi,[edx*2+edx] ; Calc offset into line string (ECX X 3)
116; Look up low nybble character and insert it into the string:
117 and eax,0000000Fh ; Mask out all but the low nybble
118 mov al,byte [HexDigits+eax] ; Look up the char equiv. of nybble
119 mov byte [DumpLin+edi+2],al ; Write the char equiv. to line string
120; Look up high nybble character and insert it into the string:
121 and ebx,000000F0h ; Mask out all the but second-lowest nybble
122 shr ebx,4 ; Shift high 4 bits of byte into low 4 bits
123 mov bl,byte [HexDigits+ebx] ; Look up char equiv. of nybble
124 mov byte [DumpLin+edi+1],bl ; Write the char equiv. to line string
125;Done! Let's go home:
126 pop rdi ; Restore caller's RDI
127 pop rbx ; Restore caller's RBX
128 ret ; Return to caller
129
130
131;-------------------------------------------------------------------------
132; PrintLine: Displays DumpLin to stdout
133; UPDATED: 4/15/2009
134; IN: Nothing
135; RETURNS: Nothing
136; MODIFIES: Nothing
137; CALLS: Kernel sys_write
138; DESCRIPTION: The hex dump line string DumpLin is displayed to stdout
139; using INT 80h sys_write. All GP registers are preserved.
140
141PrintLine:
142 push rax ; Save all used registers
143 push rbx ; Save all used registers
144 push rcx ; Save all used registers
145 push rdx ; Save all used registers
146 mov eax,4 ; Specify sys_write call
147 mov ebx,1 ; Specify File Descriptor 1: Standard output
148 mov ecx,DumpLin ; Pass offset of line string
149 mov edx,FULLLEN ; Pass size of the line string
150 int 80h ; Make kernel call to display line string
151 pop rdx ; Restore all caller's registers
152 pop rcx ;
153 pop rbx ;
154 pop rax ;
155 ret ; Return to caller
156
157
158;-------------------------------------------------------------------------
159; LoadBuff: Fills a buffer with data from stdin via INT 80h sys_read
160; UPDATED: 4/15/2009
161; IN: Nothing
162; RETURNS: # of bytes read in EBP
163; MODIFIES: ECX, EBP, Buff
164; CALLS: Kernel sys_write
165; DESCRIPTION: Loads a buffer full of data (BUFFLEN bytes) from stdin
166; using INT 80h sys_read and places it in Buff. Buffer
167; offset counter ECX is zeroed, because we're starting in
168; on a new buffer full of data. Caller must test value in
169; EBP: If EBP contains zero on return, we hit EOF on stdin.
170; Less than 0 in EBP on return indicates some kind of error.
171
172LoadBuff:
173 push rax ; Save caller's EAX
174 push rbx ; Save caller's EBX
175 push rdx ; Save caller's EDX
176 mov eax,3 ; Specify sys_read call
177 mov ebx,0 ; Specify File Descriptor 0: Standard Input
178 mov ecx,Buff ; Pass offset of the buffer to read to
179 mov edx,BUFFLEN ; Pass number of bytes to read at one pass
180 int 80h ; Call sys_read to fill the buffer
181 mov ebp,eax ; Save # of bytes read from file for later
182 xor ecx,ecx ; Clear buffer pointer ECX to 0
183 pop rdx ; Restore caller's EDX
184 pop rbx ; Restore caller's EBX
185 pop rax ; Restore caller's EAX
186 ret ; And return to caller
187
188
189GLOBAL _start
190
191; ------------------------------------------------------------------------
192; MAIN PROGRAM BEGINS HERE
193;-------------------------------------------------------------------------
194_start:
195 nop ; No-ops for GDB
196 nop
197
198; Whatever initialization needs doing before the loop scan starts is here:
199 xor esi,esi ; Clear total byte counter to 0
200 call LoadBuff ; Read first buffer of data from stdin
201 cmp ebp,0 ; If ebp=0, sys_read reached EOF on stdin
202 jbe Exit
203
204; Go through the buffer and convert binary byte values to hex digits:
205Scan:
206 xor eax,eax ; Clear EAX to 0
207 mov al,byte[Buff+ecx] ; Get a byte from the buffer into AL
208 mov edx,esi ; Copy total counter into EDX
209 and edx,0000000Fh ; Mask out lowest 4 bits of char counter
210 call DumpChar ; Call the char poke procedure
211
212; Bump the buffer pointer to the next character and see if buffer's done:
213 inc esi ; Increment total chars processed counter
214 inc ecx ; Increment buffer pointer
215 cmp ecx,ebp ; Compare with # of chars in buffer
216 jb .modTest ; If we've processed all chars in buffer...
217 call LoadBuff ; ...go fill the buffer again
218 cmp ebp,0 ; If ebp=0, sys_read reached EOF on stdin
219 jbe Done ; If we got EOF, we're done
220
221; See if we're at the end of a block of 16 and need to display a line:
222.modTest:
223 test esi,0000000Fh ; Test 4 lowest bits in counter for 0
224 jnz Scan ; If counter is *not* modulo 16, loop back
225 call PrintLine ; ...otherwise print the line
226 call ClearLine ; Clear hex dump line to 0's
227 jmp Scan ; Continue scanning the buffer
228
229; All done! Let's end this party:
230Done:
231 call PrintLine ; Print the "leftovers" line
232Exit: mov eax,1 ; Code for Exit Syscall
233 mov ebx,0 ; Return a code of zero
234 int 80H ; Make kernel call