diff --git a/ARCHES b/ARCHES index a31b376ed3..a2cc13f027 100644 --- a/ARCHES +++ b/ARCHES @@ -12,3 +12,5 @@ mips-linux-muslsf mipsel-linux-muslsf mips64-linux-muslsf s390x-linux-musl +riscv64-linux-musl +loongarch64-unknown-linux-musl diff --git a/Makefile b/Makefile index 5b012d5502..8baa0d1c99 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ ARCHES := $(shell cat ARCHES) # Create the individual build/clean/dist-clean rules for each arch... define rules_for_each_arch -$(strip $(1)).build: $(TOOLS)/musl-cross/.unpacked $(ROOT)/mettle/configure +$(strip $(1)).build: $(TOOLS)/musl-cross/.unpacked $(if $(findstring riscv64,$(strip $(1))),$(TOOLS)/musl-cross/.riscv64-unpacked) $(if $(findstring loongarch64,$(strip $(1))),$(TOOLS)/musl-cross/.loongarch64-unpacked) $(ROOT)/mettle/configure make TARGET=$(strip $(1)) $(strip $(1)).install: diff --git a/README.md b/README.md index 5fdfa5bc79..a6eef79860 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,8 @@ The available platform triples for Linux targets are: * `mipsel-linux-muslsf` * `mips64-linux-muslsf` * `s390x-linux-musl` +* `riscv64-linux-musl` +* `loongarch64-unknown-linux-musl` For Mingw32-64 Windows targets, the following triples are added. On up-to-date Debian / Ubuntu systems, the `mingw-w64` package will install both toolchains. diff --git a/make/Makefile.common b/make/Makefile.common index 6d4911d29a..8ef042f700 100644 --- a/make/Makefile.common +++ b/make/Makefile.common @@ -26,7 +26,7 @@ ifeq (,$(findstring mingw,$(TARGET))) endif CPPFLAGS:=$(CPPFLAGS) -I$(BUILD)/include -DCURL_STATICLIB -CONFIG_FIXUP=cp $(ROOT)/mettle/config.guess $(ROOT)/mettle/config.sub . ; +CONFIG_FIXUP=cp $(ROOT)/mettle/config.guess $(ROOT)/mettle/config.sub . ; [ ! -d config ] || cp $(ROOT)/mettle/config.guess $(ROOT)/mettle/config.sub config/ ; CONFIGURE=configure --prefix=$(BUILD) --disable-shared ac_cv_path_PKGCONFIG=$(CWD)/pkg-config CONFIGURE_STATIC=configure --prefix=$(BUILD) --static ifneq "$(TARGET)" "native" @@ -41,6 +41,18 @@ ifeq "$(D)" "1" CFLAGS:=$(CFLAGS) -g endif +# loongarch64's toolchain is much newer (GCC 14) than the others here and +# flags -Werror=calloc-transposed-args (added in GCC 14) against several +# third-party deps (json-c, etc) that pass calloc()'s count/size arguments +# in the other order. Harmless either way since both arguments are +# multiplied together, so silence it for this target rather than patching +# every affected dep. Must land before ENV is captured below, since libs +# built with -Werror do so via their own build systems (eg. json-c's +# configure.ac appends -Wall -Werror itself), not by inheriting it from us. +ifneq (,$(findstring loongarch64,$(TARGET))) + CFLAGS:=$(CFLAGS) -Wno-error=calloc-transposed-args +endif + # Libraries cannot be compiled with -Werror due to the multiple compilation warnings. # This would be probably a good idea to update them to their latest versions and see if these issues are fixed. ENV:=$(ENV) ARFLAGS="cr" AR_FLAGS="cr" LDFLAGS="-L$(BUILD)/lib $(LDFLAGS)" CC="$(CC)" CPP="$(CPP)" AR="$(AR)" RANLIB="$(RANLIB)" CFLAGS="$(CFLAGS)" CPPFLAGS="$(CPPFLAGS)" OBJCFLAGS="$(OBJCFLAGS)" diff --git a/make/Makefile.libpcap b/make/Makefile.libpcap index 37c708cbca..7ca32021fd 100644 --- a/make/Makefile.libpcap +++ b/make/Makefile.libpcap @@ -30,10 +30,23 @@ $(BUILD)/libpcap/Makefile: $(TOOLS) $(BUILD)/libpcap/configure $(LIBPCAP_DEPS) $(CONFIG_FIXUP) \ $(ENV) ./$(CONFIGURE) $(LIBPCAP_CONFIG_FLAGS) $(LOGBUILD) +# libpcap's AC_LBL_C_INIT macro has a pre-existing bug (unrelated to +# riscv64) where its "if test $GCC = yes" check doesn't see the +# already-detected GNU compiler at that point in the generated configure +# script, falling into the non-GCC branch that appends -I/usr/local/include +# to INCLS. That's always been silently harmless before, since the old +# musl-cross toolchains don't care about host-path leakage; the riscv64 +# Buildroot toolchain's wrapper actively rejects it as unsafe cross-compile +# input. INCLS is a plain (non-recursive) Makefile variable, so it can be +# overridden straight on the make command line. +ifneq (,$(findstring riscv64,$(TARGET))) + LIBPCAP_BUILD_FLAGS = INCLS=-I. +endif + $(BUILD)/lib/libpcap.a: $(BUILD)/libpcap/Makefile @echo "Building libpcap for $(TARGET)" @cd $(BUILD)/libpcap; \ - $(ENV) $(MAKE) $(LOGBUILD) ; \ - $(MAKE_INSTALL) $(LOGBUILD) + $(ENV) $(MAKE) $(LIBPCAP_BUILD_FLAGS) $(LOGBUILD) ; \ + $(MAKE_INSTALL) $(LIBPCAP_BUILD_FLAGS) $(LOGBUILD) libpcap: $(BUILD)/lib/libpcap.a diff --git a/make/Makefile.libsigar b/make/Makefile.libsigar index cc5a7240e4..dd512d9864 100644 --- a/make/Makefile.libsigar +++ b/make/Makefile.libsigar @@ -4,7 +4,8 @@ $(BUILD)/libsigar/configure: @cd $(BUILD); \ rm -fr libsigar; \ $(TAR) zxf $(ROOT)/deps/libsigar-1.6.7.tar.gz; \ - mv libsigar-1.6.7 libsigar + mv libsigar-1.6.7 libsigar; \ + sed -i 's/case 192: return "num";/case 192: return "num"; case 243: return "riscv64"; case 258: return "loongarch64";/' libsigar/src/sigar_elf.c $(BUILD)/libsigar/Makefile: $(TOOLS) $(BUILD)/libsigar/configure @echo "Configuring libsigar for $(TARGET)" diff --git a/make/Makefile.tools b/make/Makefile.tools index e885c09ec6..7c99cdd6dc 100644 --- a/make/Makefile.tools +++ b/make/Makefile.tools @@ -86,6 +86,18 @@ ifneq (,$(findstring musl,$(TARGET))) TOOLS_DEPS:=$(TOOLS_DEPS) $(TOOLS)/musl-cross/.unpacked elf2bin endif +# riscv64's toolchain is fetched and wired up separately; see the +# .riscv64-unpacked rule below for why. +ifneq (,$(findstring riscv64,$(TARGET))) + TOOLS_DEPS:=$(TOOLS_DEPS) $(TOOLS)/musl-cross/.riscv64-unpacked +endif + +# loongarch64's toolchain is fetched and wired up separately; see the +# .loongarch64-unpacked rule below for why. +ifneq (,$(findstring loongarch64,$(TARGET))) + TOOLS_DEPS:=$(TOOLS_DEPS) $(TOOLS)/musl-cross/.loongarch64-unpacked +endif + ifeq "$(shell uname -s)" "Darwin" BUILD_HOST=osx TOOLS_DEPS:=$(TOOLS_DEPS) coreutils @@ -244,4 +256,94 @@ $(TOOLS)/musl-cross/.unpacked: musl-cross-$(BUILD_HOST)-$(TOOLCHAIN_VERSION).tar @cd $(TOOLS) && tar xfm $(ROOT)/musl-cross-$(BUILD_HOST)-$(TOOLCHAIN_VERSION).tar.xz @touch $(TOOLS)/musl-cross/.unpacked +# riscv64 isn't in the shared musl-cross bundle (it predates musl's riscv64 +# port). The musl.cc riscv64-linux-musl-cross toolchain (gcc 11.2.1) is +# available, but its binutils has a genuine bug linking -static-pie for +# riscv64: it leaves R_RISCV_JUMP_SLOT relocations against PLT stubs that +# never get resolved (no dynamic linker in a static binary), segfaulting +# at the first such call. Confirmed arch-specific, not a general +# "newer toolchain" issue: the exact same gcc/binutils vintage links a +# clean, correct static-pie binary for aarch64. A newer toolchain (gcc +# 13.2.0 / binutils 2.42, from Bootlin) fixes it for riscv64 too, so that's +# what's used here instead. +# +# Its tool prefix (riscv64-buildroot-linux-musl-*) differs from the +# riscv64-linux-musl-* convention every other rule in this file assumes +# (CC=$(TOOLS)/musl-cross/bin/$(TARGET)-*), so thin exec wrapper scripts +# are generated under that expected name. Plain symlinks don't work here: +# Buildroot's gcc/g++ are themselves wrapper scripts that derive the real +# (*.br_real) binary's name from their own invoked name, which breaks +# under a symlink with a different basename; exec'ing from a real script +# gives the real binary its own correct argv0. +RISCV64_TOOLCHAIN=riscv64-lp64d--musl--bleeding-edge-2024.02-1 +RISCV64_TOOLCHAIN_PREFIX=riscv64-buildroot-linux-musl + +$(RISCV64_TOOLCHAIN).tar.bz2: + @echo "Downloading riscv64 toolchain" + curl -f -O https://toolchains.bootlin.com/downloads/releases/toolchains/riscv64-lp64d/tarballs/$(RISCV64_TOOLCHAIN).tar.bz2 + +$(TOOLS)/musl-cross/.riscv64-unpacked: $(TOOLS)/musl-cross/.unpacked $(RISCV64_TOOLCHAIN).tar.bz2 + @echo "Unpacking riscv64 toolchain" + @if [ "$(shell uname -s)" != "Linux" ] || [ "$(shell uname -m)" != "x86_64" ]; then \ + echo "$(RISCV64_TOOLCHAIN).tar.bz2 only ships Linux x86_64 host binaries; can't build riscv64 targets on $(shell uname -s) $(shell uname -m)" >&2; \ + exit 1; \ + fi + @rm -fr $(TOOLS)/riscv64-buildroot + @mkdir -p $(TOOLS)/riscv64-buildroot + @cd $(TOOLS)/riscv64-buildroot && tar xfj $(ROOT)/$(RISCV64_TOOLCHAIN).tar.bz2 --strip-components=1 + @$(TOOLS)/riscv64-buildroot/relocate-sdk.sh + @mkdir -p $(TOOLS)/musl-cross/bin + @for t in $(TOOLS)/riscv64-buildroot/bin/$(RISCV64_TOOLCHAIN_PREFIX)-*; do \ + base=$$(basename $$t); \ + case $$base in *.br_real) continue ;; esac; \ + name=$${base#$(RISCV64_TOOLCHAIN_PREFIX)-}; \ + case $$name in cc|c++) continue ;; esac; \ + wrapper=$(TOOLS)/musl-cross/bin/riscv64-linux-musl-$$name; \ + printf '#!/bin/sh\nexec "%s" "$$@"\n' "$$t" > $$wrapper; \ + chmod +x $$wrapper; \ + done + @touch $(TOOLS)/musl-cross/.riscv64-unpacked + +# loongarch64 predates musl's port too (musl added support in 1.2.4/1.2.5), +# and doesn't appear in the shared musl-cross bundle or in Bootlin's +# toolchain catalog. The loong64/cross-tools project publishes a musl-libc +# loongarch64-unknown-linux-musl toolchain (crosstool-NG, gcc 14.3.0) built +# for an x86_64 Linux host; pinned to a specific dated release here for +# reproducibility, since "latest"/"stable" tags in that repo move. +# +# Its tool prefix (loongarch64-unknown-linux-musl-*) already matches the +# ARCHES/TARGET convention this file assumes (CC=$(TOOLS)/musl-cross/bin/ +# $(TARGET)-*), so no renaming wrapper is needed here. And unlike +# Buildroot's gcc/g++ (see the riscv64 rule above), these are plain, +# non-argv0-dependent ELF binaries with no baked-in RPATH, so plain +# symlinks into musl-cross/bin work fine -- verified gcc resolves its own +# real install path through the symlink and finds its libexec/lib/sysroot. +# +# Default -static --static -pie silently produces a plain static EXEC (no +# PIE) on this toolchain rather than failing, so mettle/configure.ac special +# -cases loongarch64 to just -static-pie, which links a correct static-pie +# binary here on its own (verified via readelf: DYN type, no PT_INTERP, no +# NEEDED entries, only R_LARCH_RELATIVE relocs). +LOONGARCH64_TOOLCHAIN_RELEASE=20260612 +LOONGARCH64_TOOLCHAIN=x86_64-cross-tools-loongarch64-unknown-linux-musl-stable + +$(LOONGARCH64_TOOLCHAIN).tar.xz: + @echo "Downloading loongarch64 toolchain" + curl -fL -o $(LOONGARCH64_TOOLCHAIN).tar.xz https://github.com/loong64/cross-tools/releases/download/$(LOONGARCH64_TOOLCHAIN_RELEASE)/$(LOONGARCH64_TOOLCHAIN).tar.xz + +$(TOOLS)/musl-cross/.loongarch64-unpacked: $(TOOLS)/musl-cross/.unpacked $(LOONGARCH64_TOOLCHAIN).tar.xz + @echo "Unpacking loongarch64 toolchain" + @if [ "$(shell uname -s)" != "Linux" ] || [ "$(shell uname -m)" != "x86_64" ]; then \ + echo "$(LOONGARCH64_TOOLCHAIN).tar.xz only ships Linux x86_64 host binaries; can't build loongarch64 targets on $(shell uname -s) $(shell uname -m)" >&2; \ + exit 1; \ + fi + @rm -fr $(TOOLS)/loongarch64-cross + @mkdir -p $(TOOLS)/loongarch64-cross + @cd $(TOOLS)/loongarch64-cross && tar xf $(ROOT)/$(LOONGARCH64_TOOLCHAIN).tar.xz --strip-components=1 + @mkdir -p $(TOOLS)/musl-cross/bin + @for t in $(TOOLS)/loongarch64-cross/bin/loongarch64-unknown-linux-musl-*; do \ + ln -sf $$t $(TOOLS)/musl-cross/bin/$$(basename $$t); \ + done + @touch $(TOOLS)/musl-cross/.loongarch64-unpacked + $(TOOLS): $(TOOLS_DEPS) diff --git a/mettle/configure.ac b/mettle/configure.ac index 24d8f3b38a..b680be01b9 100644 --- a/mettle/configure.ac +++ b/mettle/configure.ac @@ -88,7 +88,28 @@ AC_CONFIG_FILES([ AC_ARG_ENABLE([staticpie], AS_HELP_STRING([--enable-staticpie], [Building Static PIE])) AS_IF([test "x$enable_staticpie" = "xyes"], [ - AC_SUBST([PLATFORM_LDADD], ['-static --static -pie']) + AS_CASE([$host_cpu], + dnl -static --static -pie relies on crt1.o rather than the + dnl relocatable rcrt1.o, needed for a real static-pie link. + dnl -static-pie alone isn't enough on this toolchain: its gcc + dnl driver only conditions -dynamic-linker on literal "-static" + dnl (not "-static-pie"), so without an explicit override the + dnl linker still emits a dynamically-linked PIE with a real + dnl PT_INTERP. Passing -static and -pie straight to the linker, + dnl plus suppressing the interpreter explicitly, produces a + dnl correct static-pie binary (verified via readelf: DYN type, + dnl no PT_INTERP, no NEEDED entries, zero JUMP_SLOT relocs). + [riscv64], [AC_SUBST([PLATFORM_LDADD], ['-static-pie -Wl,-static -Wl,-pie -Wl,--no-dynamic-linker'])], + dnl -static --static -pie silently links a plain static EXEC + dnl (no PIE at all) on this toolchain instead of erroring, so + dnl the omission wouldn't be caught by a build failure. Plain + dnl -static-pie alone already produces a correct static-pie + dnl binary here (verified via readelf: DYN type, no PT_INTERP, + dnl no NEEDED entries, only R_LARCH_RELATIVE relocs), so no + dnl further linker overrides are needed like riscv64 required. + [loongarch64], [AC_SUBST([PLATFORM_LDADD], ['-static-pie'])], + [AC_SUBST([PLATFORM_LDADD], ['-static --static -pie'])] + ) AM_CONDITIONAL([MAKEBIN], [true]) ], [ AM_CONDITIONAL([MAKEBIN], [false]) diff --git a/mettle/m4/check-libc.m4 b/mettle/m4/check-libc.m4 index 5e5e9b3069..aef85a963d 100644 --- a/mettle/m4/check-libc.m4 +++ b/mettle/m4/check-libc.m4 @@ -23,7 +23,7 @@ AM_CONDITIONAL([HAVE_TIMEGM], [test "x$ac_cv_func_timegm" = xyes]) AC_DEFUN([CHECK_PROGNAME], [ AC_CACHE_CHECK([if libc defines __progname], ac_cv_libc_defines___progname, [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ extern char *__progname; printf("%s", __progname); ]])], [ ac_cv_libc_defines___progname="yes" ], [ ac_cv_libc_defines___progname="no" diff --git a/util/elf.h b/util/elf.h index e3c9865ceb..24e2d5036e 100644 --- a/util/elf.h +++ b/util/elf.h @@ -219,6 +219,8 @@ typedef struct { #define EM_MICROBLAZE 189 #define EM_TILEGX 191 #define EM_NUM 192 +#define EM_RISCV 243 +#define EM_LOONGARCH 258 #define EM_ALPHA 0x9026 // The following conflicts with a libev define, don't think we're actually