satrt readme
This commit is contained in:
parent
826d1afd58
commit
06def8fb86
8 changed files with 65 additions and 8 deletions
14
05/Makefile
14
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)
|
||||
|
|
42
05/README.md
Normal file
42
05/README.md
Normal file
|
@ -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.
|
||||
|
1
05/tcc-0.9.27/.gitignore
vendored
1
05/tcc-0.9.27/.gitignore
vendored
|
@ -19,7 +19,6 @@ tcc
|
|||
*-tcc
|
||||
libtcc*.def
|
||||
|
||||
config*.h
|
||||
config*.mak
|
||||
config.texi
|
||||
conftest*
|
||||
|
|
8
05/tcc-0.9.27/config.h
Normal file
8
05/tcc-0.9.27/config.h
Normal file
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue