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

时间:2017-03-15 23:52:02

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

相信我,我花了很长时间用谷歌搜索没有太多结果。

我正在编写一个非常基本的操作系统作为一个有趣的项目。出于显而易见的原因,它需要编译成一个独立的形式(在我的案例中是i686-elf)。但是我已经确定纯C对我来说还不够,而且我喜欢使用C ++。所以我写了一些代码,它似乎工作,所以我继续,突然间我仍然得到相同的错误,尽管代码没有明显的问题。

./sh/../obj/class_string.o:(.eh_frame+0x4f): undefined reference to __gxx_personality_v0' ./sh/../obj/kernel.o:(.eh_frame+0x13): undefined reference to __gxx_personality_v0' /home/natiiix/crosscompiler/out/path/bin/../lib/gcc/i686-elf/6.1.0/libgcc.a(unwind-dw2.o): In function read_encoded_value_with_base': /home/natiiix/crosscompiler/out/src/build-gcc/i686-elf/libgcc/../../../gcc-6.1.0/libgcc/unwind-pe.h:257: undefined reference to abort'

经过一段谷歌搜索后,我发现问题必定是我的g ++交叉编译器缺少c ++库,结果证明是真的。它确实只包含libgcc和libgcov。所以我发现我会以某种方式得到它们,但事实证明这是一项相当困难的任务。找到已编译的libstdc ++几乎是不可能的。所以我必须自己编译它,因为我对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一样接近)时,我停止了undefined reference to __gxx_personality_v0,但我仍然得到一些未定义的引用似乎是C函数。 (abort,strlen,malloc,free)

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

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

1 个答案:

答案 0 :(得分:0)

从您的帖子中不清楚您想要获得什么样的确切结果。以下几点可以帮助您找出真正的问题。

  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. 编译您的程序
  5. 如果您需要为特定CPU使用标准库优化,而不是使用通用i386,那么您需要手动构建它们。这不仅适用于libstdc ++,也适用于libc(IIRC,Ubuntu 16.04仍然使用通用-march=i386选项来构建libc,Ubuntu 16.10使用-march=i686)。
  6. 您从链接输出中获得了未定义的引用,因为您使用的是-nostdlib-lstdc++,而不是-lclibstdc++使用标准C库中的函数,因此您需要它。
  7. 在开发操作系统内核并且需要独立环境时,我认为您确实不需要标准库。在这种情况下,请参阅C ++标准,第17.6.1.3节,以查找可在应用程序中使用的标准头。您必须在编译器命令行上使用-lsupc++ -lgcc,如果使用异常处理,则需要-lgcc_eh(而libgcc_eh.a来自__gxx_personality_v0)。不要在独立环境中使用-lstdc++
  8. 希望这会有所帮助并祝你好运!