2012-01-22 13 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 -static-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. コンパイルとコンパイル:すべてのかなり最近のバージョンのカーネルで動作しますが、彼らはよく知られているエラーメッセージ

    と少し古い場合失敗し
    [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最も重要なのは、32ビットは(残念ながら-march=i386ベイルを構築-m32 -march=i486用コンパイラフラグの使用を強制することです、より詳細にそれを説明したが、本質的にそれは--with-cpu--hostオプションは何をすればわからないこの

    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 
    

    のようになりますしばらくするとエラーが出る)と--enable-kernel=2.0.0を使用して、古いカーネルと互換性のあるライブラリにします。 Incidentially、configure時に私はまだ許容可能である警告

    WARNING: minimum kernel version reset to 2.0.10 
    

    を持って、私は考えます。異なるカーネルで変更されるもののリストについては、./sysdeps/unix/sysv/linux/kernel-features.hを参照してください。新しくコンパイルglibcライブラリに対する

    オクラホマので、聞かせてのリンク、少し汚いが、ここでは行く:

    私たちは、静的コンパイルをやっているlink orderが重要であるともいくつかの試行錯誤が必要になる場合がありますので
    $ 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 
    

    しかし、基本的に我々はオプションgccがリンカに与えるものから学ぶ:私は男のための必要はありませんでしたcrtbeginT.ocrtend.oもリンクされて、それに対して

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

    注意を、私はそれらを放棄した。出力には、ライブラリ間の依存関係を示す--start-group -lgcc -lgcc_eh -lc --end-groupのような行も含まれます(this postを参照)。私はちょうど-lcgccコマンドラインで2回言いました。これも相互依存関係を解決します。

    右、私は今、古いシステム上でそれを試してみてください、と思ったハードワークが報われたと今、私はブリリアント

    $ 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++オブジェクトを使用しない)で動作します。これはあまりにも驚くべきことではありませんから、libcprintf(そして多分いくつかの数学)ですが、そのインターフェイスは変更されていませんが、libstdc++へのインターフェイスは非常に異なっています。

  5. 古いLinuxシステムとgccバージョン2.95の仮想ボックスをセットアップします。 gccバージョン4.x.xをコンパイルしてください...残念ですが、その時点ではあまりにも怠惰です...

  6. ???

+0

コンパイル?ヘッダーのみのテンプレートライブラリですか? –

+0

このテンプレートライブラリを使用するテストプログラムをコンパイルします。これは、古いgccバージョンのためにターゲットマシンでコンパイルされないコードの単なる例です。 – user1059432

+0

ああ、大丈夫です。申し訳ありませんが、誤解しました。 –

答えて

3

理由あなたは元のシステム上でそれをコンパイルすることはできませんがおそらくカーネルのバージョンとは何の関係もありません(それができたのが、それはほとんどのコードのためのつまずきであることを十分にするために2.2は、一般的に古いではありません) 。問題は、ツールチェックが古くからあることです(コンパイラは少なくとも)。しかし、インストールされているegcsでG ++の新しいバージョンをビルドすることを止めるものはありません。また、完了したらglibcで問題が発生する可能性がありますが、少なくとも遠くにする必要があります。あなたは何をすべき

は、次のようなものになります。egcs

    • 最新のGCCを構築するgccあなただけ
    • 内蔵した最新のGCCは、あなたの新しいコンパイラ
    • と最新のbinutilsと ldを構築再構築

    サンプルアプリケーションをビルドするための最新のコンパイラと(ほとんどの)ツールチェーンがあります襞付け。運があなたの側になければ、glibcの新しいバージョンを作る必要があるかもしれませんが、このはあなたの問題です - ツールチェイン - カーネルではありません。 glibcは、カーネル2.4.20以降でのみ使用できます関数にシステムコールを行うためです

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

  • 8

    てきたが、エラーメッセージの理由を発見しました。ある意味、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"; }) 
    [...] 
    

    ここでの主なものであり、それが設定されている、eaxの値に基づいて、どのように処理するかを決定Linuxカーネルへのシステムコールであるアセンブリ関数を呼び出すint 0x80この場合、__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(スレッドローカルストレージ)を無効にするだろうようにする唯一のチャンスはなく、それがconfigureオプションとして提供されるという事実にもかかわらず、glibcの2.14では不可能です。

    関連する問題