x86 32 位汇编中的 BrainF*ck 解释器

BrainF*ck interpreter in x86 32-bit Assembly

我开始用 32 位 x86 汇编为我的 OS 编写一个 BrainF*ck 解释器。我已经用 C 编写了一个可以正常工作的程序,并尝试在汇编中实现它,但是用汇编编写的那个不打印任何输出。

我对汇编还是个新手,所以我想我只是犯了一些初学者的错误。我唯一能想到的就是我搞砸了某处的寻址。 如果有人能指出我做错了什么,我会很高兴。

我用相同的输入测试了 C 和汇编程序:

-[--->+<]>---.+[----->+++<]>.[--->+<]>+.[--->++<]>-.++++.

它应该打印 RexOS

我创建了我的 C 代码的 pastebin 如果这有助于理解我想要完成的事情: pastebin

我的汇编代码如下:

.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

我终于解决了这个问题。我需要做的就是将指针递增移动到循环的末尾,并在序言 (ebx) 中保存额外的寄存器,然后在尾声中恢复寄存器。还需要保存和恢复打印和扫描部分的寄存器。

我的最终工作代码如下所示:

.intel_syntax noprefix

.section .data
TAPE:
    .zero 30000

.section .text
.global interpret
interpret:
    push ebp                // prologue
    mov ebp, esp
    push ebx

    xor eax, eax            // loop counter
    mov ebx, offset TAPE    // a pointer to the tape
    mov edx, [ebp+8]        // getting the input string
    
clrt:                       // clear TAPE
    cmp eax, 30000
    je loop

    mov byte ptr [ebx+eax], 0

    inc eax

    jmp clrt

loop:
    mov cl, byte ptr [edx]  // getting the current 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

ptlp:                       // postloop
    inc edx                 // increment the input pointer
    jmp loop                // continue the loop

pinc:
    inc ebx
    jmp ptlp

pdec:
    dec ebx
    jmp ptlp

vinc:
    inc byte ptr [ebx]
    jmp ptlp

vdec:
    dec byte ptr [ebx]
    jmp ptlp

prnt:
    push edx

    push dword ptr [ebx]
    call putchar
    add esp, 4

    pop edx

    jmp ptlp

read:
    push edx

    call getchar
    mov byte ptr [ebx], al

    pop edx

    jmp ptlp

bend:
    cmp byte ptr [ebx], 0
    je ptlp

    mov ch, 1

ilst:
    cmp ch, 0
    jle ptlp

    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:
    pop ebx                 // epilogue
    mov esp, ebp
    pop ebp
    ret