c++ - 为 i686-elf 交叉编译和链接 libstdc++(在 Ubuntu 16.04 上使用 g++)

标签 c++ linux linker g++ libstdc++

请相信我,我已经花了很多时间在谷歌上搜索,但没有得到太多结果。

我正在编写一个非常基本的操作系统作为一个有趣的项目。出于明显的原因,它需要编译成独立的形式(在我的例子中是 i686-elf)。然而,我认为纯 C 对我来说还不够,我更愿意使用 C++。所以我写了一些代码,它似乎可以工作,所以我继续,尽管代码没有明显问题,但突然间我不断收到同样的错误。

./sh/../obj/class_string.o:(.eh_frame+0x4f): 未定义对 __gxx_personality_v0 的引用 ./sh/../obj/kernel.o:(.eh_frame+0x13): 未定义对 __gxx_personality_v0 的引用 /home/natiiix/crosscompiler/out/path/bin/../lib/gcc/i686-elf/6.1.0/libgcc.a(unwind-dw2.o): 在函数 read_encoded_value_with_base': /home/natiiix/crosscompiler/out/src/build-gcc/i686-elf/libgcc/../../../gcc-6.1.0/libgcc/unwind-pe.h:257: 未定义的中止引用'

经过一些谷歌搜索后,我发现问题一定是我的 g++ 交叉编译器缺少 c++ 库,事实证明这是真的。它确实只包含 libgcc 和 libgcov。所以我想我会以某种方式得到它们,但事实证明这是一项非常困难的任务。几乎不可能找到已编译的 libstdc++.a。所以我不得不自己编译它,因为我对 makefile 不是特别熟悉,所以肯定不容易弄清楚。

最后我找到了一个 bash 脚本,它在某种程度上允许我做我需要的事情。它下载 gcc 6.1.0、binutils、配置两者并运行 make、make install。如果它真的有效,那就太好了。至少据我所知,编译器本身就像一个魅力,但无论我做什么,库都不会工作,至少我怀疑,出于某种原因,它是为不同的目标平台构建的。看来 libstdc++ 根本无法为 i686-elf 或类似的东西构建。

gccbuild.sh:

#!/bin/bash

set -e

if [ "$#" -ne 1 ]; then
  echo "Supply one parameter: the target to use!!"
  exit 1
fi

sudo apt install libgmp3-dev libmpfr-dev libisl-dev libcloog-isl-dev libmpc-dev texinfo -y

cd "$(dirname "$0")"

rm -rfv out/
mkdir out/
cd out/

rm -rfv path/
mkdir path/
rm -rfv src/
mkdir src/
cd src/

wget ftp://ftp.gnu.org/gnu/binutils/binutils-2.26.tar.gz
wget ftp://ftp.gnu.org/gnu/gcc/gcc-6.1.0/gcc-6.1.0.tar.gz

tar -xvzf binutils-2.26.tar.gz
tar -xvzf gcc-6.1.0.tar.gz

export PREFIX="$(pwd)/../path/"
export TARGET=$1
export PATH="$PREFIX/bin:$PATH"

rm -rfv build-binutils/
mkdir build-binutils/
cd build-binutils/
../binutils-2.26/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --disable-werror
make
make install

cd ..

rm -rfv build-gcc/
mkdir build-gcc/
cd build-gcc/

../gcc-6.1.0/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers

make all-gcc
make all-target-libgcc

make install-gcc
make install-target-libgcc

../gcc-6.1.0/libstdc++-v3/configure --host=$TARGET --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --disable-libstdcxx-threads

make
make install

我的编译/链接脚本(以便您可以看到 g++ 参数):

${BASH_SOURCE%/*}/../../crosscompiler/out/path/bin/i686-elf-g++ -c ${BASH_SOURCE%/*}/../src/*.cpp --std=c++11 -ffreestanding -O2 -Wall -Wextra
echo moving object files from active directory to obj/

mv *.o ${BASH_SOURCE%/*}/../obj/

${BASH_SOURCE%/*}/../../crosscompiler/out/path/bin/i686-elf-g++ -T ${BASH_SOURCE%/*}/../src/linker.ld -o ${BASH_SOURCE%/*}/../bin/kokos.bin -ffreestanding -O2 -nostdlib ${BASH_SOURCE%/*}/../obj/*.o -lgcc -lstdc++ -lsupc++

当我尝试链接这些库(libstdc++ 和 libsupc++ 的版本似乎是 elf32-i386,它们与 i686-elf 一样接近)时,我不再得到 对 __gxx_personality_v0 的 undefined reference ,但我仍然得到一些 undefined reference ,这些引用似乎是 C 函数。 (中止、strlen、malloc、释放)

整个问题可以通过不使用模板、类析构函数和一些更特定于 c++ 的东西来避免(具有讽刺意味的是,类本身在大多数情况下似乎工作得很好),但对我来说这似乎不是一个很好的解决方案.我宁愿接触到这些东西。

有人可以向我解释我做错了什么吗?

最佳答案

从您的帖子中不清楚您想要获得的确切结果。以下是一些可以帮助您找出真正问题所在的观察结果。

  1. 首先,如果您需要在您的(我猜)64 位 Ubuntu 主机上编译 32 位代码,您不需要交叉工具链,只需使用 -m32 编译即可。
  2. 如果您希望您的代码针对特定 CPU 变体进行优化,只需使用适当的 -march=-mcpu=-mtune= 选项。
  3. 如果您需要将您的 32 位程序与 C++ 库静态链接,那么在 Ubuntu 上您只需安装一个软件包 libstdc++-6-dev:i386。运行 sudo apt-get install libstdc++-6-dev:i386,它还会安装所有必要的依赖项。然后用 gcc -m32 -static 编译你的程序。
  4. 如果您需要为特定 CPU 使用优化标准库,而不是为通用 i386 使用标准库,那么您需要手动构建它们。这不仅适用于 libstdc++,也适用于 libc(IIRC,Ubuntu 16.04 仍然使用通用的 -march=i386 选项来构建 libc,Ubuntu 16.10 使用 -march=i686 ).
  5. 您从链接输出中获得了 undefined reference ,因为您使用的是 -nostdlib-lstdc++ 而不是 -lclibstdc++ 使用了标准 C 库中的函数,所以你需要它。
  6. 当您开发操作系统内核并需要独立环境时,我想您确实不需要标准库。在这种情况下,请参阅 C++ 标准第 17.6.1.3 条,以查找您可以在应用程序中使用的标准头文件。您必须在编译器命令行上使用 -lsupc++ -lgcc,如果您使用异常处理(和 libgcc_eh.a,则还需要 -lgcc_eh__gxx_personality_v0 的来源)。不要在独立环境中使用-lstdc++!

希望这对您有所帮助,祝您好运!

关于c++ - 为 i686-elf 交叉编译和链接 libstdc++(在 Ubuntu 16.04 上使用 g++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42822885/

相关文章:

c++ - 链接 lib 时未解析的外部符号,编译器将字母 'A' 添加到函数名称

c++ - 链接到命名空间中的函数时出现 GNU 链接器错误

sql - 如何将变量从shell脚本传递到sql文件

c - 链接器在节中添加额外的填充?

c++ - CMake:如何从并行目录链接库

c++ - 如何创建可变参数模板字符串格式化程序

linux - 在 ssh 命令中使用远程服务器的环境变量

c++ - Linux C++ LibUSB 在 USB HUB 中写入寄存器

c++ - 无法创建 .txt 文件并用 C++ 写入它?

c++ - 是否有一个库可以从数据包的 winpcap 原始数据中获取 IP 地址和端口?