[U-Boot] [PATCH v2] x86: Wrap small helper functions from libgcc to avoid an ABI mismatch

Gabe Black gabeblack at chromium.org
Tue Nov 8 23:34:04 CET 2011


When gcc compiles some 64 bit operations on a 32 bit machine, it generates
calls to small functions instead of instructions which do the job directly.
Those functions are defined in libgcc and transparently provide whatever
functionality was necessary. Unfortunately, u-boot can be built with a
non-standard ABI when libgcc isn't. More specifically, u-boot uses
-mregparm. When the u-boot and libgcc are linked together, very confusing
bugs can crop up, for instance seemingly normal integer division or modulus
getting the wrong answer or even raising a spurious divide by zero
exception.

This change barrows (steals) a technique and some code from coreboot which
solves this problem by creating wrappers which translate the calling
convention when calling the functions in libgcc. Unfortunately that means that
these instructions which had already been turned into functions have even more
overhead, but more importantly it makes them work properly.

To find all of the functions that needed wrapping, u-boot was compiled without
linking in libgcc. All the symbols the linker complained were undefined were
presumed to be the symbols that are needed from libgcc. These were a subset of
the symbols covered by the coreboot code, so it was used unmodified.

Signed-off-by: Gabe Black <gabeblack at chromium.org>
---
Changes in v2:
- Change the [x86] tag to x86:
- Mention -mregparm in the commit message.
- Get rid of a stray line which snuck in during a rebase.

 arch/x86/config.mk    |    2 ++
 arch/x86/lib/Makefile |    1 +
 arch/x86/lib/gcc.c    |   38 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 41 insertions(+), 0 deletions(-)
 create mode 100644 arch/x86/lib/gcc.c

diff --git a/arch/x86/config.mk b/arch/x86/config.mk
index fe9083f..995fa1e 100644
--- a/arch/x86/config.mk
+++ b/arch/x86/config.mk
@@ -41,3 +41,5 @@ PLATFORM_RELFLAGS += -ffunction-sections -fvisibility=hidden
 PLATFORM_LDFLAGS += --emit-relocs -Bsymbolic -Bsymbolic-functions
 
 LDFLAGS_FINAL += --gc-sections -pie
+LDFLAGS_FINAL += --wrap=__divdi3 --wrap=__udivdi3
+LDFLAGS_FINAL += --wrap=__moddi3 --wrap=__umoddi3
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 71e94f7..210dbbe 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -32,6 +32,7 @@ SOBJS-y	+= realmode_switch.o
 COBJS-y	+= bios_setup.o
 COBJS-y	+= board.o
 COBJS-y	+= bootm.o
+COBJS-y	+= gcc.o
 COBJS-y	+= interrupts.o
 COBJS-$(CONFIG_SYS_PCAT_INTERRUPTS) += pcat_interrupts.o
 COBJS-$(CONFIG_SYS_GENERIC_TIMER) += pcat_timer.o
diff --git a/arch/x86/lib/gcc.c b/arch/x86/lib/gcc.c
new file mode 100644
index 0000000..b11ea5f
--- /dev/null
+++ b/arch/x86/lib/gcc.c
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 coresystems GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 or later of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#ifdef __GNUC__
+
+/*
+ * GCC's libgcc handling is quite broken. While the libgcc functions
+ * are always regparm(0) the code that calls them uses whatever the
+ * compiler call specifies. Therefore we need a wrapper around those
+ * functions. See gcc bug PR41055 for more information.
+ */
+#define WRAP_LIBGCC_CALL(type, name) \
+	type __real_##name(type a, type b) __attribute__((regparm(0))); \
+	type __wrap_##name(type a, type b); \
+	type __wrap_##name(type a, type b) { return __real_##name(a, b); }
+
+WRAP_LIBGCC_CALL(long long, __divdi3)
+WRAP_LIBGCC_CALL(unsigned long long, __udivdi3)
+WRAP_LIBGCC_CALL(long long, __moddi3)
+WRAP_LIBGCC_CALL(unsigned long long, __umoddi3)
+
+#endif
-- 
1.7.3.1



More information about the U-Boot mailing list