对“__divdi3”的未定义引用

Undefined reference to '__divdi3'

在 link 对 long long 类型的整数执行除法和模运算的一些代码时,我收到以下两个错误:

util.c:(.text+0x1af): undefined reference to '__divdi3'
util.c:(.text+0x1ef): undefined reference to '__moddi3'

我也尝试过使用 unsigned long long,但是会导致以下错误:

util.c:(.text+0x1af): undefined reference to '__udivdi3'
util.c:(.text+0x1ef): undefined reference to '__umoddi3'

long long 替换为 intlong 可以解决问题,但我需要使用 unsigned long long.

我正在使用以下命令行编译和 link 程序:

gcc -ffreestanding -c kernel/util.c -o kernel/util.o
ld -o kernel32.bin -Ttext 0x500 kernel/util.o kernel/kernel.o --oformat binary

这是函数:

char* itoa(unsigned long long i, char b[]){
    if (i == 0){
        b[0] = '0';
        b[1] = '[=14=]';
        return b;
    }
    char const digit[] = "0123456789";
    char* p = b;
    if (i < 0){
        *p++ = '-';
        i *= -1;
    }
    unsigned long long shifter = i;
    while (shifter){
        ++p;
        shifter = shifter / 10;
    }
    *p = '[=14=]';
    while (i){
        *--p = digit[i % 10];
        i = i / 10;
    }
    return b;
}

显然,编译器正在引用 __udivdi3 来除以整数,但 linker 找不到它..

顺便说一下,二进制文件是作为32位操作系统使用的,因此缺少很多标准库

编辑:我正在使用 gcc 4.8.4 和 ld 2.24

据此link:https://gcc.gnu.org/onlinedocs/gcc-3.3/gccint/Library-Calls.html

感兴趣的函数在 libgcc.a 库中定义。 (不在 libgcc.so 图书馆中。)

如果您的 link 步骤包含 -static 参数,我认为您的代码将使用 libgcc.a 库

然而,这个link:https://sourceware.org/ml/crossgcc/2006-04/msg00000.html

有以下要说的:

通常您 link 使用 gcc 而不是 ld 来避免这些类型的问题。

我会使用 gcc 将其更改为 link,或者添加适当的 -L 和 -l 选项以使其使用适当的 libgcc

看来你用错了功能:

— 运行时函数:long __divdi3 (long a, long b)

我猜正确的函数是:

— 运行时函数:long long __divti3 (long long a, long long b)

(https://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines)

很遗憾,我不确定是否在您的 gcc 版本中实现了。

当为不为 GCC 用作 [unsigned] long long 的数据类型提供硬件支持的体系结构构建代码时,GCC 生成代码以对该类型的值进行算术运算,其中涉及调用其自己的支持库 libgcc 提供的函数。 __divdi3() 等就在其中。这不是 GCC 可以做到的唯一方式,但它非常适合 GCC 支持多种体系结构的目标。

当被指示充当独立编译器时,GCC 不会自动 link libgcc,因此不会自动提供这些功能的实现。这一直是之前投诉的主题,例如this one and this later one。 GCC 维护者的立场是这不是 GCC 缺陷,它不会渲染 GCC non-conforming。我发现他们的推理有问题,但不太可能改变。至少,这是实施质量问题。

我确实知道 GCC 维护者来自哪里,但是:一个独立的环境提供了标准库的 none,除了根据提供给它的代码外,不能解释大多数函数调用。那么,如果该代码包含对与 libgcc 中某些函数同名的函数的显式调用怎么办?除非用户明确表示他需要 libgcc,否则编译器不应该假定它是需要的函数的那些版本。但问题是,如果 编译器 插入这样的调用,那么它不仅知道预期的实现是什么,而且如果不兼容的实现是 link,结果也是错误的代替编辑。因此,这是GCC自己造成的问题。

最重要的是,您可以明确请求 linked libgcc。您需要指定它是静态 linked,因为您不能在上下文中依赖动态 linker。这些额外的 link 选项应该可以做到:

-static-libgcc -lgcc

或者,您可以自己编写这些函数的实现,或者抄袭 GCC 的源代码,但我不明白您为什么更喜欢这些选项中的任何一个。