[PATCH 1/3] nios2: remove usage of libgcc
From: Simon Schuster
Date: Fri Oct 30 2026 - 11:54:15 EST
From: Dinh Nguyen <dinguyen@xxxxxxxxxx>
Use the kernel's runtime support for lshrdi3, ashldi3, ashrdi3, muldi3,
and ucmpdi2.
Copy over the math functions from a GPLv2 GCC implementation of divsi3,
udivsi3, mulsi3, umulsi3, modsi3, and gcc_bcmp.
Signed-off-by: Dinh Nguyen <dinguyen@xxxxxxxxxx>
Signed-off-by: Simon Schuster <schuster.simon@xxxxxxxxxxxxxxxxxx>
---
arch/nios2/Kconfig | 5 ++
arch/nios2/Makefile | 4 +-
arch/nios2/kernel/nios2_ksyms.c | 22 --------
arch/nios2/lib/Makefile | 1 +
arch/nios2/lib/math.c | 119 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 126 insertions(+), 25 deletions(-)
diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig
index 9c0e6eaeb005c..9417bcf583957 100644
--- a/arch/nios2/Kconfig
+++ b/arch/nios2/Kconfig
@@ -14,6 +14,11 @@ config NIOS2
select GENERIC_CPU_DEVICES
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
+ select GENERIC_LIB_LSHRDI3
+ select GENERIC_LIB_ASHLDI3
+ select GENERIC_LIB_ASHRDI3
+ select GENERIC_LIB_MULDI3
+ select GENERIC_LIB_UCMPDI2
select HAVE_ARCH_TRACEHOOK
select HAVE_ARCH_KGDB
select HAVE_PAGE_SIZE_4KB
diff --git a/arch/nios2/Makefile b/arch/nios2/Makefile
index f1ff4ce0f1a2c..173588c31abf9 100644
--- a/arch/nios2/Makefile
+++ b/arch/nios2/Makefile
@@ -19,8 +19,6 @@ UTS_SYSNAME = Linux
export MMU
-LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) $(KCFLAGS) -print-libgcc-file-name)
-
KBUILD_AFLAGS += -march=r$(CONFIG_NIOS2_ARCH_REVISION)
KBUILD_CFLAGS += -pipe -D__linux__ -D__ELF__
@@ -37,7 +35,7 @@ KBUILD_CFLAGS += -DUTS_SYSNAME=\"$(UTS_SYSNAME)\"
KBUILD_CFLAGS += -fno-builtin
KBUILD_CFLAGS += -G 0
-libs-y += arch/nios2/lib/ $(LIBGCC)
+libs-y += arch/nios2/lib/
INSTALL_PATH ?= /tftpboot
nios2-boot := arch/$(ARCH)/boot
diff --git a/arch/nios2/kernel/nios2_ksyms.c b/arch/nios2/kernel/nios2_ksyms.c
index e8710a269b398..351664e236fac 100644
--- a/arch/nios2/kernel/nios2_ksyms.c
+++ b/arch/nios2/kernel/nios2_ksyms.c
@@ -21,25 +21,3 @@ EXPORT_SYMBOL(memmove);
/* memory management */
EXPORT_SYMBOL(flush_icache_range);
-
-/*
- * libgcc functions - functions that are used internally by the
- * compiler... (prototypes are not correct though, but that
- * doesn't really matter since they're not versioned).
- */
-#define DECLARE_EXPORT(name) extern void name(void); EXPORT_SYMBOL(name)
-
-DECLARE_EXPORT(__gcc_bcmp);
-DECLARE_EXPORT(__divsi3);
-DECLARE_EXPORT(__moddi3);
-DECLARE_EXPORT(__modsi3);
-DECLARE_EXPORT(__udivmoddi4);
-DECLARE_EXPORT(__udivsi3);
-DECLARE_EXPORT(__umoddi3);
-DECLARE_EXPORT(__umodsi3);
-DECLARE_EXPORT(__muldi3);
-DECLARE_EXPORT(__mulsi3);
-DECLARE_EXPORT(__ucmpdi2);
-DECLARE_EXPORT(__lshrdi3);
-DECLARE_EXPORT(__ashldi3);
-DECLARE_EXPORT(__ashrdi3);
diff --git a/arch/nios2/lib/Makefile b/arch/nios2/lib/Makefile
index 9d5bf1df520c1..86433dcaac7e5 100644
--- a/arch/nios2/lib/Makefile
+++ b/arch/nios2/lib/Makefile
@@ -7,3 +7,4 @@ lib-y += delay.o
lib-y += memcpy.o
lib-y += memmove.o
lib-y += memset.o
+lib-y += math.o
diff --git a/arch/nios2/lib/math.c b/arch/nios2/lib/math.c
new file mode 100644
index 0000000000000..9a89fa268a96e
--- /dev/null
+++ b/arch/nios2/lib/math.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright Altera Corporation (C) 2026. All rights reserved.
+ */
+
+#include <linux/export.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+/*
+ * Software 32-bit multiply for cores built without the hardware multiplier.
+ */
+s32 __mulsi3(s32 a, s32 b);
+s32 __divsi3(s32 a, s32 b);
+s32 __udivsi3(s32 a, s32 b);
+s32 __modsi3(s32 a, s32 b);
+s32 __umodsi3(s32 a, s32 b);
+int __gcc_bcmp(const void *s1, const void *s2, size_t len);
+
+static u32 udivmodsi4(u32 num, u32 den, int modwanted)
+{
+ u32 bit = 1;
+ u32 res = 0;
+
+ while (den < num && bit && !(den & (1U << 31))) {
+ den <<= 1;
+ bit <<= 1;
+ }
+
+ while (bit) {
+ if (num >= den) {
+ num -= den;
+ res |= bit;
+ }
+ bit >>= 1;
+ den >>= 1;
+ }
+
+ return modwanted ? num : res;
+}
+
+s32 __mulsi3(s32 a, s32 b)
+{
+ s32 res = 0;
+ u32 cnt = a;
+
+ while (cnt) {
+ if (cnt & 1)
+ res += b;
+
+ b <<= 1;
+ cnt >>= 1;
+ }
+
+ return res;
+}
+EXPORT_SYMBOL(__mulsi3);
+
+s32 __divsi3(s32 a, s32 b)
+{
+ int neg = 0;
+ s32 res;
+
+ if (a < 0) {
+ a = -a;
+ neg = !neg;
+ }
+
+ if (b < 0) {
+ b = -b;
+ neg = !neg;
+ }
+
+ res = udivmodsi4(a, b, 0);
+ if (neg)
+ res = -res;
+
+ return res;
+}
+EXPORT_SYMBOL(__divsi3);
+
+s32 __udivsi3(s32 a, s32 b)
+{
+ return udivmodsi4(a, b, 0);
+}
+EXPORT_SYMBOL(__udivsi3);
+
+s32 __modsi3(s32 a, s32 b)
+{
+ int neg = 0;
+ s32 res;
+
+ if (a < 0) {
+ a = -a;
+ neg = 1;
+ }
+
+ if (b < 0)
+ b = -b;
+
+ res = udivmodsi4(a, b, 1);
+ if (neg)
+ res = -res;
+
+ return res;
+}
+EXPORT_SYMBOL(__modsi3);
+
+s32 __umodsi3(s32 a, s32 b)
+{
+ return udivmodsi4(a, b, 1);
+}
+EXPORT_SYMBOL(__umodsi3);
+
+int __gcc_bcmp(const void *s1, const void *s2, size_t len)
+{
+ return memcmp(s1, s2, len);
+}
+EXPORT_SYMBOL(__gcc_bcmp);
+
--
2.39.5