When GCC optimizes for size, it branches to libgcc's _restgpr_N_x
routines to restore non-volatile registers. U-Boot's private libgcc
lacks these routines, so builds with CONFIG_USE_PRIVATE_LIBGCC=y fail
to link with Debian's GCC 14.2, for example qemu-ppce500:

  undefined reference to `_restgpr_31_x'

Copy the 32-bit integer register save and restore routines from
Linux's arch/powerpc/lib/crtsavres.S (v7.3-rc5), following the private
libgcc's existing approach for shift routines. Put each group of
routines in its own section so --gc-sections can discard unused
groups. Linux's CONFIG_CC_OPTIMIZE_FOR_SIZE condition is then not
needed.

Signed-off-by: Josef Schlehofer <[email protected]>
Cc: Tom Rini <[email protected]>
Cc: Christophe Leroy <[email protected]>
Cc: Marek BehĂșn <[email protected]>
---
Changes in v2:
- new patch

The routines assemble to the same code as crtsavgpr.o, crtresgpr.o and
crtresxgpr.o in Debian's libgcc 14.2.
---
 arch/powerpc/lib/Makefile    |   3 +-
 arch/powerpc/lib/crtsavres.S | 213 +++++++++++++++++++++++++++++++++++
 2 files changed, 215 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/lib/crtsavres.S

diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index a3048975ae7..90f0e1e5fa9 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -5,7 +5,8 @@
 
 ## Build a couple of necessary functions into a private libgcc
 ## if the user asked for it
-lib-$(CONFIG_USE_PRIVATE_LIBGCC) += _ashldi3.o _ashrdi3.o _lshrdi3.o
+lib-$(CONFIG_USE_PRIVATE_LIBGCC) += _ashldi3.o _ashrdi3.o _lshrdi3.o \
+                                   crtsavres.o
 
 MINIMAL=
 
diff --git a/arch/powerpc/lib/crtsavres.S b/arch/powerpc/lib/crtsavres.S
new file mode 100644
index 00000000000..8c35eedecb6
--- /dev/null
+++ b/arch/powerpc/lib/crtsavres.S
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Out-of-line integer register save and restore routines, which GCC calls
+ * from function prologues and epilogues when it optimizes for size.
+ *
+ * This code was copied from crtsavres.S in arch/powerpc/lib of the Linux
+ * kernel sources (v7.3-rc5, last changed by commit 699d53f04829
+ * ("powerpc/vdso32: Fix use of crtsavres for PPC64")): the 32-bit integer
+ * register routines, without the CONFIG_CC_OPTIMIZE_FOR_SIZE condition.
+ * Each group of routines is in a section of its own, so that --gc-sections
+ * drops the groups that nothing calls. The source file copyrights are as
+ * follows:
+ *
+ *   Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
+ *   Copyright 2008 Freescale Semiconductor, Inc.
+ *   Written By Michael Meissner
+ *
+ * Based on gcc/config/rs6000/crtsavres.asm from gcc
+ */
+
+#include <asm/processor.h>
+
+/* Routines for saving integer registers, called by the compiler.  */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the integer save area.  */
+
+       .section ".text._savegpr_14","ax",@progbits
+       .align  2
+
+_GLOBAL(_savegpr_14)
+_GLOBAL(_save32gpr_14)
+       stw     14,-72(11)      /* save gp registers */
+_GLOBAL(_savegpr_15)
+_GLOBAL(_save32gpr_15)
+       stw     15,-68(11)
+_GLOBAL(_savegpr_16)
+_GLOBAL(_save32gpr_16)
+       stw     16,-64(11)
+_GLOBAL(_savegpr_17)
+_GLOBAL(_save32gpr_17)
+       stw     17,-60(11)
+_GLOBAL(_savegpr_18)
+_GLOBAL(_save32gpr_18)
+       stw     18,-56(11)
+_GLOBAL(_savegpr_19)
+_GLOBAL(_save32gpr_19)
+       stw     19,-52(11)
+_GLOBAL(_savegpr_20)
+_GLOBAL(_save32gpr_20)
+       stw     20,-48(11)
+_GLOBAL(_savegpr_21)
+_GLOBAL(_save32gpr_21)
+       stw     21,-44(11)
+_GLOBAL(_savegpr_22)
+_GLOBAL(_save32gpr_22)
+       stw     22,-40(11)
+_GLOBAL(_savegpr_23)
+_GLOBAL(_save32gpr_23)
+       stw     23,-36(11)
+_GLOBAL(_savegpr_24)
+_GLOBAL(_save32gpr_24)
+       stw     24,-32(11)
+_GLOBAL(_savegpr_25)
+_GLOBAL(_save32gpr_25)
+       stw     25,-28(11)
+_GLOBAL(_savegpr_26)
+_GLOBAL(_save32gpr_26)
+       stw     26,-24(11)
+_GLOBAL(_savegpr_27)
+_GLOBAL(_save32gpr_27)
+       stw     27,-20(11)
+_GLOBAL(_savegpr_28)
+_GLOBAL(_save32gpr_28)
+       stw     28,-16(11)
+_GLOBAL(_savegpr_29)
+_GLOBAL(_save32gpr_29)
+       stw     29,-12(11)
+_GLOBAL(_savegpr_30)
+_GLOBAL(_save32gpr_30)
+       stw     30,-8(11)
+_GLOBAL(_savegpr_31)
+_GLOBAL(_save32gpr_31)
+       stw     31,-4(11)
+       blr
+
+/* Routines for restoring integer registers, called by the compiler.  */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the integer restore area.  */
+
+       .section ".text._restgpr_14","ax",@progbits
+       .align  2
+
+_GLOBAL(_restgpr_14)
+_GLOBAL(_rest32gpr_14)
+       lwz     14,-72(11)      /* restore gp registers */
+_GLOBAL(_restgpr_15)
+_GLOBAL(_rest32gpr_15)
+       lwz     15,-68(11)
+_GLOBAL(_restgpr_16)
+_GLOBAL(_rest32gpr_16)
+       lwz     16,-64(11)
+_GLOBAL(_restgpr_17)
+_GLOBAL(_rest32gpr_17)
+       lwz     17,-60(11)
+_GLOBAL(_restgpr_18)
+_GLOBAL(_rest32gpr_18)
+       lwz     18,-56(11)
+_GLOBAL(_restgpr_19)
+_GLOBAL(_rest32gpr_19)
+       lwz     19,-52(11)
+_GLOBAL(_restgpr_20)
+_GLOBAL(_rest32gpr_20)
+       lwz     20,-48(11)
+_GLOBAL(_restgpr_21)
+_GLOBAL(_rest32gpr_21)
+       lwz     21,-44(11)
+_GLOBAL(_restgpr_22)
+_GLOBAL(_rest32gpr_22)
+       lwz     22,-40(11)
+_GLOBAL(_restgpr_23)
+_GLOBAL(_rest32gpr_23)
+       lwz     23,-36(11)
+_GLOBAL(_restgpr_24)
+_GLOBAL(_rest32gpr_24)
+       lwz     24,-32(11)
+_GLOBAL(_restgpr_25)
+_GLOBAL(_rest32gpr_25)
+       lwz     25,-28(11)
+_GLOBAL(_restgpr_26)
+_GLOBAL(_rest32gpr_26)
+       lwz     26,-24(11)
+_GLOBAL(_restgpr_27)
+_GLOBAL(_rest32gpr_27)
+       lwz     27,-20(11)
+_GLOBAL(_restgpr_28)
+_GLOBAL(_rest32gpr_28)
+       lwz     28,-16(11)
+_GLOBAL(_restgpr_29)
+_GLOBAL(_rest32gpr_29)
+       lwz     29,-12(11)
+_GLOBAL(_restgpr_30)
+_GLOBAL(_rest32gpr_30)
+       lwz     30,-8(11)
+_GLOBAL(_restgpr_31)
+_GLOBAL(_rest32gpr_31)
+       lwz     31,-4(11)
+       blr
+
+/* Routines for restoring integer registers, called by the compiler.  */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the integer restore area.  */
+
+       .section ".text._restgpr_14_x","ax",@progbits
+       .align  2
+
+_GLOBAL(_restgpr_14_x)
+_GLOBAL(_rest32gpr_14_x)
+       lwz     14,-72(11)      /* restore gp registers */
+_GLOBAL(_restgpr_15_x)
+_GLOBAL(_rest32gpr_15_x)
+       lwz     15,-68(11)
+_GLOBAL(_restgpr_16_x)
+_GLOBAL(_rest32gpr_16_x)
+       lwz     16,-64(11)
+_GLOBAL(_restgpr_17_x)
+_GLOBAL(_rest32gpr_17_x)
+       lwz     17,-60(11)
+_GLOBAL(_restgpr_18_x)
+_GLOBAL(_rest32gpr_18_x)
+       lwz     18,-56(11)
+_GLOBAL(_restgpr_19_x)
+_GLOBAL(_rest32gpr_19_x)
+       lwz     19,-52(11)
+_GLOBAL(_restgpr_20_x)
+_GLOBAL(_rest32gpr_20_x)
+       lwz     20,-48(11)
+_GLOBAL(_restgpr_21_x)
+_GLOBAL(_rest32gpr_21_x)
+       lwz     21,-44(11)
+_GLOBAL(_restgpr_22_x)
+_GLOBAL(_rest32gpr_22_x)
+       lwz     22,-40(11)
+_GLOBAL(_restgpr_23_x)
+_GLOBAL(_rest32gpr_23_x)
+       lwz     23,-36(11)
+_GLOBAL(_restgpr_24_x)
+_GLOBAL(_rest32gpr_24_x)
+       lwz     24,-32(11)
+_GLOBAL(_restgpr_25_x)
+_GLOBAL(_rest32gpr_25_x)
+       lwz     25,-28(11)
+_GLOBAL(_restgpr_26_x)
+_GLOBAL(_rest32gpr_26_x)
+       lwz     26,-24(11)
+_GLOBAL(_restgpr_27_x)
+_GLOBAL(_rest32gpr_27_x)
+       lwz     27,-20(11)
+_GLOBAL(_restgpr_28_x)
+_GLOBAL(_rest32gpr_28_x)
+       lwz     28,-16(11)
+_GLOBAL(_restgpr_29_x)
+_GLOBAL(_rest32gpr_29_x)
+       lwz     29,-12(11)
+_GLOBAL(_restgpr_30_x)
+_GLOBAL(_rest32gpr_30_x)
+       lwz     30,-8(11)
+_GLOBAL(_restgpr_31_x)
+_GLOBAL(_rest32gpr_31_x)
+       lwz     0,4(11)
+       lwz     31,-4(11)
+       mtlr    0
+       mr      1,11
+       blr
-- 
2.54.0 (Apple Git-157)

Reply via email to