hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Alinux/+libc.ha | 5+++++
Aos/+linux/+libc.ha | 5+++++
Art/+linux/platformstart+libc.ha | 18++++++++++++++++++
Rrt/+linux/start+aarch64.s -> rt/+linux/start+aarch64-libc.s | 0
Rrt/+linux/start+riscv64.s -> rt/+linux/start+riscv64-libc.s | 0
Rrt/+linux/start+x86_64.s -> rt/+linux/start+x86_64-libc.s | 0
Art/hare+libc.sc | 35+++++++++++++++++++++++++++++++++++
Art/malloc+libc.ha | 24++++++++++++++++++++++++
Art/start+test+libc.ha | 4++++
Mscripts/gen-stdlib | 2+-
Mstdlib.mk | 4++--
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 $@ $<