On 05/05/21 15:14, Paolo Bonzini wrote:
The -nostdlib flag disables the driver from adding libclang_rt.*.a
during linking. Adding a specific library to the command line such as
libgcc then causes the linker to report unresolved symbols, because the
libraries that resolve those symbols aren't automatically added.
libgcc however is only needed for long division (64-bit by 64-bit).
Instead of linking the whole of it, implement the routines that are
needed.
Reported-by: Bill Wendling <morbo@xxxxxxxxxx>
Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
Oops, I didn't actually remove libgcc!
diff --git a/Makefile b/Makefile
index 24b7917..ddebcae 100644
--- a/Makefile
+++ b/Makefile
@@ -25,8 +25,6 @@ cc-option = $(shell if $(CC) -Werror $(1) -S -o /dev/null -xc /dev/null \
#make sure env CFLAGS variable is not used
CFLAGS =
-libgcc := $(shell $(CC) --print-libgcc-file-name)
-
libcflat := lib/libcflat.a
cflatobjs := \
lib/argv.o \
diff --git a/arm/Makefile.common b/arm/Makefile.common
index 55478ec..38385e0 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -58,9 +58,7 @@ OBJDIRS += lib/arm
libeabi = lib/arm/libeabi.a
eabiobjs = lib/arm/eabi_compat.o
-libgcc := $(shell $(CC) $(machine) --print-libgcc-file-name)
-
-FLATLIBS = $(libcflat) $(LIBFDT_archive) $(libgcc) $(libeabi)
+FLATLIBS = $(libcflat) $(LIBFDT_archive) $(libeabi)
%.elf: LDFLAGS = -nostdlib $(arch_LDFLAGS)
%.elf: %.o $(FLATLIBS) $(SRCDIR)/arm/flat.lds $(cstart.o)
$(CC) $(CFLAGS) -c -o $(@:.elf=.aux.o) $(SRCDIR)/lib/auxinfo.c \
diff --git a/x86/Makefile.common b/x86/Makefile.common
index 55f7f28..52bb7aa 100644
--- a/x86/Makefile.common
+++ b/x86/Makefile.common
@@ -37,12 +37,10 @@ COMMON_CFLAGS += -O1
# stack.o relies on frame pointers.
KEEP_FRAME_POINTER := y
-libgcc := $(shell $(CC) -m$(bits) --print-libgcc-file-name)
-
# We want to keep intermediate file: %.elf and %.o
.PRECIOUS: %.elf %.o
-FLATLIBS = lib/libcflat.a $(libgcc)
+FLATLIBS = lib/libcflat.a
%.elf: %.o $(FLATLIBS) $(SRCDIR)/x86/flat.lds $(cstart.o)
$(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,$(SRCDIR)/x86/flat.lds \
$(filter %.o, $^) $(FLATLIBS)
---
arm/Makefile.arm | 1 +
lib/ldiv32.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++
x86/Makefile.i386 | 2 +-
3 files changed, 107 insertions(+), 1 deletion(-)
create mode 100644 lib/ldiv32.c
diff --git a/arm/Makefile.arm b/arm/Makefile.arm
index d379a28..687a8ed 100644
--- a/arm/Makefile.arm
+++ b/arm/Makefile.arm
@@ -23,6 +23,7 @@ cstart.o = $(TEST_DIR)/cstart.o
cflatobjs += lib/arm/spinlock.o
cflatobjs += lib/arm/processor.o
cflatobjs += lib/arm/stack.o
+cflatobjs += lib/ldiv32.o
# arm specific tests
tests =
diff --git a/lib/ldiv32.c b/lib/ldiv32.c
new file mode 100644
index 0000000..e9d434f
--- /dev/null
+++ b/lib/ldiv32.c
@@ -0,0 +1,105 @@
+#include <inttypes.h>
+
+extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *p_rem);
+extern int64_t __moddi3(int64_t num, int64_t den);
+extern int64_t __divdi3(int64_t num, int64_t den);
+extern uint64_t __udivdi3(uint64_t num, uint64_t den);
+extern uint64_t __umoddi3(uint64_t num, uint64_t den);
+
+uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *p_rem)
+{
+ uint64_t quot = 0;
+
+ /* Trigger a division by zero at run time (trick taken from iPXE). */
+ if (den == 0)
+ return 1/((unsigned)den);
+
+ if (num >= den) {
+ /* Align den to num to avoid wasting time on leftmost zero bits. */
+ int n = __builtin_clzll(den) - __builtin_clzll(num);
+ den <<= n;
+
+ do {
+ quot <<= 1;
+ if (num >= den) {
+ num -= den;
+ quot |= 1;
+ }
+ den >>= 1;
+ } while (n--);
+ }
+
+ if (p_rem)
+ *p_rem = num;
+
+ return quot;
+}
+
+int64_t __moddi3(int64_t num, int64_t den)
+{
+ uint64_t mask = num < 0 ? -1 : 0;
+
+ /* Compute absolute values and do an unsigned division. */
+ num = (num + mask) ^ mask;
+ if (den < 0)
+ den = -den;
+
+ /* Copy sign of num into result. */
+ return (__umoddi3(num, den) + mask) ^ mask;
+}
+
+int64_t __divdi3(int64_t num, int64_t den)
+{
+ uint64_t mask = (num ^ den) < 0 ? -1 : 0;
+
+ /* Compute absolute values and do an unsigned division. */
+ if (num < 0)
+ num = -num;
+ if (den < 0)
+ den = -den;
+
+ /* Copy sign of num^den into result. */
+ return (__udivdi3(num, den) + mask) ^ mask;
+}
+
+uint64_t __udivdi3(uint64_t num, uint64_t den)
+{
+ uint64_t rem;
+ return __udivmoddi4(num, den, &rem);
+}
+
+uint64_t __umoddi3(uint64_t num, uint64_t den)
+{
+ uint64_t rem;
+ __udivmoddi4(num, den, &rem);
+ return rem;
+}
+
+#ifdef TEST
+#include <assert.h>
+#define UTEST(a, b, q, r) assert(__udivdi3(a, b) == q && __umoddi3(a, b) == r)
+#define STEST(a, b, q, r) assert(__divdi3(a, b) == q && __moddi3(a, b) == r)
+int main()
+{
+ UTEST(1, 1, 1, 0);
+ UTEST(2, 2, 1, 0);
+ UTEST(5, 3, 1, 2);
+ UTEST(10, 3, 3, 1);
+ UTEST(120, 3, 40, 0);
+ UTEST(120, 1, 120, 0);
+ UTEST(0x7FFFFFFFFFFFFFFFULL, 17, 0x787878787878787, 8);
+ UTEST(0x7FFFFFFFFFFFFFFFULL, 0x787878787878787, 17, 8);
+ UTEST(0x8000000000000001ULL, 17, 0x787878787878787, 10);
+ UTEST(0x8000000000000001ULL, 0x787878787878787, 17, 10);
+ UTEST(0, 5, 0, 0);
+
+ STEST(0x7FFFFFFFFFFFFFFFULL, 17, 0x787878787878787, 8);
+ STEST(0x7FFFFFFFFFFFFFFFULL, -17, -0x787878787878787, 8);
+ STEST(-0x7FFFFFFFFFFFFFFFULL, 17, -0x787878787878787, -8);
+ STEST(-0x7FFFFFFFFFFFFFFFULL, -17, 0x787878787878787, -8);
+ STEST(33, 5, 6, 3);
+ STEST(33, -5, -6, 3);
+ STEST(-33, 5, -6, -3);
+ STEST(-33, -5, 6, -3);
+}
+#endif
diff --git a/x86/Makefile.i386 b/x86/Makefile.i386
index c04e5aa..960e274 100644
--- a/x86/Makefile.i386
+++ b/x86/Makefile.i386
@@ -3,7 +3,7 @@ bits = 32
ldarch = elf32-i386
COMMON_CFLAGS += -mno-sse -mno-sse2
-cflatobjs += lib/x86/setjmp32.o
+cflatobjs += lib/x86/setjmp32.o lib/ldiv32.o
tests = $(TEST_DIR)/taskswitch.flat $(TEST_DIR)/taskswitch2.flat \
$(TEST_DIR)/cmpxchg8b.flat $(TEST_DIR)/la57.flat