Hello guys, I decided to write a brain**** compiler to help me understand how compilers work, I've done very little ring3 programming, so I am rather new to this. So anyway here is my bf compiler code...


        use32
;=============================================================================;
section .data
;=============================================================================;
        welcom  db  "Coty's crazed  Brain**** compiler (C) 2011",10
        wellen  equ $-welcom

numofargs      dd 0      ; How many arguments were passed (including this prog)
progname        dd 0      ; The progname this app was launched with
argument1      dd 0      ; File to compile input
argument2      dd 0      ; file to compile outpu
argument3      dd 0      ; unused
argument4      dd 0      ; unused

codeinsize      equ    32768
codeoutsize    equ    8192
;=============================================================================;
section .text
global _start
;=============================================================================;
_start:
        ;---------------------------------------------------------------------;
        ; First lets grab our arguments...                                    ;
        ;---------------------------------------------------------------------;
        pop    eax
        pop    ebx
        pop    ecx
        pop    edx
        pop    edi
        pop    esi
        mov    , eax
        mov    ,  ebx
        mov    , ecx
        mov    , edx
        mov    , edi
        mov    , esi
        ;---------------------------------------------------------------------;
        ; Print our so cool message...                                        ;
        ;---------------------------------------------------------------------;
        xor    esi, esi
        xor    edi, edi
        mov    eax, 4   
        mov    ebx, 1   
        mov    ecx, welcom 
        mov    edx, wellen
        int    0x80
        ;---------------------------------------------------------------------;
        ; Read our code from disk.                                            ;
        ;---------------------------------------------------------------------;
        mov    ebx,
        mov    eax,  5
        mov    ecx,  0
        int    0x80

        mov    eax,  3
        mov    ebx,  eax
        mov    ecx,  codeinbuf
        mov    edx,  codeinsize
        int    0x80
        ;---------------------------------------------------------------------;
        ; Compile the code...                                                ;
        ;---------------------------------------------------------------------;
        mov    esi, codeinbuf
        mov    edi, codeoutbuf
        xor    ecx, ecx
        xor    edx, edx
        compile_loop:
                lodsb
                cmp    al, "+"
                jne    next0
                push    esi
                push    ecx
                mov    esi, inc_eax
                mov    ecx, inc_eaxsize
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, inc_eaxsize
                        mov    al,
                        sub    al, inc_eaxsize
                        mov    , al
                .over:
                pop    ecx 
                add    ecx, inc_eaxsize             
                pop    esi
                jmp    next7
        next0:
                cmp    al, "-"
                jne    next1
                push    esi
                push    ecx
                mov    esi, dec_eax
                mov    ecx, dec_eaxsize
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, dec_eaxsize
                        mov    al,
                        sub    al, dec_eaxsize
                        mov    , al
                .over:
                pop    ecx 
                add    ecx, dec_eaxsize             
                pop    esi
                jmp    next7
        next1:
                cmp    al, ">"
                jne    next2
                push    esi
                push    ecx
                mov    esi, inc_ecx
                mov    ecx, inc_ecxsize
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, inc_ecxsize
                        mov    al,
                        sub    al, inc_ecxsize
                        mov    , al
                .over:
                pop    ecx     
                add    ecx, inc_ecxsize         
                pop    esi
                jmp    next7
        next2:
                cmp    al, "<"
                jne    next3
                push    esi
                push    ecx
                mov    esi, dec_ecx
                mov    ecx, dec_ecxsize
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, dec_ecxsize
                        mov    al,
                        sub    al, dec_ecxsize
                        mov    , al
                .over:
                pop    ecx 
                add    ecx, dec_ecxsize             
                pop    esi
                jmp    next7
        next3:
                cmp    al, "."
                jne    next4
                push    esi
                push    ecx
                mov    esi, period
                mov    ecx, period_size
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, period_size
                        mov    al,
                        sub    al, period_size
                        mov    , al
                .over:
                pop    ecx   
                add    ecx, period_size           
                pop    esi
                jmp    next7
        next4:
                cmp    al, ","
                jne    next5
                push    esi
                push    ecx
                mov    esi, comma
                mov    ecx, comma_size
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, comma_size
                        mov    al,
                        sub    al, comma_size
                        mov    , al
                .over:
                pop    ecx
                pop    esi
                add    ecx, comma_size
                jmp    next7
        next5:
                cmp    al, "["
                jne    next6
                mov    edx, 1
                jmp    next7
        next6:
                cmp    al, "]"
                jne    next7
                mov    ax,
                stosw
                xor    edx, edx
                add    ecx, 2
        next7:
                cmp    ecx, codeoutsize
                jne    compile_loop
        ;---------------------------------------------------------------------;
        ; Write our binary to a file!                                        ;
        ;---------------------------------------------------------------------;
        mov    ebx,       ; File descriptor
        mov    eax, 8
        mov    ecx, 00644Q            ; CHMOD permisions
        int    0x80
        mov    ebx, eax
        mov    eax, 4                ; write system call
        mov    ecx, codeoutbuf
        mov    edx, codeoutsize
        int    0x80 
mov eax,6               ; sys_close()
int 80h
        ;---------------------------------------------------------------------;
        ; Exit proc.                                                          ;
        ;---------------------------------------------------------------------;
        mov    eax, 1
        mov    ebx, 0
        int    0x80
;=============================================================================;
; Opcode list, you can change these to output ARM, PPC, 6502, ect.            ;
;=============================================================================;
inc_eax:
        inc    eax
inc_eaxsize equ $-inc_eax

dec_eax:
        dec    eax
dec_eaxsize equ $-dec_eax

inc_ecx:
        inc    ecx
inc_ecxsize equ $-inc_ecx

dec_ecx:
        dec    ecx
dec_ecxsize equ $-dec_ecx
        ;---------------------------------------------------------------------;
        ; Loop stuff...                                                      ;
        ;---------------------------------------------------------------------;
loop_sys:
        db 0xE2  ; Short jump!
loop_var:
        db 0xFE  ; jmp $
loop_length equ 1
        ;---------------------------------------------------------------------;
        ; Here is our library to handle "." and ","... think if it like the  ;
        ; iostream.h of brain**** or something...                            ;
        ;---------------------------------------------------------------------;
period:
        mov    [8191], al
        mov    ecx, 8191
        mov    edx, 1
        mov    eax, 4
        mov    ebx, 1
        int    0x80
period_size equ $-period
comma:
        mov    eax, 3
        xor    ebx, ebx
        int    0x80
        ;
        ;  EAX nao holds our keypress!
        ;
comma_size equ $-comma
;=============================================================================;
section .bss
;=============================================================================;
        codeinbuf  resb 32768        ; This is we the source code gets loaded.
        codeoutbuf resb 8192        ; This is were the finished binary goes.



I compile with:

~$ nasm -f elf i.asm
~$ ld -s -o i i.o

Here is some sample code to compile:
[><+-,.]

I compile the BF code acordingly:
./i test.bf test.bin

The compiler starts, displays my message, "Coty's crazed  Brain**** compiler (C) 2011", then I read a segmentation fault and my BF code is not compiled... Any hints to what might be causing this? I tried making my buffers smaller to see if that was the issue, and maybe I was attempting to write outside of my little box in memory, but I still got the error...

Any help will be appreciated, thanks in advance!

Cheers! - Coty Miller
Posted on 2011-10-17 09:04:05 by Coty
Hi Coty,

First thing that causes the segfault is attempting to write to your .text section, which is readonly. We can tell Nasm to make .text writeable, and it will... in the .o file. However, ld, in its infinite wisdom, "knows" that .text is readonly, and changes it back for us! :( Workaround is to use a different name, ".kode" or so.

Then, I think you're running off the end of your valid memory. Not clear to me how compile_loop is intended to exit.

At the end of the "open", you mov 3 into eax before moving eax into ebx for the "read" - a simple braincramp.

I've made a few simple changes - added a "getc" for debugging purposes after the "lodsb" in "compile_loop", etc. I'm not sure this actually "works" - it only writes a one-byte .bin file - I'm not very familiar with BF. It at least completes without a segfault.


        use32
;=============================================================================;
section .data
;=============================================================================;
        welcom  db  "Coty's crazed  Brain**** compiler (C) 2011",10
        wellen  equ $-welcom

numofargs      dd 0      ; How many arguments were passed (including this prog)
progname        dd 0      ; The progname this app was launched with
argument1      dd 0      ; File to compile input
argument2      dd 0      ; file to compile outpu
argument3      dd 0      ; unused
argument4      dd 0      ; unused


codeinsize      equ    32768
codeoutsize    equ    8192
;=============================================================================;
;section .text
section .kode write exec
global _start
;=============================================================================;
_start:
        ;---------------------------------------------------------------------;
        ; First lets grab our arguments...                                    ;
        ;---------------------------------------------------------------------;
        pop    eax
        pop    ebx
        pop    ecx
        pop    edx
        pop    edi
        pop    esi
        mov    , eax
        mov    ,  ebx
        mov    , ecx
        mov    , edx
        mov    , edi
        mov    , esi
        ;---------------------------------------------------------------------;
        ; Print our so cool message...                                        ;
        ;---------------------------------------------------------------------;
        xor    esi, esi
        xor    edi, edi
        mov    eax, 4   
        mov    ebx, 1   
        mov    ecx, welcom 
        mov    edx, wellen
        int    0x80
        ;---------------------------------------------------------------------;
        ; Read our code from disk.                                            ;
        ;---------------------------------------------------------------------;
        mov    ebx,
        mov    eax,  5
        mov    ecx,  0
        int    0x80

        mov    ebx,  eax
        mov    eax,  3
;        mov    ebx,  eax
        mov    ecx,  codeinbuf
        mov    edx,  codeinsize
        int    0x80
; save eax somewhere?
mov , eax

mov ebx, eax ; ebx unused here?
        ;---------------------------------------------------------------------;
        ; Compile the code...                                                ;
        ;---------------------------------------------------------------------;
        mov    esi, codeinbuf
        mov    edi, codeoutbuf
        xor    ecx, ecx
        xor    edx, edx
        compile_loop:
                lodsb
dec ebx
jz indone
call putc
                cmp    al, "+"
                jne    next0
                push    esi
                push    ecx
                mov    esi, inc_eax
                mov    ecx, inc_eaxsize
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, inc_eaxsize
                        mov    al,
                        sub    al, inc_eaxsize
                        mov    , al
                .over:
                pop    ecx 
                add    ecx, inc_eaxsize             
                pop    esi
                jmp    next7
        next0:
                cmp    al, "-"
                jne    next1
                push    esi
                push    ecx
                mov    esi, dec_eax
                mov    ecx, dec_eaxsize
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, dec_eaxsize
                        mov    al,
                        sub    al, dec_eaxsize
                        mov    , al
                .over:
                pop    ecx 
                add    ecx, dec_eaxsize             
                pop    esi
                jmp    next7
        next1:
                cmp    al, ">"
                jne    next2
                push    esi
                push    ecx
                mov    esi, inc_ecx
                mov    ecx, inc_ecxsize
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, inc_ecxsize
                        mov    al,
                        sub    al, inc_ecxsize
                        mov    , al
                .over:
                pop    ecx     
                add    ecx, inc_ecxsize         
                pop    esi
                jmp    next7
        next2:
                cmp    al, "<"
                jne    next3
                push    esi
                push    ecx
                mov    esi, dec_ecx
                mov    ecx, dec_ecxsize
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, dec_ecxsize
                        mov    al,
                        sub    al, dec_ecxsize
                        mov    , al
                .over:
                pop    ecx 
                add    ecx, dec_ecxsize             
                pop    esi
                jmp    next7
        next3:
                cmp    al, "."
                jne    next4
                push    esi
                push    ecx
                mov    esi, period
                mov    ecx, period_size
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, period_size
                        mov    al,
                        sub    al, period_size
                        mov    , al
                .over:
                pop    ecx   
                add    ecx, period_size           
                pop    esi
                jmp    next7
        next4:
                cmp    al, ","
                jne    next5
                push    esi
                push    ecx
                mov    esi, comma
                mov    ecx, comma_size
                rep    movsb
                        cmp    edx, 1
                        jne    .over
                        ;sub    byte, comma_size
                        mov    al,
                        sub    al, comma_size
                        mov    , al
                .over:
                pop    ecx
                pop    esi
                add    ecx, comma_size
                jmp    next7
        next5:
                cmp    al, "["
                jne    next6
                mov    edx, 1
                jmp    next7
        next6:
                cmp    al, "]"
                jne    next7
                mov    ax,
                stosw
                xor    edx, edx
                add    ecx, 2
        next7:
                cmp    ecx, codeoutsize
                jne    compile_loop

indone:

        ;---------------------------------------------------------------------;
        ; Write our binary to a file!                                        ;
        ;---------------------------------------------------------------------;
        mov    ebx,       ; File descriptor
        mov    eax, 8
        mov    ecx, 00644Q            ; CHMOD permisions
        int    0x80
        mov    ebx, eax
        mov    eax, 4                ; write system call
        mov    ecx, codeoutbuf
        mov    edx, codeoutsize
        int    0x80 
mov eax,6               ; sys_close()
int 80h
        ;---------------------------------------------------------------------;
        ; Exit proc.                                                          ;
        ;---------------------------------------------------------------------;
        mov    eax, 1
        mov    ebx, 0
        int    0x80
;=============================================================================;
; Opcode list, you can change these to output ARM, PPC, 6502, ect.            ;
;=============================================================================;
inc_eax:
        inc    eax
inc_eaxsize equ $-inc_eax

dec_eax:
        dec    eax
dec_eaxsize equ $-dec_eax

inc_ecx:
        inc    ecx
inc_ecxsize equ $-inc_ecx

dec_ecx:
        dec    ecx
dec_ecxsize equ $-dec_ecx
        ;---------------------------------------------------------------------;
        ; Loop stuff...                                                      ;
        ;---------------------------------------------------------------------;
loop_sys:
        db 0xE2  ; Short jump!
loop_var:
        db 0xFE  ; jmp $
loop_length equ 1
        ;---------------------------------------------------------------------;
        ; Here is our library to handle "." and ","... think if it like the  ;
        ; iostream.h of brainf*** or something...                            ;
        ;---------------------------------------------------------------------;
period:
        mov    [8191], al
        mov    ecx, 8191
        mov    edx, 1
        mov    eax, 4
        mov    ebx, 1
        int    0x80
period_size equ $-period
comma:
        mov    eax, 3
        xor    ebx, ebx
        int    0x80
        ;
        ;  EAX nao holds our keypress!
        ;
comma_size equ $-comma

putc:
push edx
push ecx
push ebx
push eax ; "buffer"

mov ecx, esp
mov edx, 1
mov ebx, 1
mov eax, 4
int 80h

pop eax
pop ebx
pop ecx
pop edx
ret

;=============================================================================;
section .bss
;=============================================================================;
        codeinbuf  resb 32768        ; This is we the source code gets loaded.
        codeoutbuf resb 8192        ; This is were the finished binary goes.
insize resd 1


This isn't going to work in Linux:

        mov    [8191], al

but perhaps it isn't intended to?

Anyway, see if those minor changes helped any...

Edit: removed a "bad word" from a comment in the code.

Best,
Frank

Posted on 2011-10-18 16:14:19 by fbkotler
My mistake. It IS writing the output file with "correct"(?) code in it.

On looking at this further, we don't need to resort to the writeable text section trick. What you're writing to is "code", but it doesn't get executed here, merely copied to a buffer, and written to a file to be executed at some future date. That stuff could be in your ".data" section.

The resulting binary is, in fact, 8192 bytes long - the full "codeoutsize". You probably want to calculate the actual size of the code copied to the buffer and write just that size to the .bin file.

Do you propose to eventually put an ELF header on the resulting executable? Is it up to the author of the BF program to provide a clean exit, or should that be written to the executable by default? I'm not familiar with the workings and conventions of BF.

We have a "problem" with the name of this language. This is a "family" Forum. The real problem is that here in the "Land of the Free and the Home of the Brave" (and probably other places) schools and libraries and stuff are required to be provided with "filters" to protect the kiddies from... whatever they're at risk from... the abbreviation for "firetruck"... We don't want to trigger any filters and get blocked! I just went back and edited a comment in the code (iostream library for...). You might want to do the same, just to keep it "squeaky-clean" around here...

Best,
Frank

Posted on 2011-10-19 04:44:04 by fbkotler
First off I am sorry! I thought I had removed all the "****" from my code, I guess I missed a spot, so I fixed it!

Second, I plan to make it run on Linux when I am done as-well as exiting properly. Right now some of the code generated is just a place holder so I can  run ndisasm and check the compiled output  :)

And I guess I didn't take into consideration that I was writing to a read only section... Thank you very much! Thanks for pointing everything out, the error is gone now and generated code looks correct :D

Also on a side I really like that putc fuction you put in the code above, I have never thought of pushing letter to print onto the stack then pointing ESP as the string... Very nice, that solves the placeholder "mov    [8191], al"  :D

How "compile_loop" loop exits is it compares ECX with maximum code buffer size, if it's equile it exits, the problem with this is it was implemented before ",", ".", "[" and "]" was added so it could easily over flow the buffer... Since those are multibyte instructions...

Thanks for all your help fbkotler!

Posted on 2011-10-19 07:44:53 by Coty
is these asembly code in intel-formated or at&t-formated?

mov    , eax  //in at&t formated

but 

  mov    eax,  5        //in intel formated
Posted on 2012-06-20 00:26:35 by puttyios
Those appear to be Intel syntax... except the comment character "//" is wrong.

Nasm syntax:

; nasm -f elf32 hw.asm
; ld -o hw hw.o
global _start

section .data
msg db 'Hello, world',0Ah
msg_len equ $-msg

section .text
_start:

mov eax,4
mov ebx,1
mov ecx, msg
mov edx,msg_len
int 80h

mov eax,1
int 80h


AT&T (Gas) syntax:

.global _start

.text
_start:
    movl $4, %eax
    movl $1, %ebx
    movl $msg, %ecx
    movl $msg_len, %edx
    int  $0x80
   
    movl %eax, %ebx
    movl $1, %eax
    int  $0x80

.data
    msg: .ascii "Hello World!\n"
    msg_len = . - msg
   

And just to really confuse the issue, (G)as with the ".intel_syntax" directive:

.global _start
.intel_syntax noprefix

.section data
    msg .string "hello, from gas"
    msg_len = . - msg

.section text
_start:

    mov eax, 4
    mov ebx, 1
    mov ecx, msg
    mov edx, msg_len
    int 0x80

    xor eax,eax
    inc eax
    int 0x80


Best,
Frank

Posted on 2012-06-20 10:40:07 by fbkotler