diff mbox series

[kvm-unit-tests] libcflat: provide long division routines

Message ID 20210505131412.654238-1-pbonzini@redhat.com (mailing list archive)
State New, archived
Headers show
Series [kvm-unit-tests] libcflat: provide long division routines | expand

Commit Message

Paolo Bonzini May 5, 2021, 1:14 p.m. UTC
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@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 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

Comments

Paolo Bonzini May 5, 2021, 1:16 p.m. UTC | #1
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@google.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

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
>
Bill Wendling May 5, 2021, 7:46 p.m. UTC | #2
On Wed, May 5, 2021 at 6:16 AM Paolo Bonzini <pbonzini@redhat.com> 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@google.com>
> > Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>
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
> >
>
diff mbox series

Patch

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