zig
zig copied to clipboard
glibc: add changes to make riscv64-linux-gnu works
Fixes #3340, builds with zig build-exe bootstrap.c -lc -target riscv64-linux-gnu -mcpu=generic_rv64. I can't test this until I can get RISC-V hardware but this does fix compiling.
I applied this PR's patch to the prebuilt zig-linux-x86_64-0.12.0-dev.2341+92211135f and was able to compile a hello world with zig cc -target riscv64-linux-gnu.2.34 -mcpu=generic_rv64 hello-world.c and run it under QEMU
I've fixed that missing header issue and I compiled glibc just to check if that header had anything worth adding and all I got was this:
/* This file is automatically generated.
It defines a symbol `__stub_FUNCTION' for each function
in the C library which is a stub, meaning it will fail
every time called, usually setting errno to ENOSYS. */
#ifdef _LIBC
#error Applications may not define the macro _LIBC
#endif
note that this patch should additionally be sent upstream so its not lost in zig when we next upgrade glibc
Woops, made a mistake
@nektro Yeah, the fini/ini stuff is actually upstream already. I just simplified it a bit since idk how we do things with glibc. The stub file though can be copied from a built version of glibc.
Might also fix https://github.com/ziglang/zig-bootstrap/issues/115
@RossComputerGuy Regarding the stubs-lp64d.h file, I see that the libc6-dev package from Debian sid includes:
/* This file is automatically generated.
It defines a symbol `__stub_FUNCTION' for each function
in the C library which is a stub, meaning it will fail
every time called, usually setting errno to ENOSYS. */
#ifdef _LIBC
# error Applications may not define the macro _LIBC
#endif
#define __stub___compat_bdflush
#define __stub___compat_create_module
#define __stub___compat_get_kernel_syms
#define __stub___compat_query_module
#define __stub___compat_uselib
#define __stub_chflags
#define __stub_fchflags
#define __stub_fedisableexcept
#define __stub_feenableexcept
#define __stub_fegetexcept
#define __stub_gtty
#define __stub_revoke
#define __stub_setlogin
#define __stub_sigreturn
#define __stub_stty
While an empty file might fix compilation, I'm not sure if it'll produce correct behavior.
@bjia56 Alright, I'll copy that in.
I've got a draft PR In https://github.com/ziglang/zig/pull/18815 that builds on this PR. It enables Zig code to target riscv64-linux , with or without glibc (previously this would fail with missing "ucontext_t" errors).
I don't have any experience with riscv*, so I'm not able to test anything, so it may be wrong in obvious or subtle ways (I copied some details from https://go.dev/src/runtime/defs_linux_riscv64.go), but it does compile successfully. Just putting the PR out there in case someone with riscv access/experience/motivation needs pointers on how to get Zig's built-in library and/or the glibc linking for Zig code to work.
There are also glibc linking tests in test/link/glibc_compat that could be expanded to cover cross-compiling to riscv targets pretty easily I think.
I've just been using QEMU userspace emulation (qemu-riscv64) @rootbeer. Interesting PR though, I plan on getting some RISC-V hardware when I have the money so hopefully I can help more with future RISC-V developments. I was going to run the tests in std this evening with -fqemu set.
With the most recent patches from this PR applied to zig-linux-x86_64-0.12.0-dev.2341+92211135f, I'm getting the following:
$ ./zig-linux-x86_64-0.12.0-dev.2341+92211135f/zig cc -target riscv64-linux-gnu.2.34 hello-world.c
$ file a.out
a.out: ELF 64-bit LSB executable, UCB RISC-V, RVC, double-float ABI, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-riscv64-lp64.so.1, for GNU/Linux 2.0.0, with debug_info, not stripped
Note that the interpreter is /lib/ld-linux-riscv64-lp64.so.1, even though stubs-lp64d.h was pulled in as part of compilation. The lp64 interpreter does not exist in either Debian or Ubuntu, both of which supply /lib/ld-linux-riscv64-lp64d.so.1.
Using patchelf to switch the interpreter to ld-linux-riscv64-lp64d.so.1 allows the program to run inside QEMU
Yeah, that's what I have to do on NixOS. I think Zig's interpreter selection or target guessing not quite there yet. If it at least compiles and can execute, I'd call that a win. I can probably look into fixing that once I have hardware.
Btw - looks like we may be missing another file (this is Debian sid):
root@c3cfce38249c:/# cat /usr/include/riscv64-linux-gnu/gnu/lib-names-lp64d.h
/* This file is automatically generated. */
#ifndef __GNU_LIB_NAMES_H
# error "Never use <gnu/lib-names-lp64d.h> directly; include <gnu/lib-names.h> instead."
#endif
#define LD_LINUX_RISCV64_LP64D_SO "ld-linux-riscv64-lp64d.so.1"
#define LD_SO "ld-linux-riscv64-lp64d.so.1"
#define LIBANL_SO "libanl.so.1"
#define LIBBROKENLOCALE_SO "libBrokenLocale.so.1"
#define LIBCRYPT_SO "libcrypt.so.1"
#define LIBC_MALLOC_DEBUG_SO "libc_malloc_debug.so.0"
#define LIBC_SO "libc.so.6"
#define LIBDL_SO "libdl.so.2"
#define LIBGCC_S_SO "libgcc_s.so.1"
#define LIBMVEC_SO "libmvec.so.1"
#define LIBM_SO "libm.so.6"
#define LIBNSL_SO "libnsl.so.1"
#define LIBNSS_COMPAT_SO "libnss_compat.so.2"
#define LIBNSS_DB_SO "libnss_db.so.2"
#define LIBNSS_DNS_SO "libnss_dns.so.2"
#define LIBNSS_FILES_SO "libnss_files.so.2"
#define LIBNSS_HESIOD_SO "libnss_hesiod.so.2"
#define LIBNSS_LDAP_SO "libnss_ldap.so.2"
#define LIBPTHREAD_SO "libpthread.so.0"
#define LIBRESOLV_SO "libresolv.so.2"
#define LIBRT_SO "librt.so.1"
#define LIBTHREAD_DB_SO "libthread_db.so.1"
#define LIBUTIL_SO "libutil.so.1"
Looks like this is where the lp64d interpreter is referenced. Still testing if this makes any difference...
Actually, nvm on the previous post - this file doesn't seem to be pulled in as part of compilation.
I think I found it - this line needs to switch on the abi to determine if it should use lp64, lp64f, or lp64d: https://github.com/ziglang/zig/blob/f5dbcd1cb4374be619ba0b18e40a069a7e860d93/lib/std/Target.zig#L1674
@bjia56 Would you be willing to add the fix for the interpreter to your PR?
@RossComputerGuy I haven't gotten around to building zig to test the interpreter fix yet, but hopefully will get to it later this week
From testing with _freeze_importlib (CPython), it looks like the binary depends on ld-linux-riscv64-lp64.so.1 as a shared library and would segfault in __libc_start_main (before the C main starts) even after manually using patchelf to switch the interpreter to ld-linux-riscv64-lp64d.so.1. Using patchelf to replace it with the lp64d shared object fixes the segfault, so the abi fix mentioned above is likely required for the glibc dynamic loader to work properly.
I will have a VisionFive2 tomorrow so I can start looking into real hardware testing then.
Thank you @RossComputerGuy
Just checking since I need this for my work over at #20389: What remains to be done here? :eyes:
@alexrp Just a review and merge
Hey @RossComputerGuy I built on your work here in #20909 which is now in master. There's still the .cfi_label issue, but I expect us to upgrade to LLVM 19 in this release cycle, so that should be resolved soon-ish. Thanks for getting the ball rolling on this!
Closing since our riscv64-linux-gnu support is now (to my knowledge) fully usable.