Undefined reference to '_ modsi3' and' _ udivdi3' Problem Analysis and Solution

Source: Internet
Author: User

Undefined reference to '_ modsi3' and' _ udivdi3' Analysis and Solution

Embedded Development Exchange Group 280352802, welcome to join!

[Compiler version] arm-Linux-GCC 3.4.1 [Problem description]

When developing the embedded underlying layer (compiling a program without OS based on ARM), write integer-to-string functions and use the remainder operation % and divisor operations. Some code is as follows:

...while(num){denom = num % radix;num /= radix;*ptr++ = denom + '0';if((num < radix) && num){*ptr++ = num + '0';*ptr = '\0';break;}}...

Some makefiles are as follows:

....c.o:$(CC) -static -nostartfiles -nostdlib -fno-builtin $(CPPFLAGS) $(CFLAGS) -c $<...

Error:

Undefined reference to '_ umodsi3'

Undefined reference to '_ udivdi3'

[Problem Analysis]

Arm is a simplified instruction set and basically does not support remainder and Division operations. Therefore, we should avoid the above operations as much as possible. The libgcc library contains these operations. This error does not contain the GCC support library libgcc. A, and the library file is missing.

[Solution]

1. Specify to connect to the GCC library during connection,-lgcc

-Lgcc indicates that the linker will connect to the GCC support library libgcc.. -LM indicates that the linker will connect to the standard library libm of GCC. a,-LC indicates that the linker will connect to the Standard C library libc of GCC. a. if all three of them are required, the connection order is-lm-LC-lgcc.

2. Self-implemented library functions for response

If you do not want to use library functions, you can refer to the Linux kernel source code Linux/ARCH/ARM/lib/lib1funcs. s implements these two library functions, lib1funcs. s implements division and modulo operations. The specific source code is as follows:

/* * linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines * * Author: Nicolas Pitre <nico@cam.org> *   - contributed to gcc-3.4 on Sep 30, 2003 *   - adapted for the Linux kernel on Oct 2, 2003 *//* Copyright 1995, 1996, 1998, 1999, 2000, 2003 Free Software Foundation, Inc.This file is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 2, or (at your option) anylater version.In addition to the permissions in the GNU General Public License, theFree Software Foundation gives you unlimited permission to link thecompiled version of this file into combinations with other programs,and to distribute those combinations without any restriction comingfrom the use of this file.  (The General Public License restrictionsdo apply in other respects; for example, they cover modification ofthe file, and distribution when not linked into a combineexecutable.)This file is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNUGeneral Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; see the file COPYING.  If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA.  *//*#include <linux/linkage.h>#include <asm/assembler.h>*/#define ALIGN.align 4,0x90#define __LINUX_ARM_ARCH__  1#define ENTRY(name) \  .globl name; \  ALIGN; \  name:.macro ARM_DIV_BODY dividend, divisor, result, curbit#if __LINUX_ARM_ARCH__ >= 5clz\curbit, \divisorclz\result, \dividendsub\result, \curbit, \resultmov\curbit, #1mov\divisor, \divisor, lsl \resultmov\curbit, \curbit, lsl \resultmov\result, #0#else@ Initially shift the divisor left 3 bits if possible,@ set curbit accordingly.  This allows for curbit to be located@ at the left end of each 4 bit nibbles in the division loop@ to save one loop in most cases.tst\divisor, #0xe0000000moveq\divisor, \divisor, lsl #3moveq\curbit, #8movne\curbit, #1@ Unless the divisor is very big, shift it up in multiples of@ four bits, since this is the amount of unwinding in the main@ division loop.  Continue shifting until the divisor is @ larger than the dividend.1:cmp\divisor, #0x10000000cmplo\divisor, \dividendmovlo\divisor, \divisor, lsl #4movlo\curbit, \curbit, lsl #4blo1b@ For very big divisors, we must shift it a bit at a time, or@ we will be in danger of overflowing.1:cmp\divisor, #0x80000000cmplo\divisor, \dividendmovlo\divisor, \divisor, lsl #1movlo\curbit, \curbit, lsl #1blo1bmov\result, #0#endif@ Division loop1:cmp\dividend, \divisorsubhs\dividend, \dividend, \divisororrhs\result,   \result,   \curbitcmp\dividend, \divisor,  lsr #1subhs\dividend, \dividend, \divisor, lsr #1orrhs\result,   \result,   \curbit,  lsr #1cmp\dividend, \divisor,  lsr #2subhs\dividend, \dividend, \divisor, lsr #2orrhs\result,   \result,   \curbit,  lsr #2cmp\dividend, \divisor,  lsr #3subhs\dividend, \dividend, \divisor, lsr #3orrhs\result,   \result,   \curbit,  lsr #3cmp\dividend, #0@ Early termination?movnes\curbit,   \curbit,  lsr #4@ No, any more bits to do?movne\divisor,  \divisor, lsr #4bne1b.endm.macro ARM_DIV2_ORDER divisor, order#if __LINUX_ARM_ARCH__ >= 5clz\order, \divisorrsb\order, \order, #31#elsecmp\divisor, #(1 << 16)movhs\divisor, \divisor, lsr #16movhs\order, #16movlo\order, #0cmp\divisor, #(1 << 8)movhs\divisor, \divisor, lsr #8addhs\order, \order, #8cmp\divisor, #(1 << 4)movhs\divisor, \divisor, lsr #4addhs\order, \order, #4cmp\divisor, #(1 << 2)addhi\order, \order, #3addls\order, \order, \divisor, lsr #1#endif.endm.macro ARM_MOD_BODY dividend, divisor, order, spare#if __LINUX_ARM_ARCH__ >= 5clz\order, \divisorclz\spare, \dividendsub\order, \order, \sparemov\divisor, \divisor, lsl \order#elsemov\order, #0@ Unless the divisor is very big, shift it up in multiples of@ four bits, since this is the amount of unwinding in the main@ division loop.  Continue shifting until the divisor is @ larger than the dividend.1:cmp\divisor, #0x10000000cmplo\divisor, \dividendmovlo\divisor, \divisor, lsl #4addlo\order, \order, #4blo1b@ For very big divisors, we must shift it a bit at a time, or@ we will be in danger of overflowing.1:cmp\divisor, #0x80000000cmplo\divisor, \dividendmovlo\divisor, \divisor, lsl #1addlo\order, \order, #1blo1b#endif@ Perform all needed substractions to keep only the reminder.@ Do comparisons in batch of 4 first.subs\order, \order, #3@ yes, 3 is intended hereblt2f1:cmp\dividend, \divisorsubhs\dividend, \dividend, \divisorcmp\dividend, \divisor,  lsr #1subhs\dividend, \dividend, \divisor, lsr #1cmp\dividend, \divisor,  lsr #2subhs\dividend, \dividend, \divisor, lsr #2cmp\dividend, \divisor,  lsr #3subhs\dividend, \dividend, \divisor, lsr #3cmp\dividend, #1mov\divisor, \divisor, lsr #4subges\order, \order, #4bge1btst\order, #3teqne\dividend, #0beq5f@ Either 1, 2 or 3 comparison/substractions are left.2:cmn\order, #2blt4fbeq3fcmp\dividend, \divisorsubhs\dividend, \dividend, \divisormov\divisor,  \divisor,  lsr #13:cmp\dividend, \divisorsubhs\dividend, \dividend, \divisormov\divisor,  \divisor,  lsr #14:cmp\dividend, \divisorsubhs\dividend, \dividend, \divisor5:.endmENTRY(__udivsi3)subsr2, r1, #1moveqpc, lrbccLdiv0cmpr0, r1bls11ftstr1, r2beq12fARM_DIV_BODY r0, r1, r2, r3movr0, r2movpc, lr11:moveqr0, #1movner0, #0movpc, lr12:ARM_DIV2_ORDER r1, r2movr0, r0, lsr r2movpc, lrENTRY(__umodsi3)subsr2, r1, #1@ compare divisor with 1bccLdiv0cmpner0, r1@ compare dividend with divisormoveq   r0, #0tsthir1, r2@ see if divisor is power of 2andeqr0, r0, r2movlspc, lrARM_MOD_BODY r0, r1, r2, r3movpc, lrENTRY(__divsi3)cmpr1, #0eorip, r0, r1@ save the sign of the result.beqLdiv0rsbmir1, r1, #0@ loops below use unsigned.subsr2, r1, #1@ division by 1 or -1 ?beq10fmovsr3, r0rsbmir3, r0, #0@ positive dividend valuecmpr3, r1bls11ftstr1, r2@ divisor is power of 2 ?beq12fARM_DIV_BODY r3, r1, r0, r2cmpip, #0rsbmir0, r0, #0movpc, lr10:teqip, r0@ same sign ?rsbmir0, r0, #0movpc, lr11:movlor0, #0moveqr0, ip, asr #31orreqr0, r0, #1movpc, lr12:ARM_DIV2_ORDER r1, r2cmpip, #0movr0, r3, lsr r2rsbmir0, r0, #0movpc, lrENTRY(__modsi3)cmpr1, #0beqLdiv0rsbmir1, r1, #0@ loops below use unsigned.movsip, r0@ preserve sign of dividendrsbmir0, r0, #0@ if negative make positivesubsr2, r1, #1@ compare divisor with 1cmpner0, r1@ compare dividend with divisormoveqr0, #0tsthir1, r2@ see if divisor is power of 2andeqr0, r0, r2bls10fARM_MOD_BODY r0, r1, r2, r310:cmpip, #0rsbmir0, r0, #0movpc, lrLdiv0:strlr, [sp, #-4]!/*bl__div0*/movr0, #0@ About as wrong as it could be.ldrpc, [sp], #4
[Similar problem -- 64-bit division in arm]

In 32-bit embedded systems (most systems are currently, such as arm films), for general a divided by B (B is 32-bit ):
(1) When a is a 32-bit Linux kernel, The uint32_t type is commonly used and can be directly written as a/B
(2) However, when a is 64-bit and uint64_t is used, a special function related to operations should be used. In the Linux kernel, do_div (n, base) is usually used. Note, here, the result of do_div is the remainder, and the real result of A/B is saved by. The specific definition of do_div (n, base) is related to the current architecture. For the ARM platform, in ARCH/ARM/include/ASM/div64.h and Linux/ARCH/ARM/lib/div64.s, the implementation of arch/ARM/ASM/div64.s is very complicated. Therefore, if you write code A/B and A is of the uint64_t type, you must use do_div (a, B) to obtain result, instead, you cannot simply use a/B. Otherwise, the compilation can be normal, but the final link error will prompt the above error: Undefined reference to "_ udivdi3 ".

It's easy to know the reason. The solution is to find the corresponding Division used in your code, that is, a/B, where the devisor A is 64-bit. in Linux, uint64_t is generally used, replace A/B with a obtained by do_div (A, B) (Note: instead of using do_div () directly, because do_div (a, B) gets the remainder .) You can.

The Linux kernel has already helped us implement the corresponding 64-bit unsingned and signed functions:

static inline u64 div_u64(u64 dividend, u32 divisor);static inline s64 div_s64(s64 dividend, s32 divisor);

We can use it directly. When using this function, we need to include the corresponding header file:
# Include <Linux/math64.h>
If you need to obtain the remainder during the 64-bit divisor, you can directly use the following in # include <Linux/math64.h>:

static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder);static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.