use*_*432 14 c++ linux gcc glibc linux-kernel
好吧,这只是一个有趣的练习,但是对于一些较旧的Linux系统来说编译程序不是太难,或者可以吗?
我可以访问几个运行linux的古老系统,也许看看它们在负载下的表现会很有趣.举个例子,我们想用Eigen做一些线性代数,这是一个很好的只有头的库.有没有机会在目标系统上编译它?
user@ancient:~ $ uname -a
Linux local 2.2.16 #5 Sat Jul 8 20:36:25 MEST 2000 i586 unknown
user@ancient:~ $ gcc --version
egcs-2.91.66
Run Code Online (Sandbox Code Playgroud)
也许不是......所以让我们在当前系统上编译它.以下是我的尝试,主要是失败的.更多的想法非常受欢迎.
编译 -m32 -march=i386
user@ancient:~ $ ./a.out
BUG IN DYNAMIC LINKER ld.so: dynamic-link.h: 53: elf_get_dynamic_info: Assertion `! "bad dynamic tag"' failed!
Run Code Online (Sandbox Code Playgroud)编译-m32 -march=i386 -static
:运行在所有相当新的内核版本上,但如果它们稍微更旧并且具有众所周知的错误消息则会失败
user@ancient:~ $ ./a.out
FATAL: kernel too old
Segmentation fault
Run Code Online (Sandbox Code Playgroud)
这是一个glibc
错误,它支持最小内核版本,例如我的系统上的内核2.6.4:
$ file a.out
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
statically linked, for GNU/Linux 2.6.4, not stripped
Run Code Online (Sandbox Code Playgroud)编译glibc
自己,支持最老的内核.这篇文章更详细地描述了它,但基本上就是这样
wget ftp://ftp.gnu.org/gnu/glibc/glibc-2.14.tar.bz2
tar -xjf glibc-2.14.tar.bz2
cd glibc-2.14
mkdir build; cd build
../configure --prefix=/usr/local/glibc_32 \
--enable-kernel=2.0.0 \
--with-cpu=i486 --host=i486-linux-gnu \
CC="gcc -m32 -march=i486" CXX="g++ -m32 -march=i486"
make -j 4
make intall
Run Code Online (Sandbox Code Playgroud)
不确定--with-cpu
和--host
选项是否做了什么,最重要的是强制使用编译器标志-m32 -march=i486
进行32位构建(不幸的-march=i386
是,在一段时间后出现错误)--enable-kernel=2.0.0
并使库与旧内核兼容.在configure
我收到警告的过程中
WARNING: minimum kernel version reset to 2.0.10
Run Code Online (Sandbox Code Playgroud)
我想这仍然是可以接受的.有关使用不同内核更改的内容列表,请参阅./sysdeps/unix/sysv/linux/kernel-features.h
.
好的,所以让我们链接新编译的glibc
库,稍微凌乱,但在这里:
$ export LIBC_PATH=/usr/local/glibc_32
$ export LIBC_FLAGS=-nostdlib -L${LIBC_PATH} \
${LIBC_PATH}/crt1.o ${LIBC_PATH}/crti.o \
-lm -lc -lgcc -lgcc_eh -lstdc++ -lc \
${LIBC_PATH}/crtn.o
$ g++ -m32 -static prog.o ${LIBC_FLAGS} -o prog
Run Code Online (Sandbox Code Playgroud)
由于我们正在进行静态编译,因此链接顺序很重要,可能需要一些试验和错误,但基本上我们会从gcc
链接器的选项中学习:
$ g++ -m32 -static -Wl,-v file.o
Run Code Online (Sandbox Code Playgroud)
请注意,crtbeginT.o
并且crtend.o
我也不需要为我的程序链接,因此我将它们排除在外.输出还包括一行--start-group -lgcc -lgcc_eh -lc --end-group
,表示库之间的相互依赖性,请参阅此文章.我刚刚-lc
在gcc
命令行中提到了两次,这也解决了相互依赖.
是的,努力工作得到了回报,现在我得到了
$ file ./prog
./prog: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
statically linked, for GNU/Linux 2.0.10, not stripped
Run Code Online (Sandbox Code Playgroud)
很棒我想,现在在旧系统上尝试:
user@ancient:~ $ ./prog
set_thread_area failed when setting up thread-local storage
Segmentation fault
Run Code Online (Sandbox Code Playgroud)
这再次是glibc
来自的错误消息./nptl/sysdeps/i386/tls.h
.我无法理解细节并放弃.
编译新系统g++ -c -m32 -march=i386
并链接旧系统.哇,这实际上适用于C和简单的C++程序(不使用C++对象),至少对于我测试过的少数几个.这并不太令人惊讶,因为我需要的libc
是printf
(也许是一些数学)接口没有改变但接口libstdc++
现在非常不同.
使用旧的linux系统和gcc版本2.95设置虚拟盒.然后编译gcc版本4.xx ...对不起,但现在太懒了...
???
找到了错误消息的原因:
user@ancient $ ./prog
set_thread_area failed when setting up thread-local storage
Segmentation fault
Run Code Online (Sandbox Code Playgroud)
这是因为glibc
系统调用一个仅自内核2.4.20起可用的函数.在某种程度上,glibc
当它至少需要内核2.4.20时,它可以被视为错误地声称与内核2.0.10兼容的错误.
细节:
./glibc-2.14/nptl/sysdeps/i386/tls.h
[...]
/* Install the TLS. */ \
asm volatile (TLS_LOAD_EBX \
"int $0x80\n\t" \
TLS_LOAD_EBX \
: "=a" (_result), "=m" (_segdescr.desc.entry_number) \
: "0" (__NR_set_thread_area), \
TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc)); \
[...]
_result == 0 ? NULL \
: "set_thread_area failed when setting up thread-local storage\n"; })
[...]
Run Code Online (Sandbox Code Playgroud)
这里的主要内容是,它调用汇编函数int 0x80
,它是对linux内核的系统调用,它根据值来决定做什么eax
,__NR_set_thread_area
在这种情况下设置为
并在
$ grep __NR_set_thread_area /usr/src/linux-2.4.20/include/asm-i386/unistd.h
#define __NR_set_thread_area 243
Run Code Online (Sandbox Code Playgroud)
但不是在任何早期的内核版本中.
所以好消息是"3.编译glibc --enable-kernel=2.0.0
"可能会产生可运行在所有Linux内核上的可执行文件> = 2.4.20.
使这项工作与旧内核的唯一机会是禁用tls
(线程本地存储),但是,这是不可能用glibc 2.14,尽管它提供的事实configure
选项.
无法在原始系统上编译它的原因可能与内核版本无关(它可以,但 2.2 通常还不够老,不足以成为大多数代码的绊脚石)。问题在于工具链很古老(至少是编译器)。但是,没有什么可以阻止您使用已安装的 G++ 构建更新版本egcs
。glibc
完成此操作后,您可能还会遇到问题,但您至少应该做到这一点。
你应该做的事情看起来像这样:
egcs
gcc
您刚刚构建的重建最新的 GCCld
使用新编译器构建最新的 binutils现在,您拥有一个构建良好的现代编译器和(大部分)工具链,可用于构建示例应用程序。如果运气不好,您可能还需要构建更新版本的glibc
,但这是您的问题 - 工具链 - 而不是内核。
归档时间: |
|
查看次数: |
5053 次 |
最近记录: |