【解决过程】
之前遇到过几次了,都是类似的原因导致此问题的。后来才了解,其根本原因:
嵌入式中,32位系统中(目前多数系统都是,比如ARM的片子),对于普通的a除以b(b为32位):
(1)当a为32位,Linux 内核中,常用uint32_t 类型,可以直接写为 a/b
(2)但是,对于a是64位,uint64_t的时候,就要用到专门的除操作相关的函数,linux内核里面一般为
do_div(n, base),注意,
此处do_div得到的结果是余数
,
而真正的a/b的结果,是用a来保存的
。
do_div(n,base)的具体定义,和当前体系结构有关,对于arm平台,在
arch/arm/include\asm\div64.h
其实现很复杂,感兴趣的自己去代码里看吧,这里不多说了。
因此,如果你当前写代码,a/b,如果a是uint64_t类型,那么一定要利用do_div(a,b),而得到结果a,
而不能简单的用a/b,否则编译可以正常编译,但是最后链接最后出错,会提示上面的那个错误:
undefined reference to "__udivdi3"
【解决方法】
知道原因,就好办了。办法就是,去你代码里面找到对应的用到除法的地方,即类似于a/b的地方,其中被除数a为64位,Linux中一般用用uint64_t,将a/b用do_div(a,b)得到的a去代替(注意,不是直接用do_div()得到真正a除b后的结果,因为do_div(a,b)得到的是余数,囧。。。),即可,而具体写其他,就显得很麻烦。此处,我们可以借鉴Linux中\fs\yaffs2\yaffs_fs.c中的宏:
static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
{
uint64_t result = partition_size;
do_div(result, block_size);
return (uint32_t)result;
}
来自己也去封装一个支持64位数的除法的函数,不过,Linux内核就是好,早已经帮我们实现了对应的64位的unsingned和signed两个函数:
static inline u64 div_u64(u64 dividend, u32 divisor);
static inline s64 div_s64(s64 dividend, s32 divisor);
我们可以直接拿过来用了,注意用此函数时,要包含对应头文件:
#include <linux/math64.h>
总结一下就是:
1.先包含头文件:
2.然后用(a,b)得到a/b的结果即可。
如果需要在进行64位除数的时候,同时得到余数remainder,可以直接用
static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder);
static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
1.
- 64 bit division in linux
If you've encountered an error message like this
Unknown symbol __udivdi3Unknown symbol __umoddi3Unresolved symbol __udivdi3Unresolved symbol __umoddi3
you most likely want to make a 64 bit division, which is not supported by default in linux kernel space.
To solve this problem, you need to use the do_div macro available in asm/div64.h:
#include <asm/div64.h>unsigned long long x, y, result;unsigned long mod;mod = do_div(x, y);result = x;
If you want to calculate x / y with do_div(x, y),
the result of the division is in x, the remainder is returned from the do_div function
.
Since do_div is just an asm (assembler) macro, it doesn't break real time determinism, so it's also suitable for use in RTAI classic, RTAI fusion and ADEOS/ADEOS-IPIPE applications.
(转载注:这篇文章对于我有很大的帮助,只看了一半就把目前手上的
内核
线程的问题
解决
了,而这个问题之前并没有找到合适的
解决
方法
)
原文地址:http://yijunzhu.diandian.com/?tag=%E5%86%85%E6%A0%B8
编译
Linux
下面的代码,经常会遇到这种错误:
undefined
reference
to
`
__
udivdi
3
'
【
解决
过程】
...
undefined
reference
to
`
__modsi
3
'和
`
__
udivdi
3
'问题的分析
与
解决
办法
嵌入式开发交流群280
3
52802,欢迎加入!
【编译器版本】
arm
-
linux
-
gcc
3
.4.1
【问题描述】
在做嵌入式底层开发时(基于ARM编译无OS的程序),编写整数转字符串
函数
,用到了求余操作%和除数操作,部分代码如下:
while(num)
deno...
[ 17.940000] qca_ol:
Unknown
symbol
__
udivdi
3
(err 0)
insmod: can't insert '/lib/modules/qca_ol.ko':
unknown
symbol
in module, or
unknown
parameter
这个错误导致qca_ol.ko无法
pwm_dev = rt_device_find(PWM_DEV_NAME);
if (!pwm_dev) {
rt_kprintf("PWM device not found\n");
return;
/* 打开设备 */
if (rt_device_open(pwm_dev, RT_DEVICE_FLAG_RDWR) != RT_EOK) {
rt_kprintf("Open device failed\n");
return;
/* 配置通道1(PE9) */
rt_pwm_set(pwm_dev, CHANNEL1, 1000000, 500000); // 周期1ms, 占空比50%
rt_pwm_enable(pwm_dev, CHANNEL1); // 启用输出
/* 配置通道2(PE11) */
rt_pwm_set(pwm_dev, CHANNEL2, 2000000, 1500000); // 周期2ms, 占空比75%
rt_pwm_enable(pwm_dev, CHANNEL2); // 启用输出
while(1)
__WEAK void SystemClock_Config(void)
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regula
to
r output voltage
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULA
TO
R_VOLTAGE_SCALE1);
/** Initializes the RCC Oscilla
to
rs according
to
the specified parameters
* in the RCC_OscInitTypeDef structure.
RCC_OscInitStruct.Oscilla
to
rType = RCC_OSCILLA
TO
RTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_
DIV
2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
Error_Handler();
/** Initializes the CPU, AHB and APB buses clocks
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLK
Div
ider = RCC_SYSCLK_
DIV
1;
RCC_ClkInitStruct.APB1CLK
Div
ider = RCC_HCLK_
DIV
4;
RCC_ClkInitStruct.APB2CLK
Div
ider = RCC_HCLK_
DIV
2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
Error_Handler();
但是报错:
linking...
./rt
-
thread/src/components.o: In function
`
main_thread_entry&#
3
9;:
F:\Code_Test\keil_test\car\brain\Debug/../rt
-
thread/src/components.c:198:
undefined
reference
to
`
main&#
3
9;
collect2.exe: error: ld returned 1 exit status
make: *** [makefile:85: rtthread.elf] Error 1
"make
-
j12 all" terminated with exit code 2. Build might be incomplete.
报错如下:
通过参考博客:http://blog.chinaunix.net/uid
-
20717979
-
id
-
3
3
51
3
60.html 后发现是数据类型问题,但是作者提供的思路没有
解决
,于是去lib/printfmt.c文件中做类型强转换后运行成功
printnum(putch, putdat, num / base, base, width
-
1, padc);
printnum(putch, putdat, (uint
3
2_t)num / (uint
3
2_t)base, bas