1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
# Write out the (hex) textual representation of numbers.
== code
# instruction effective address register displacement immediate
# . op subop mod rm32 base index scale r32
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
# convert the lowest nibble of eax to ascii and return it in the lowest byte of eax
to-hex-char: # in/eax: int -> out/eax: int
# no error checking; accepts argument in eax
# if (eax <= 9) return eax + '0'
3d/compare-eax-with 0x9/imm32/9
7f/jump-if-> $to-hex-char:else/disp8
05/add-to-eax 0x30/imm32/0
c3/return
$to-hex-char:else:
# otherwise return eax + 'a' - 10
05/add-to-eax 0x57/imm32/a-10
c3/return
append-byte-hex: # f: (addr stream byte), n: int
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
50/push-eax
# AL = convert upper nibble to hex
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax
c1/shift 5/subop/logic-right 3/mod/direct 0/rm32/eax . . . . . 4/imm8 # shift eax right by 4 bits, while padding zeroes
25/and-eax 0xf/imm32
# . AL = to-hex-char(AL)
e8/call to-hex-char/disp32
# append-byte(f, AL)
# . . push args
50/push-eax
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
# . . call
e8/call append-byte/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# AL = convert lower nibble to hex
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax
25/and-eax 0xf/imm32
# . AL = to-hex-char(AL)
e8/call to-hex-char/disp32
# append-byte(f, AL)
# . . push args
50/push-eax
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
# . . call
e8/call append-byte/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
$append-byte-hex:end:
# . restore registers
58/pop-to-eax
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-append-byte-hex:
# - check that append-byte-hex adds the hex textual representation
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# append-byte-hex(_test-stream, 0xa) # exercises digit, non-digit as well as leading zero
# . . push args
68/push 0xa/imm32
68/push _test-stream/imm32
# . . call
e8/call append-byte-hex/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-stream-equal(_test-stream, "0a", msg)
# . . push args
68/push "F - test-append-byte-hex"/imm32
68/push "0a"/imm32
68/push _test-stream/imm32
# . . call
e8/call check-stream-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . end
c3/return
write-int32-hex: # f: (addr stream byte), n: int
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
$write-int32-hex:hex-prefix:
# write(f, "0x")
# . . push args
68/push "0x"/imm32
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
$write-int32-hex:rest:
# write-int32-hex-bits(f, n, 32)
# . . push args
68/push 0x20/imm32
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
# . . call
e8/call write-int32-hex-bits/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
$write-int32-hex:end:
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
# print rightmost 'bits' of 'n'
# bits must be multiple of 4
write-int32-hex-bits: # f: (addr stream byte), n: int, bits: int
# pseudocode:
# bits -= 4
# while true
# if (bits < 0) break
# eax = n >> bits
# eax = eax & 0xf
# append-byte(f, AL)
# bits -= 4
#
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
50/push-eax
51/push-ecx
# ecx = bits-4
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0x10/disp8 . # copy *(ebp+16) to ecx
81 5/subop/subtract 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # subtract from ecx
$write-int32-hex-bits:loop:
# if (bits < 0) break
81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0/imm32 # compare ecx
7c/jump-if-< $write-int32-hex-bits:end/disp8
# eax = n >> bits
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 0xc/disp8 . # copy *(ebp+12) to eax
d3/>>ecx 5/subop/pad-zeroes 3/mod/direct 0/rm32/eax . . . . . . # shift eax right by ecx bits, padding zeroes
# eax = to-hex-char(AL)
25/and-eax 0xf/imm32
e8/call to-hex-char/disp32
# append-byte(f, AL)
# . . push args
50/push-eax
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
# . . call
e8/call append-byte/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# bits -= 4
81 5/subop/subtract 3/mod/direct 1/rm32/ecx . . . . . 4/imm32 # subtract from ecx
eb/jump $write-int32-hex-bits:loop/disp8
$write-int32-hex-bits:end:
# . restore registers
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-write-int32-hex:
# - check that write-int32-hex prints the hex textual representation
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write-int32-hex(_test-stream, 0x8899aa)
# . . push args
68/push 0x8899aa/imm32
68/push _test-stream/imm32
# . . call
e8/call write-int32-hex/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-stream-equal(_test-stream, "0x008899aa", msg)
# . . push args
68/push "F - test-write-int32-hex"/imm32
68/push "0x008899aa"/imm32
68/push _test-stream/imm32
# . . call
e8/call check-stream-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . end
c3/return
# . . vim:nowrap:textwidth=0
|