2012-01-22 22 views
14

好的,这只是一个有趣的练习,但它不能太难编译某些较老的linux系统的程序,或者它可以吗?如何将c/C++应用程序移植到传统的linux内核版本

我可以访问几个运行linux的古代系统,也许看到它们如何在负载下执行会很有趣。举一个例子,我们想用Eigen来做一些线性代数,这是一个很好的标题库。有没有机会在目标系统上编译它?

[email protected]:~ $ uname -a 
Linux local 2.2.16 #5 Sat Jul 8 20:36:25 MEST 2000 i586 unknown 
[email protected]:~ $ gcc --version 
egcs-2.91.66 

也许不是......所以让我们在当前系统上编译它。以下是我的尝试,主要是失败的。任何更多的想法非常欢迎。

  1. 编译-m32 -march=i386

    [email protected]:~ $ ./a.out 
    BUG IN DYNAMIC LINKER ld.so: dynamic-link.h: 53: elf_get_dynamic_info: Assertion `! "bad dynamic tag"' failed! 
    
  2. 编译-m32 -march=i386 -static:运行在所有相当新的内核版本,但如果它们与众所周知的错误信息

    [email protected]:~ $ ./a.out 
    FATAL: kernel too old 
    Segmentation fault 
    

    这个年龄稍大的失败是一个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 
    
  3. 编译glibc自己与最古老的内核的支持。 This post介绍比较详细,但它本质上是这样的

    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 
    

    不知道,如果--with-cpu--host选择做什么,最重要的是要强制使用编译器标志-m32 -march=i486 32位构建(不幸的是-march=i386保释一段时间后出错)和--enable-kernel=2.0.0,以使库与旧版内核兼容。 Incidentially,在configure我得到了警告

    WARNING: minimum kernel version reset to 2.0.10 
    

    这仍然是可以接受的,我想。有关不同内核更改的列表,请参见./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 
    

    因为我们正在做一个静态编译的link order是重要的,可能需要一些试验和错误

    $ g++ -m32 -static -Wl,-v file.o 
    

    注意,crtbeginT.ocrtend.o也与一个我并不需要对M:,但基本上我们从哪些选项gcc给人以链接学习y节目,所以我把它们排除了。输出还包括一行,如--start-group -lgcc -lgcc_eh -lc --end-group,表示库之间的相互依赖关系,请参阅this post。我刚刚在gcc命令行中提到了两次-lc,这也解决了相互依赖问题。

    对,努力工作得到了回报,现在我得到

    $ file ./prog 
    ./prog: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), 
    statically linked, for GNU/Linux 2.0.10, not stripped 
    

    辉煌我想,现在尝试对旧体制:

    [email protected]:~ $ ./prog 
    set_thread_area failed when setting up thread-local storage 
    Segmentation fault 
    

    这又是一个glibc错误来自./nptl/sysdeps/i386/tls.h的消息。我不明白细节并放弃。

  4. 编译新系统g++ -c -m32 -march=i386并链接旧的。哇,这实际上适用于C和简单的C++程序(不使用C++对象),至少对于我测试过的少数人来说。这并不令人感到意外,因为我需要的所有libc都是printf(也许有些数学),其中接口没有改变,但现在libstdc++的接口非常不同。

  5. 用旧的linux系统和gcc版本2.95设置一个虚拟盒子。然后编译gcc版本4.x.x ...抱歉,但现在太懒了...

  6. ???

+0

编译?只有标题的模板库? – 2012-01-22 14:27:03

+0

编译使用此模板库的测试程序。这只是由于过时的gcc版本而不能在目标机器上编译的代码的一个例子。 – user1059432

+0

啊,好的。对不起,只是误解了。 – 2012-01-22 14:40:28

回答

3

的原因,你不能编译它原来的系统上可能没有什么用的内核版本做(这可能,但2.2还不是一般老不够,要成为大多数代码的绊脚石) 。问题是工具链是古老的(至少是编译器)。但是,没有任何东西阻止您使用已安装的egcs构建较新版本的G ++。一旦你完成了这个任务,你也可能遇到glibc的问题,但你至少应该得到那么多。

你应该做的会是这个样子:

  • 构建最新的GCC与egcs
  • 重建最新GCC与gcc你刚刚建立
  • 建立最新的binutils和ld与新的编译器

现在你有一个精心打造的现代编译器和(大部分)工具链,用它来构建你的示例ap折叠。如果运气不在您身边,您可能还需要构建更新版本的glibc,但是这个是您的问题 - 工具链 - 而不是内核。

8

已经找到了错误信息的原因:

[email protected] $ ./prog 
set_thread_area failed when setting up thread-local storage 
Segmentation fault 

这是因为glibc使一个系统调用的函数,而只是因为内核2.4.20可用。在某种程度上,它可以被看作是一个错误glibc,因为它错误地声称与内核2.0.10兼容,至少需要内核2.4.20。

细节:

./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"; }) 
[...] 

这里最主要的是,它调用汇编函数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 

,但没有定义任何早期版本的内核。

所以好消息是“3.编译glibc与--enable-kernel=2.0.0”可能会生成可执行文件,该文件可在所有Linux内核> = 2.4.20上运行。

使用旧版本内核的唯一机会是禁用tls(线程本地存储),但这对于glibc 2.14是不可能的,尽管事实上它是作为configure选项提供的。

相关问题