要するに:同じ (または互換性のある) アーキテクチャを使用して、コンパイル済みのバイナリをあるホストから別のホストに移動する場合 、別のディストリビューションに持ち込んでもまったく問題ないかもしれません .ただし、コードの複雑さが増すにつれて、インストールされていないライブラリに対してリンクされる可能性が高くなります。別の場所にインストールされています。または別のバージョンでインストールすると、増加します。たとえば、 ldd
のコードを取り上げます gcc -o exit-test exit-test.c
でコンパイルすると、次の依存関係が報告されます (Debian 派生) Ubuntu Linux ホスト上:
$ ldd exit-test
linux-gate.so.1 => (0xb7748000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb757b000)
/lib/ld-linux.so.2 (0x8005a000)
明らかに、このバイナリは、たとえば Mac (./exit-test: cannot execute binary file: Exec format error
) に移動すると実行されません。 )。 RHEL ボックスに移動してみましょう:
$ ./exit-test
-bash: ./exit-test: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
まあ。これはなぜでしょうか?
$ ls /lib/ld-l* # reference the `ldd` output above
ls: cannot access /lib/ld-l*: No such file or directory
このユースケースでも、共有ライブラリが見つからないため、フォークリフトは失敗しました。
ただし、 gcc -static exit-test-static exit-test.c
でコンパイルすると 、ライブラリなしでシステムに移植すると問題なく動作します。もちろん、ディスク容量が犠牲になります:
$ ls -l ./exit-test{,-static}
-rwxr-xr-x 1 username groupname 7312 Jan 29 14:18 ./exit-test
-rwxr-xr-x 1 username groupname 728228 Jan 29 14:27 ./exit-test-static
別の実行可能な解決策は、必要なライブラリを新しいホストにインストールすることです。
U&L ユニバースの多くのものと同様に、これは多くのスキンを持つ猫であり、そのうちの 2 つが上記で概説されています。
場合によります。 IA-32 (Intel 32 ビット) 用にコンパイルされたものは、Intel 上の Linux が 32 ビット アプリケーション (適切なソフトウェアがインストールされている場合) との下位互換性を保持しているため、amd64 で実行できます。これがあなたの code
です RedHat 7.3 32 ビット システム (2002 年頃、gcc バージョン 2.96) でコンパイルし、バイナリを Centos 7.4 64 ビット システム (2017 年頃) にコピーして実行:
-bash-4.2$ file code
code: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.2.5, not stripped
-bash-4.2$ ./code
-bash: ./code: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
-bash-4.2$ sudo yum -y install glibc.i686
...
-bash-4.2$ ./code ; echo $?
99
古代の RedHat 7.3 から Centos 7.4 (本質的には RedHat Enterprise Linux 7.4) は同じ「ディストリビューション」ファミリにとどまっているため、2002 年のランダムな「Linux からのゼロからの」インストールから 2018 年の他のランダムな Linux ディストリビューションに移行するよりも移植性が高くなる可能性があります。 .
amd64 用にコンパイルされたものは、Linux の 32 ビットのみのリリースでは動作しません (古いハードウェアは新しいハードウェアを認識しません)。これは、古代の古いもので実行することを目的とした最新のシステムでコンパイルされた新しいソフトウェアにも当てはまります。ライブラリやシステムコールでさえ後方移植性がない可能性があるため、コンパイルのトリック、または古いコンパイラの取得などが必要になる場合があるため、または代わりに可能性があるためです。古いシステムでコンパイルします。 (これは、古代の古いものの仮想マシンを保持する正当な理由です。)
アーキテクチャは重要です。 amd64 (または IA-32) は ARM や MIPS とは大きく異なるため、いずれかのバイナリが別のバージョンで実行されることは想定されていません。アセンブリ レベルでは main
IA-32 のコードのセクションは gcc -S code.c
経由でコンパイルされます へ
main:
pushl %ebp
movl %esp,%ebp
movl $99,%eax
popl %ebp
ret
これは amd64 システムで処理できます (Linux システムでは -- OpenBSD では対照的に amd64 では 処理しません 32 ビット バイナリをサポートします。古いアーチとの後方互換性は、攻撃者に小刻みに動く余地を与えます。 CVE-2014-8866 など)。一方、ビッグエンディアンの MIPS システム main
では 代わりに次のようにコンパイルします:
main:
.frame $fp,8,$31
.mask 0x40000000,-4
.fmask 0x00000000,0
.set noreorder
.set nomacro
addiu $sp,$sp,-8
sw $fp,4($sp)
move $fp,$sp
li $2,99
move $sp,$fp
lw $fp,4($sp)
addiu $sp,$sp,8
j $31
nop
これは、Intel プロセッサが何をすべきかわからないものであり、MIPS 上の Intel アセンブリについても同様です。
QEMU やその他のエミュレーターを使用して外部コードを実行することもできます (おそらく非常にゆっくりと)。
でも!あなたのコードは非常に単純なコードなので、他の何よりも移植性の問題が少なくなります。プログラムは通常、時間の経過とともに変更されたライブラリ (glibc、openssl など) を利用します。それらの場合、さまざまなライブラリの古いバージョンをインストールする必要がある場合もあります (たとえば、RedHat は通常、そのようなパッケージ名のどこかに「compat」を入れます)
compat-glibc.x86_64 1:2.12-4.el7.centos
または、glibc を使用する古いものに対する ABI の変更 (アプリケーション バイナリ インターフェイス) や、C++11 やその他の C++ リリースによる最近の変更について心配することもできます。ライブラリの問題を回避するために静的にコンパイルする (ディスク上のバイナリ サイズを大幅に増やす) こともできますが、一部の古いバイナリがこれを行ったかどうかは、古い Linux ディストリビューションがほとんどすべてを動的にコンパイルしていたかどうか (RedHat:はい) によって異なります。一方、 patchelf
のようなもの 動的にリジガーできます (ELF、しかしおそらく a.out
ではありません) 形式) バイナリを他のライブラリを使用します。
でも!プログラムを実行できることと、実際にそのプログラムで何か役に立つことを行うことは別のことです。古い 32 ビット Intel バイナリは、OpenSSL のバージョンに依存している場合、セキュリティ上の問題が発生する可能性があります。このバージョンには、バックポートされていない恐ろしいセキュリティ問題が含まれているか、プログラムが最新の Web サーバーとまったくネゴシエートできない可能性があります (最新のサーバーが古いプロトコルと古いプログラムの暗号を拒否する)、または SSH プロトコル バージョン 1 がサポートされなくなった、または ...
@thrig と @DopeGhoti の優れた回答に加えて、Linux を含む Unix または Unix ライクな OS は、伝統的に常にバイナリよりもソース コードの移植性を重視して設計および調整されてきました。
あなたの例のようにハードウェア固有のものがないか、単純なソースである場合は、ほとんど any の間から問題なく移動できます。 ソース コードとしての Linux またはアーキテクチャのバージョン 宛先サーバーに C 開発パッケージがインストールされている 、必要なライブラリ、および対応する開発ライブラリがインストールされています。
遠い古いバージョンの Linux からより高度なコードを移植したり、異なるカーネル バージョンのカーネル モジュールなどのより具体的なプログラムを移植したりする場合、非推奨のライブラリ/API/ABI を考慮してソース コードを適応および変更する必要がある場合があります。