I started to write a BrainF*ck interpreter for my OS in 32-bit x86 assembly. I have already written one in C that just works and tried to implement it in assembly but the one written in assembly doesn't print any output.
I'm still new to assembly so I guess I just made some beginner mistakes. Only thing I can think of is that I messed up the addressing somewhere. I'd be really happy if someone could point out what I'm doing wrong.
I tested the C and assembly programs with the same input:
-[--->+<]>---.+[----->+++<]>.[--->+<]>+.[--->++<]>-.++++.
It should print RexOS
I created a pastebin of my C code if that helps understand what I'm trying to accomplish: pastebin
My assembly code is the following:
.intel_syntax noprefix
.section .data
TAPE:
.zero 30000
.section .text
.global interpret
interpret:
push ebp // prologue
mov ebp, esp
mov edx, [ebp+8] // getting the input string
mov edi, offset TAPE // a pointer to the tape
xor ecx, ecx // stores current char
// inner loop counter
loop:
mov cl, byte ptr [edx] // getting the current char
inc edx // increase the index to the next char
cmp cl, 0 // if we reached the end of the string
je exit // return the length
cmp cl, '>'
je pinc // increment the pointer
cmp cl, '<'
je pdec // decrement the pointer
cmp cl, '+'
je vinc // increment value at index
cmp cl, '-'
je vdec // decrement value at index
cmp cl, '.'
je prnt // print the value at index
cmp cl, ','
je read // read character from stdin
cmp cl, ']'
je bend // end of bracket
jmp loop
pinc:
inc edi
jmp loop
pdec:
dec edi
jmp loop
vinc:
inc byte ptr [edi]
jmp loop
vdec:
dec byte ptr [edi]
jmp loop
prnt:
push edx
push dword ptr [edi]
call putchar
add esp, 4
pop edx
jmp loop
read:
call getchar
mov byte ptr [edi], al
jmp loop
bend:
cmp byte ptr [edi], 0
je loop
mov ch, 1
ilst:
cmp ch, 0
jle loop
dec edx // jump to the previous index
mov cl, byte ptr [edx] // getting the current char
cmp cl, '['
je dclp // decrease internal loop counter
cmp cl, ']'
je inlp // increase internal loop counter
jmp ilst
inlp:
inc ch
jmp ilst
dclp:
dec ch
jmp ilst
exit:
mov esp, ebp // epilogue
pop ebp
ret
movborincb; GAS might accept them, but it's better to be consistent. (e.g.inc byte ptr [eax]). And If you want to zero both CL and CH, usexor ecx,ecxto zero them both at once with one equally-compact instruction.push word ptr [eax]is mismatched withpop eax, so you're messing up your stack every putchar by subtracting 2 from ESP then adding 4 with pop. Push a whole dword; putchar will still only look at the low byte. (or movzx load into another reg and push that.)