From 05c3e4cab6bebdbe5b6017673a428e1b5b691a71 Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Mon, 15 Jun 2020 12:41:53 +0300 Subject: [PATCH 1/3] Cleaner output for 'make test' --- Makefile | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 573d8c8..fc7fd3f 100644 --- a/Makefile +++ b/Makefile @@ -4,21 +4,26 @@ build: test: build @echo "hello-world test" - ./bfcc -run examples/hello-world.bf > x - diff examples/hello-world.out x && rm x || echo "Failed Hello-World" + @./bfcc -run examples/hello-world.bf > x + @diff examples/hello-world.out x && rm x || echo "Failed Hello-World" + @echo "hello-world test OK" @echo "fibonacci test" - ./bfcc -run examples/fibonacci.bf > x - diff examples/fibonacci.out x && rm x || echo "Failed Fibonacci" + @./bfcc -run examples/fibonacci.bf > x + @diff examples/fibonacci.out x && rm x || echo "Failed!" + @echo "fibonacci test: OK" @echo "bizzfuzz test" - ./bfcc -run examples/bizzfuzz.bf > x - diff examples/bizzfuzz.out x && rm x || echo "Failed BizzFuzz" + @./bfcc -run examples/bizzfuzz.bf > x + @diff examples/bizzfuzz.out x && rm x || echo "Failed!" + @echo "bizzfuzz test: OK" @echo "quine test" - ./bfcc -run examples/quine.bf > x - diff examples/quine.out x && rm x || echo "Failed Quine" + @./bfcc -run examples/quine.bf > x + @diff examples/quine.out x && rm x || echo "Failed!" + @echo "quine test: OK" @echo "mandelbrot test" - ./bfcc -run examples/mandelbrot.bf > x - diff examples/mandelbrot.out x && rm x || echo "Failed Mandelbrot" + @./bfcc -run examples/mandelbrot.bf > x + @diff examples/mandelbrot.out x && rm x || echo "Failed!" + @echo "mandelbrot test: OK" From e9177236950a520d2044abb510ad197e49fd7374 Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Mon, 15 Jun 2020 13:07:50 +0300 Subject: [PATCH 2/3] Compile assembly via gcc rather than nasm --- generators/generator_asm.go | 74 +++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/generators/generator_asm.go b/generators/generator_asm.go index 9342e40..29ba03e 100644 --- a/generators/generator_asm.go +++ b/generators/generator_asm.go @@ -27,11 +27,13 @@ type GeneratorASM struct { func (g *GeneratorASM) generateSource() error { var buff bytes.Buffer var programStart = ` -global _start -section .text +.intel_syntax noprefix -_start: - mov r8, stack +.global main + + +main: + lea %r8, stack ` buff.WriteString(programStart) @@ -80,30 +82,30 @@ _start: switch tok.Type { case lexer.GREATER: - buff.WriteString(fmt.Sprintf(" add r8, %d\n", tok.Repeat)) + buff.WriteString(fmt.Sprintf(" add %%r8, %d\n", tok.Repeat)) case lexer.LESS: - buff.WriteString(fmt.Sprintf(" sub r8, %d\n", tok.Repeat)) + buff.WriteString(fmt.Sprintf(" sub %%r8, %d\n", tok.Repeat)) case lexer.PLUS: - buff.WriteString(fmt.Sprintf(" add byte [r8], %d\n", tok.Repeat)) + buff.WriteString(fmt.Sprintf(" add byte ptr [%%r8], %d\n", tok.Repeat)) case lexer.MINUS: - buff.WriteString(fmt.Sprintf(" sub byte [r8], %d\n", tok.Repeat)) + buff.WriteString(fmt.Sprintf(" sub byte ptr [%%r8], %d\n", tok.Repeat)) case lexer.OUTPUT: - buff.WriteString(" mov rax, 1\n") // SYS_WRITE - buff.WriteString(" mov rdi, 1\n") // STDOUT - buff.WriteString(" mov rsi, r8\n") // data-comes-here - buff.WriteString(" mov rdx, 1\n") // one byte - buff.WriteString(" syscall\n") // Syscall + buff.WriteString(" mov %rax, 1\n") // SYS_WRITE + buff.WriteString(" mov %rdi, 1\n") // STDOUT + buff.WriteString(" mov %rsi, %r8\n") // data-comes-here + buff.WriteString(" mov %rdx, 1\n") // one byte + buff.WriteString(" syscall\n") // Syscall case lexer.INPUT: - buff.WriteString(" mov rax, 0\n") // SYS_READ - buff.WriteString(" mov rdi, 0\n") // STDIN - buff.WriteString(" mov rsi, r8\n") // Dest - buff.WriteString(" mov rdx, 1\n") // one byte - buff.WriteString(" syscall\n") // syscall + buff.WriteString(" mov %rax, 0\n") // SYS_READ + buff.WriteString(" mov %rdi, 0\n") // STDIN + buff.WriteString(" mov %rsi, %r8\n") // Dest + buff.WriteString(" mov %rdx, 1\n") // one byte + buff.WriteString(" syscall\n") // syscall case lexer.LOOPOPEN: @@ -117,7 +119,7 @@ _start: // loop so the label here is AFTER our condition // i++ - buff.WriteString(" cmp byte [r8], 0\n") + buff.WriteString(" cmp byte ptr [%r8], 0\n") buff.WriteString(fmt.Sprintf(" je close_loop_%d\n", i)) buff.WriteString(fmt.Sprintf("label_loop_%d:\n", i)) opens = append(opens, i) @@ -168,7 +170,7 @@ _start: // test at the start of the loop, because // running it twice would be pointless. // - buff.WriteString(" cmp byte [r8], 0\n") + buff.WriteString(" cmp byte ptr [r8], 0\n") buff.WriteString(fmt.Sprintf(" jne label_loop_%d\n", last)) buff.WriteString(fmt.Sprintf("close_loop_%d:\n", last)) @@ -185,13 +187,15 @@ _start: } // terminate - buff.WriteString(" mov rax, 60\n") - buff.WriteString(" mov rdi, 0\n") + buff.WriteString(" mov %rax, 60\n") + buff.WriteString(" mov %rdi, 0\n") buff.WriteString(" syscall\n") - // program-area - buff.WriteString("section .bss\n") - buff.WriteString("stack: resb 300000\n") + buff.WriteString(".bss\n") + buff.WriteString("stack:\n") + buff.WriteString(".rept 30000\n") + buff.WriteString(" .byte 0x0\n") + buff.WriteString(".endr\n") // Output to a file err := ioutil.WriteFile(g.output+".s", buff.Bytes(), 0644) @@ -200,22 +204,12 @@ _start: func (g *GeneratorASM) compileSource() error { - // nasm to compile to object-code - nasm := exec.Command("nasm", "-f", "elf64", "-o", g.output+".o", g.output+".s") - nasm.Stdout = os.Stdout - nasm.Stderr = os.Stderr - - err := nasm.Run() - if err != nil { - return err - } - - // ld to link to an executable - ld := exec.Command("ld", "-m", "elf_x86_64", "-o", g.output, g.output+".o") - ld.Stdout = os.Stdout - ld.Stderr = os.Stderr + // Use gcc to compile our object-code + gcc := exec.Command("gcc", "-o", g.output, "-static", g.output+".s") + gcc.Stdout = os.Stdout + gcc.Stderr = os.Stderr - err = ld.Run() + err := gcc.Run() if err != nil { return err } From c6f57fb0bf603ab32fe0fe6fc15196ef034f187a Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Mon, 15 Jun 2020 13:08:36 +0300 Subject: [PATCH 3/3] Document the gcc-usage; no more nasm --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d38608a..d773e9d 100644 --- a/README.md +++ b/README.md @@ -45,11 +45,11 @@ Finally if you prefer you can specify an output name for the compiled result: $ bfcc [-run] ./examples/bizzfuzz.bf ./bf $ ./bf -There are two backends included, one generates an assembly language source-file, and compiles with with `nasm`, and the other generates C-code, which is compiled via `gcc`. +There are two backends included, one generates an assembly language source-file, and compiles with `gcc`, and the other generates C-code which is also compiled via `gcc`. -By default the assembly-language backend is selected, because this is the thing that I was more interested in writing, due to that you **must** have `nasm` installed to compile the generated assembly language file. +By default the assembly-language backend is selected, because this is the thing that I was more interested in writing. -Use the `-backend` flag to specify the backend which you prefer to use: +You may use the `-backend` flag to specify the backend which you prefer to use: $ bfcc -backend=c ./examples/mandelbrot.bf ./mb-c $ bfcc -backend=asm ./examples/mandelbrot.bf ./mb-asm @@ -57,8 +57,8 @@ Use the `-backend` flag to specify the backend which you prefer to use: You'll see slightly difference sizes in the two executable: $ ls -lash mb-c mb-asm - 76K -rwxr-xr-x 1 skx skx 73K Jun 15 10:11 mb-asm - 36K -rwxr-xr-x 1 skx skx 34K Jun 15 10:11 mb-c + 76K -rwxr-xr-x 1 skx skx 860K Jun 15 10:11 mb-asm + 36K -rwxr-xr-x 1 skx skx 34K Jun 15 10:11 mb-c But both should work identically; if they do not that's a bug in the generated C/assembly source files I've generated! @@ -80,7 +80,7 @@ In the end it took me about four hours to get something I was happy with, and la * Finally I cleaned up and improved the code. * Implementing a separate lexer. * Allowing the use of pluggable backends, so we could generate both C and Assembly Language output (but only one at a time). - + * Started using `gcc` to compile our assembly, to drop the dependency upon `nasm`. @@ -98,6 +98,8 @@ In the end it took me about four hours to get something I was happy with, and la * Adding a lexer in [#4](https://github.com/skx/bfcc/pull/4) * Allowing the generation of either C or assembly in [#6](https://github.com/skx/bfcc/pull/6) * Allow generating a breakpoint instruction when using the assembly-backend in [#7](https://github.com/skx/bfcc/pull/7). + * Switched to generating assembly to be compiled by `gcc` rather than `nasm` [#8](https://github.com/skx/bfcc/pull/8). + ### Debugging the generated program @@ -159,9 +161,7 @@ You can run `make test` to run all the scripts, and compare their generated outp Mostly none. -It might be cute to convert the assembly, such that `gcc` could compile it. That would drop the `nasm` dependency, but it's not a big deal. Patches welcome if you want to have a stab at it. - -Otherwise more backends might be nice, but I guess the two existing ones are the most obvious. Due to the way the code is structured adding a new one would be trivial though. +More backends might be nice, but I guess the two existing ones are the most obvious. Due to the way the code is structured adding a new one would be trivial.