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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
|
%ifndef _STRING_ASM
%define _STRING_ASM
; stack direction
; ---------------
; + = external
; - = local
;
; ^ must be getting old D:
;
; calling conventions
; push COUNT
; push SOURCE
; push DESTINATION
; call FUNCTION
; add sp, 6 (^ in the case of three WORDS)
;
; In C, for instance, this translate to:
; FUNCTION (DESTINATION, SOURCE, COUNT);
memset:
; Set memory with byte value
push bp ; setup stack frame
mov bp, sp ; ...
push si
push di
push cx
mov di, [bp + 4] ; destination address
mov ax, [bp + 6] ; requested byte value
mov cx, [bp + 8] ; count
cld ; will decrement address ES:DI
rep stosb ; while cx > 0
; store byte AL in ES:DI
pop cx
pop di
pop si
mov sp, bp
pop bp
ret
memcpy:
push bp ; setup stack frame
mov bp, sp ; ...
mov di, [bp + 4] ; destination buffer
mov si, [bp + 6] ; source buffer
mov cx, [bp + 8] ; count of characters to move
cld
rep movsb
mov sp, bp
pop bp
ret
strlen:
; Determine length of null terminated string
push bp ; setup stack frame
mov bp, sp ; ...
push cx
push si
xor cx, cx ; cx is counter
xor ax, ax ; ax is return value
mov si, [bp + 4] ; string address
.loop:
lodsb ; load byte from ES:SI into AL
cmp al, 0 ; zero?
je .return ; if so, we're done
inc cx ; if not, keep going
jmp .loop
.return:
mov ax, cx
pop si
pop cx
mov sp, bp
pop bp
ret
strnchr:
; Find first occurence of character in a string
push bp ; setup stack frame
mov bp, sp ; ...
push cx
push dx
push si
xor ax, ax ; ax is return value
mov si, [bp + 4] ; string address
mov dx, [bp + 6] ; needle character
mov cx, [bp + 8] ; counter
.loop:
lodsb ; load byte at si
cmp al, dl ; same as needle?
je .return ; if true: return
dec cx ; decrement counter
jne .loop ; counter zero?
.return:
mov ax, cx ; return index of character
pop si
pop dx
pop cx
mov sp, bp
pop bp
ret
strncmp:
; Determine difference between two strings
push bp ; setup stack frame
mov bp, sp ; ...
push bx ; save registers
push dx
push si
push di
mov di, [bp + 4] ; string2 address
mov si, [bp + 6] ; string1 address
mov cx, [bp + 8] ; limit to compare
.loop:
mov bx, [si] ; string1
mov dx, [di] ; string2
inc si ; next address, string1
inc di ; next address, string2
dec cx ; decrease byte counter
cmp bx, dx ; compare bytes
jne .diff ; Just die if not-equal
cmp cx, 0 ; If equal, check for null termination
jne .loop
.diff:
cmp bx, dx
jg .s1_larger
jl .s1_smaller
je .return
.s1_smaller:
mov ax, -1
jmp .return
.s1_larger:
mov ax, cx
.return:
pop di ; cleanup stack
pop si
pop dx
pop bx
mov sp, bp
pop bp
ret
strtok:
push bp
mov bp, sp
push bx ; save GPRs
push cx
push dx
push di
push si
xor ax, ax ; use: for delimter (LSB)
xor bx, bx ; use: base address for effective address calculations
xor cx, cx ; use: input string length counter
xor dx, dx ; use: temp for string comparison
xor si, si ; use: token array
xor di, di ; use: input string
mov di, [bp + 4] ; arg1 - input string (null terminated)
mov si, [bp + 6] ; arg2 - address of token array
mov al, [bp + 8] ; arg3 - delimter value
cld ; clear direction flag
.find_first:
mov dl, byte [di] ; Load byte from input string
cmp dl, al ; is it the delimiter?
jne .calculate_length ; if not, calculate length of string at this address
inc di ; else, scan next byte
jmp .find_first
.calculate_length:
push ax ; save delimiter
push di ; get length of null terminated string
call strlen
add sp, 2
mov cx, ax ; count is return value
pop ax ; restore delimiter
lea bx, [di] ; load initial address for _no_adjust
jmp .strtok_record_no_adjust
.strtok_record_eos:
mov byte [di], 0 ; Null terminate token
.strtok_record:
lea bx, [di + 1] ; The address following the null terminated token
; points to our new token address
.strtok_record_no_adjust:
mov [si], bx ; store address in results array
add si, 2 ; increment results array by one WORD
inc di ; increment input string
dec cx ; decrement input string length counter
.strtok_scan:
mov dl, byte [di] ; load byte from input string
cmp dl, 0 ; is it the end of the string?
je .strtok_return
cmp dl, al ; is this the delimiter?
je .strtok_record_eos ; if yes, record the address
dec cx ; decrement input string length counter
inc di ; increment input string
jmp .strtok_scan ; loop until scanning is done
cmp cx, 0 ; if the counter is not zero there's more to parse
jne .strtok_record ; loop until token parsing is done
.strtok_return:
mov ax, [bp + 6] ; return token array
pop si ; restore GPRs
pop di
pop dx
pop cx
pop bx
mov sp, bp
pop bp
ret
%endif ; _STRING_ASM
|