-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathitsy-linux.asm
More file actions
444 lines (399 loc) · 9.66 KB
/
itsy-linux.asm
File metadata and controls
444 lines (399 loc) · 9.66 KB
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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
; nasm itsy-linux.asm -fbin -l itsy-linux.lst -o itsy-linux && chmod +x itsy-linux
%define link 0
%define immediate 080h
%macro head 4
%%link dd link
%define link %%link
%strlen %%count %1
db %3 + %%count, %1
xt_ %+ %2 dd %4
%endmacro
%macro primitive 2-3 0
head %1, %2, %3, $ + 4
%endmacro
%macro colon 2-3 0
head %1, %2, %3, docolon
%endmacro
%macro variable 3
head %1, %2, 0, dovar
val_ %+ %2 dd %3
%endmacro
%define TEXTORG 0x00400000
%define MEMSIZE 1048576
%define TIBSIZE 80
%define STACKSIZE 4096
%define TIBPTR TEXTORG + MEMSIZE - TIBSIZE
%define SP0 TIBPTR - 4
%define RP0 SP0 - STACKSIZE
BITS 32
org TEXTORG
ehdr: ; Elf32_Ehdr
db 0x7F, "ELF", 1, 1, 1, 0 ; e_ident
times 8 db 0
dw 2 ; e_type
dw 3 ; e_machine
dd 1 ; e_version
dd xt_abort + 4 ; e_entry
dd phdr - $$ ; e_phoff
dd 0 ; e_shoff
dd 0 ; e_flags
dw ehdrsize ; e_ehsize
dw phdrsize ; e_phentsize
dw 1 ; e_phnum
dw 0x28 ; e_shentsize without setting this size 'file' complains that elf header is corrupted
dw 0 ; e_shnum
dw 0 ; e_shstrndx
ehdrsize equ $ - ehdr
phdr: ; Elf32_Phdr
dd 1 ; p_type
dd 0 ; p_offset
dd $$ ; p_vaddr
dd $$ ; p_paddr
dd filesize ; p_filesz
dd MEMSIZE ; p_memsz
dd 7 ; p_flags
dd 0x1000 ; p_align
phdrsize equ $ - phdr
; esp - data stack pointer
; ebp - return stack pointer
; esi - Forth instruction pointer
; ebx - TOS (top of data stack)
variable 'state', state, 0
variable '>in', to_in, 0
variable '#tib', number_t_i_b, 0
variable 'dp', dp, freemem
variable 'base', base, 10
variable 'last', last, final
variable 'tib', t_i_b, TIBPTR
primitive 'bye', bye
xor eax, eax
inc eax ; eax holds 1 (syscall for exit)
xor ebx, ebx ; ebx holds 0 (exit code)
int 80h
primitive 'execute', execute
; ebx is TOS, so it contains address we will jump to
mov eax, ebx ; eax is important here, it is used by docolon and dovar
pop ebx ; we used TOS so we need to pop new value from the data stack
jmp dword[eax] ; now we jump to the address that is stored in the eax
primitive 'abort', abort
mov eax, dword[val_number_t_i_b]
mov dword[val_to_in], eax
xor ebp, ebp
mov dword[val_state], ebp
mov esp, SP0
mov ebp, RP0
mov esi, xt_interpret + 4
jmp next
primitive ',', comma
xchg eax, ebx
mov ebx, val_dp
mov edi, [ebx]
stosd
mov [ebx], edi
pop ebx
jmp next
primitive 'lit', lit
push ebx
lodsd
xchg eax, ebx
jmp next
primitive 'rot', rote
pop edx
pop eax
push edx
push ebx
xchg eax, ebx
jmp next
primitive 'drop', drop
pop ebx
jmp next
primitive 'dup', dupe
push ebx
jmp next
primitive 'swap', swap
xchg ebx, [esp]
jmp next
primitive '+', plus
pop eax
add ebx, eax
jmp next
primitive 'exit', exit
xchg ebp, esp
pop esi
xchg ebp, esp
next lodsd
jmp dword[eax] ; eax is later used by docolon and dovar
primitive '=', equals
pop eax
sub ebx, eax
sub ebx, 1
sbb ebx, ebx
jmp next
primitive '@', fetch
mov ebx, dword[ebx]
jmp next
primitive '!', store
pop dword[ebx]
pop ebx
jmp next
primitive '0branch', zero_branch
lodsd
test ebx, ebx
jne zerob_z
xchg eax, esi
zerob_z pop ebx
jmp next
primitive 'branch', branch
mov esi, dword[esi]
jmp next
primitive 'count', count
movzx eax, byte[ebx]
inc ebx
push ebx
mov ebx, eax
jmp next
primitive 'accept', accept
xor edx, edx
xchg edx, ebx ; now edx contains read byte count and ebx 0 (reading from stdin)
xor eax, eax
mov al, 3 ; sys_read
pop ecx ; buffer
int 80h
xchg ebx, eax ; eax after sys_read contains number of bytes read (negative number means error), let's move it to TOS
jmp next
primitive 'emit', emit
push ebx
xor eax, eax
mov al, 4 ; sys_write
xor ebx, ebx
inc ebx ; ebx now contains 1 (stdout)
mov ecx, esp ; buffer
mov edx, ebx ; write byte count
int 80h
pop ebx
pop ebx
jmp next
primitive '>number', to_number
pop edi
pop ecx
pop eax
to_numl test ebx, ebx
je to_numz
push eax
movzx eax, byte[edi]
cmp al, 'a'
jc to_nums
sub al, 32
to_nums cmp al, '9' + 1
jc to_numg
cmp al, 'A'
jc to_numh
sub al, 7
to_numg sub al, 48
cmp al, byte[val_base]
jnc to_numh
xchg eax, edx
pop eax
push edx
xchg eax, ecx
mul dword[val_base]
xchg eax, ecx
mul dword[val_base]
add ecx, edx
pop edx
add eax, edx
dec ebx
inc edi
jmp to_numl
to_numz push eax
to_numh push ecx
push edi
jmp next
primitive 'word', word
mov edi, dword[val_dp]
push edi
mov edx, ebx
mov ebx, dword[val_t_i_b]
mov ecx, ebx
add ebx, dword[val_to_in]
add ecx, dword[val_number_t_i_b]
wordf cmp ecx, ebx
je wordz
mov al, byte[ebx]
inc ebx
cmp dl, 32
jne word_exact1
cmp al, dl
jbe wordf
jmp wordc
word_exact1 cmp al, dl
je wordf
wordc inc edi
mov byte[edi], al
cmp ecx, ebx
je wordz
mov al, byte[ebx]
inc ebx
cmp dl, 32
jne word_exact2
cmp al, dl
jbe wordz
jmp wordc
word_exact2 cmp al, dl
jne wordc
wordz mov byte[edi + 1], 32
mov eax, dword[val_dp]
xchg eax, edi
sub eax, edi
mov byte[edi], al
sub ebx, dword[val_t_i_b]
mov dword[val_to_in], ebx
pop ebx
jmp next
primitive 'find', find
mov edi, val_last
findl push edi
push ebx
movzx ecx, byte[ebx]
inc ecx
findc mov al, byte[edi + 4]
and al, 07Fh
cmp al, byte[ebx]
je findm
pop ebx
pop edi
mov edi, dword[edi]
test edi, edi
jne findl
findnf push ebx
xor ebx, ebx
jmp next
findm inc edi
inc ebx
loop findc
pop ebx
pop edi
xor ebx, ebx
inc ebx
lea edi, [edi + 4]
mov al, byte[edi]
test al, immediate
jne findi
neg ebx
findi and eax, 31
add edi, eax
inc edi
push edi
jmp next
colon ':', colon
dd xt_lit, -1
dd xt_state
dd xt_store
dd xt_create
dd xt_do_semi_code
docolon xchg ebp, esp
push esi
xchg ebp, esp
lea esi, [eax + 4] ; eax value is set by next
jmp next
colon ';', semicolon, immediate
dd xt_lit, xt_exit
dd xt_comma
dd xt_lit, 0
dd xt_state
dd xt_store
dd xt_exit
colon 'create', create
dd xt_dp, xt_fetch
dd xt_last, xt_fetch
dd xt_comma
dd xt_last, xt_store
dd xt_lit, 32
dd xt_word
dd xt_count
dd xt_plus
dd xt_dp, xt_store
dd xt_lit, 0
dd xt_comma
dd xt_do_semi_code
dovar push ebx
lea ebx, [eax + 4] ; eax value is set by next
jmp next
primitive '(;code)', do_semi_code
mov edi, dword[val_last]
mov al, byte[edi + 4]
and eax, 31
add edi, eax
mov dword[edi + 5], esi
xchg ebp, esp
pop esi
xchg esp, ebp
jmp next
final:
colon 'interpret', interpret
interpt dd xt_number_t_i_b
dd xt_fetch
dd xt_to_in
dd xt_fetch
dd xt_equals
dd xt_zero_branch
dd intpar
dd xt_t_i_b
dd xt_fetch
dd xt_lit, 50
dd xt_accept
dd xt_number_t_i_b
dd xt_store
dd xt_lit, 0
dd xt_to_in
dd xt_store
intpar dd xt_lit, 32
dd xt_word
dd xt_find
dd xt_dupe
dd xt_zero_branch
dd intnf
dd xt_state
dd xt_fetch
dd xt_equals
dd xt_zero_branch
dd intexc
dd xt_comma
dd xt_branch
dd intdone
intexc dd xt_execute
dd xt_branch
dd intdone
intnf dd xt_dupe
dd xt_rote
dd xt_count
dd xt_to_number
dd xt_zero_branch
dd intskip
dd xt_state
dd xt_fetch
dd xt_zero_branch
dd intnc
dd xt_last
dd xt_fetch
dd xt_dupe
dd xt_fetch
dd xt_last
dd xt_store
dd xt_dp
dd xt_store
intnc dd xt_abort
intskip dd xt_drop
dd xt_drop
dd xt_state
dd xt_fetch
dd xt_zero_branch
dd intdone
dd xt_lit
dd xt_lit
dd xt_comma
dd xt_comma
intdone dd xt_branch
dd interpt
freemem:
filesize equ $ - $$