diff options
-rw-r--r-- | 05/Makefile | 14 | ||||
-rw-r--r-- | 05/README.md | 42 | ||||
-rw-r--r-- | 05/tcc-0.9.27/.gitignore | 1 | ||||
-rw-r--r-- | 05/tcc-0.9.27/config.h | 8 | ||||
-rw-r--r-- | 05/tcc-0.9.27/x86_64-gen.c | 2 | ||||
-rw-r--r-- | 05/test.c | 3 | ||||
-rw-r--r-- | 05/test.s | 1 | ||||
-rw-r--r-- | README.md | 2 |
8 files changed, 65 insertions, 8 deletions
diff --git a/05/Makefile b/05/Makefile index 0a2fcb5..628d286 100644 --- a/05/Makefile +++ b/05/Makefile @@ -1,4 +1,6 @@ -all: out04 a.out +TCCDIR=tcc-0.9.27 +TCC=$(TCCDIR)/tcc +all: out04 a.out test.out README.html in04: *.b ../04a/out04 ../04a/out04 main.b in04 out04: in04 ../04/out03 @@ -9,5 +11,13 @@ out04: in04 ../04/out03 ./out04 $< $@ a.out: main.c *.h out04 ./out04 +test.out: $(TCC) test.s.o test.c.o + $(TCC) -static -nostdlib test.s.o test.c.o -o test.out +test.s.o: $(TCC) test.s + $(TCC) -static -nostdlib -c test.s -o test.s.o +test.c.o: $(TCC) test.c + $(TCC) -static -nostdlib -c test.c -o test.c.o +$(TCC): $(TCCDIR)/*.c $(TCCDIR)/*.h out04 + cd $(TCCDIR) && ../out04 tcc.c tcc clean: - rm -f out* README.html *.out + rm -f out* README.html *.out *.o $(TCC) diff --git a/05/README.md b/05/README.md new file mode 100644 index 0000000..276aac6 --- /dev/null +++ b/05/README.md @@ -0,0 +1,42 @@ +# [bootstrap](../README.md) stage 05 + +This stage consists of a C compiler capable of compiling TCC (after some modifications +to TCC's source code). +Run + +``` +make +``` + +to build our C compiler and TCC. This will take some time (approx. 25 seconds on my computer). +A test program, `test.out` will be compiled using `tcc`. If you run +it, you should get the output + +``` +Hello, world! +``` + +So now we just compile TCC with itself, and we're done, right? +Well, not quite... + +## the nightmare begins + +The issue here is that to compile TCC/GCC with TCC, we need libc, the C standard library functions. +Our C compiler just includes these functions in the standard header files, but normally +the code for them is located in a separate library file (called something like +`/usr/lib/x86_64-linux-gnu/libc-2.31.so`). + +This library file is itself compiled from C source files (typically glibc). +So, can't we just compile glibc with TCC, then compile TCC with itself? +Well, no. Compiling glibc with TCC is basically impossible; you need to compile +it with GCC. + +Other libc implementations aren't too happy about TCC either -- I tried to compile +[musl](http://www.musl-libc.org/) for several hours, and had to give up in the end. + +It seems that the one option left is to make our own libc, and try to use it along with +TCC to compile GCC. +From there, we should be able to compile glibc with GCC. Then, we can compile GCC with GCC and glibc. +If we do all this, we should get the same libc.so and gcc files as if we had started +with any GCC and glibc builds. It's all very confusing. + diff --git a/05/tcc-0.9.27/.gitignore b/05/tcc-0.9.27/.gitignore index c989b6b..a50ca5e 100644 --- a/05/tcc-0.9.27/.gitignore +++ b/05/tcc-0.9.27/.gitignore @@ -19,7 +19,6 @@ tcc *-tcc libtcc*.def -config*.h config*.mak config.texi conftest* diff --git a/05/tcc-0.9.27/config.h b/05/tcc-0.9.27/config.h new file mode 100644 index 0000000..d363b97 --- /dev/null +++ b/05/tcc-0.9.27/config.h @@ -0,0 +1,8 @@ +#define TCC_VERSION "0.9.27" +#define CONFIG_TCC_STATIC 1 +#define CONFIG_TCC_ELFINTERP "/XXX" +#define CONFIG_TCC_CRT_PREFIX "/XXX" +#define CONFIG_SYSROOT "/XXX" +#define inline +#define TCC_TARGET_X86_64 1 +#define ONE_SOURCE 1 diff --git a/05/tcc-0.9.27/x86_64-gen.c b/05/tcc-0.9.27/x86_64-gen.c index 9060ae9..ad56ed6 100644 --- a/05/tcc-0.9.27/x86_64-gen.c +++ b/05/tcc-0.9.27/x86_64-gen.c @@ -599,7 +599,7 @@ static void gcall_or_jmp(int is_jmp) #ifdef TCC_TARGET_PE greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32, (int)(vtop->c.i-4)); #else - greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32, (int)(vtop->c.i-4)); + greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32, (int)(vtop->c.i-4)); // tcc's PLT code doesn't seem to work with static builds #endif } else { /* put an empty PC32 relocation */ @@ -1,6 +1,5 @@ -// calling assembly functions from C is not working for some reason. extern unsigned long __syscall(int, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); -int main(unsigned long (*_syscall)(int, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)) { +int main(void) { __syscall(1, 1, (unsigned long)"Hello, world!\n", 14, 0, 0, 0); return 42; } @@ -15,7 +15,6 @@ __syscall: ret _start: - lea __syscall, %rdi call main mov $60, %eax syscall @@ -60,7 +60,7 @@ If you're unfamiliar with x86-64 assembly, you should check out the instruction Bootstrapping a compiler is not an easy task, so we're trying to make it as easy as possible. We don't even necessarily need a standard-compliant C compiler, we only need enough to compile someone else's C compiler, specifically we'll be -using [TCC](https://bellard.org/tcc/) since it's written in standard C89. +using [TCC](https://bellard.org/tcc/) since it's written (mostly) in standard C89. - efficiency is not a concern |