On Wed, May 5, 2021 at 6:16 AM Paolo Bonzini <pbonzini@xxxxxxxxxx> wrote: > > 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> > Thanks, Paolo! -bw > 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 > > >