commit 44e5d7f95a09ec1c5d6b5e97b4f202da0270ac4e
parent c51098d8791887e0e226a68d1e6656b395a6860a
Author: Alexey Yerin <yyp@disroot.org>
Date: Wed, 17 Nov 2021 20:00:10 +0300
Initial support for +libc
This allows linking Hare programs to C code, as well as enabling use
of tools like valgrind that detect default C allocator.
Signed-off-by: Alexey Yerin <yyp@disroot.org>
Diffstat:
11 files changed, 94 insertions(+), 3 deletions(-)
diff --git a/linux/+libc.ha b/linux/+libc.ha
@@ -0,0 +1,5 @@
+use rt;
+
+@init fn ensure_rt_init() void = {
+ rt::start_linux();
+};
diff --git a/os/+linux/+libc.ha b/os/+linux/+libc.ha
@@ -0,0 +1,5 @@
+use rt;
+
+@init fn ensure_rt_init() void = {
+ rt::start_linux();
+};
diff --git a/rt/+linux/platformstart+libc.ha b/rt/+linux/platformstart+libc.ha
@@ -0,0 +1,18 @@
+export @init fn start_linux() void = {
+ // Here we use a cool strategy of re-constructing argv and argc without
+ // knowing their original values. Since environ is placed just after
+ // them, it's possible to traverse backwards calculating how many
+ // entries were processed and comparing that value to the one at
+ // current position.
+ let argv_ptr = c_environ: uintptr - size(*char): uintptr * 2;
+ let i = 0z;
+ for (*(argv_ptr: **char): uintptr: size != i; i += 1) {
+ argv_ptr -= size(*char): uintptr;
+ };
+
+ argc = i;
+ argv = (argv_ptr + size(*char): uintptr): **char;
+ envp = c_environ;
+};
+
+let @symbol("environ") c_environ: *[*]nullable *char;
diff --git a/rt/+linux/start+aarch64.s b/rt/+linux/start+aarch64-libc.s
diff --git a/rt/+linux/start+riscv64.s b/rt/+linux/start+riscv64-libc.s
diff --git a/rt/+linux/start+x86_64.s b/rt/+linux/start+x86_64-libc.s
diff --git a/rt/hare+libc.sc b/rt/hare+libc.sc
@@ -0,0 +1,35 @@
+SECTIONS {
+ . = 0x8000000;
+ .text : {
+ KEEP (*(.text))
+ *(.text.*)
+ }
+ . = 0x80000000;
+ .data : {
+ KEEP (*(.data))
+ *(.data.*)
+ }
+
+ .init_array : {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+
+ .fini_array : {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+
+ .test_array : {
+ PROVIDE_HIDDEN (__test_array_start = .);
+ KEEP (*(.test_array))
+ PROVIDE_HIDDEN (__test_array_end = .);
+ }
+
+ .bss : {
+ KEEP (*(.bss))
+ *(.bss.*)
+ }
+}
diff --git a/rt/malloc+libc.ha b/rt/malloc+libc.ha
@@ -0,0 +1,24 @@
+// Allocates n bytes of memory and returns a pointer to them, or null if there
+// is insufficient memory.
+export fn malloc(n: size) nullable *void = {
+ return c_malloc(n);
+};
+
+// Changes the allocation size of a pointer to n bytes. If n is smaller than
+// the prior allocation, it is truncated; otherwise the allocation is expanded
+// and the values of the new bytes are undefined. May return a different pointer
+// than the one given if there is insufficient space to expand the pointer
+// in-place. Returns null if there is insufficient memory to support the
+// request.
+export fn realloc(p: nullable *void, n: size) nullable *void = {
+ return c_realloc(p, n);
+};
+
+// Frees a pointer previously allocated with [[malloc]].
+export @symbol("rt.free") fn free_(p: nullable *void) void = {
+ c_free(p);
+};
+
+@symbol("malloc") fn c_malloc(_: size) nullable *void;
+@symbol("realloc") fn c_realloc(_: nullable *void, _: size) nullable *void;
+@symbol("free") fn c_free(_: nullable *void) void;
diff --git a/rt/start+test+libc.ha b/rt/start+test+libc.ha
@@ -0,0 +1,4 @@
+export @symbol("main") fn main() int = {
+ const nfail = tests_main();
+ return if (nfail > 0) 1 else 0;
+};
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -89,7 +89,7 @@ rt() {
gen_ssa -plinux rt
gen_ssa -pfreebsd rt
cat <<EOF
-\$($cache)/rt/start.o: \$(STDLIB)/rt/+\$(PLATFORM)/start+\$(ARCH).s
+\$($cache)/rt/start.o: \$(STDLIB)/rt/+\$(PLATFORM)/start+\$(ARCH)-libc.s
@printf 'AS \t\$@\n'
@mkdir -p \$($cache)/rt
@\$(AS) -o \$@ \$<
diff --git a/stdlib.mk b/stdlib.mk
@@ -68,7 +68,7 @@ $(HARECACHE)/rt/rt-freebsd.ssa: $(stdlib_rt_freebsd_srcs) $(stdlib_rt)
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nrt \
-t$(HARECACHE)/rt/rt.td $(stdlib_rt_freebsd_srcs)
-$(HARECACHE)/rt/start.o: $(STDLIB)/rt/+$(PLATFORM)/start+$(ARCH).s
+$(HARECACHE)/rt/start.o: $(STDLIB)/rt/+$(PLATFORM)/start+$(ARCH)-libc.s
@printf 'AS \t$@\n'
@mkdir -p $(HARECACHE)/rt
@$(AS) -o $@ $<
@@ -1787,7 +1787,7 @@ $(TESTCACHE)/rt/rt-freebsd.ssa: $(testlib_rt_freebsd_srcs) $(testlib_rt)
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nrt \
-t$(TESTCACHE)/rt/rt.td $(testlib_rt_freebsd_srcs)
-$(TESTCACHE)/rt/start.o: $(STDLIB)/rt/+$(PLATFORM)/start+$(ARCH).s
+$(TESTCACHE)/rt/start.o: $(STDLIB)/rt/+$(PLATFORM)/start+$(ARCH)-libc.s
@printf 'AS \t$@\n'
@mkdir -p $(TESTCACHE)/rt
@$(AS) -o $@ $<