GNU/Linux >> Belajar Linux >  >> Linux

Akankah executable Linux yang dikompilasi pada satu rasa Linux berjalan pada rasa yang berbeda?

Singkatnya:Jika Anda mengambil biner terkompilasi dari satu host ke host lain menggunakan arsitektur yang sama (atau kompatibel) , Anda mungkin baik-baik saja membawanya ke distribusi lain . Namun seiring meningkatnya kompleksitas kode, kemungkinan ditautkan ke perpustakaan yang tidak diinstal; dipasang di lokasi lain; atau diinstal pada versi yang berbeda, meningkat. Ambil contoh kode Anda, yang mana ldd melaporkan dependensi berikut saat dikompilasi dengan gcc -o exit-test exit-test.c pada host Linux Ubuntu (berasal dari Debian):

$ 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)

Jelas biner ini tidak akan berjalan jika saya menendangnya ke, katakanlah, Mac (./exit-test: cannot execute binary file: Exec format error ). Mari coba pindahkan ke kotak RHEL:

$ ./exit-test
-bash: ./exit-test: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory

Aduh Buyung. Mengapa ini bisa terjadi?

$ ls /lib/ld-l* # reference the `ldd` output above
ls: cannot access /lib/ld-l*: No such file or directory

Bahkan untuk kasus penggunaan ini, memforkliftnya gagal karena perpustakaan bersama tidak ada.

Namun, jika saya mengkompilasinya dengan gcc -static exit-test-static exit-test.c , memindahkannya ke sistem tanpa perpustakaan berfungsi dengan baik. Dengan mengorbankan, tentu saja, ruang disk:

$ 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

Solusi lain yang layak adalah menginstal pustaka yang diperlukan di host baru.

Seperti banyak hal di alam semesta U&L, ini adalah kucing dengan banyak kulit, dua di antaranya diuraikan di atas.


Tergantung. Sesuatu yang dikompilasi untuk IA-32 (Intel 32-bit) dapat berjalan di amd64 karena Linux di Intel mempertahankan kompatibilitas mundur dengan aplikasi 32-bit (dengan perangkat lunak yang sesuai terpasang). Ini code Anda dikompilasi pada sistem RedHat 7.3 32-bit (sekitar tahun 2002, gcc versi 2.96) dan kemudian biner disalin ke dan dijalankan pada sistem Centos 7.4 64-bit (sekitar tahun 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 kuno hingga Centos 7.4 (pada dasarnya RedHat Enterprise Linux 7.4) tetap berada dalam keluarga "distribusi" yang sama, jadi kemungkinan akan memiliki portabilitas yang lebih baik daripada beralih dari beberapa instalasi acak "Linux dari awal" dari tahun 2002 ke beberapa distribusi Linux acak lainnya pada tahun 2018 .

Sesuatu yang dikompilasi untuk amd64 tidak akan berjalan pada rilis Linux 32-bit saja (perangkat keras lama tidak tahu tentang perangkat keras baru). Ini juga berlaku untuk perangkat lunak baru yang dikompilasi pada sistem modern yang dimaksudkan untuk dijalankan pada hal-hal lama kuno, karena perpustakaan dan bahkan panggilan sistem mungkin tidak portabel mundur, jadi mungkin memerlukan trik kompilasi, atau mendapatkan kompiler lama dan sebagainya, atau mungkin sebagai gantinya kompilasi pada sistem lama. (Ini adalah alasan yang bagus untuk menjaga mesin virtual dari hal-hal lama kuno.)

Arsitektur memang penting; amd64 (atau IA-32) sangat berbeda dari ARM atau MIPS sehingga biner dari salah satunya tidak diharapkan berjalan di yang lain. Pada tingkat rakitan, main bagian kode Anda pada kompilasi IA-32 melalui gcc -S code.c untuk

main:
    pushl %ebp
    movl %esp,%ebp
    movl $99,%eax
    popl %ebp
    ret

yang dapat ditangani oleh sistem amd64 (pada sistem Linux--OpenBSD sebaliknya pada amd64 tidak mendukung binari 32-bit; kompatibilitas mundur dengan lengkungan lama memang memberikan ruang gerak bagi penyerang, mis. CVE-2014-8866 dan teman-teman). Sedangkan pada sistem MIPS big-endian main alih-alih mengkompilasi ke:

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

yang mana prosesor Intel tidak tahu apa yang harus dilakukan, dan juga untuk perakitan Intel di MIPS.

Anda mungkin dapat menggunakan QEMU atau emulator lain untuk menjalankan kode asing (mungkin sangat, sangat lambat).

Namun! Kode Anda adalah kode yang sangat sederhana, sehingga memiliki lebih sedikit masalah portabilitas daripada yang lainnya; program biasanya menggunakan pustaka yang telah berubah seiring waktu (glibc, openssl, ...); untuk itu orang mungkin juga perlu menginstal versi lama dari berbagai pustaka (RedHat misalnya biasanya menempatkan "compat" di suatu tempat dalam nama paket untuk itu)

compat-glibc.x86_64                     1:2.12-4.el7.centos

atau mungkin khawatir tentang perubahan ABI (Application Binary Interface) untuk hal-hal lama yang menggunakan glibc, atau perubahan terbaru karena C++11 atau rilis C++ lainnya. Seseorang juga dapat mengkompilasi statis (sangat meningkatkan ukuran biner pada disk) untuk mencoba menghindari masalah perpustakaan, meskipun apakah beberapa biner lama melakukan ini tergantung pada apakah distribusi Linux lama mengkompilasi hampir semua yang dinamis (RedHat:ya) atau tidak. Sebaliknya, hal-hal seperti patchelf dapat rejigger dinamis (ELF, tapi mungkin bukan a.out format) biner untuk menggunakan perpustakaan lain.

Namun! Mampu menjalankan program adalah satu hal, dan benar-benar melakukan sesuatu yang bermanfaat dengannya adalah hal lain. Biner Intel 32-bit lama mungkin memiliki masalah keamanan jika mereka bergantung pada versi OpenSSL yang memiliki beberapa masalah keamanan yang mengerikan dan tidak di-backport di dalamnya, atau program mungkin tidak dapat bernegosiasi sama sekali dengan server web modern (seperti modern server menolak protokol dan cipher lama dari program lama), atau protokol SSH versi 1 tidak lagi didukung, atau ...


Menambahkan ke jawaban @thrig dan @DopeGhoti yang luar biasa:Unix atau OS mirip Unix, termasuk Linux, secara tradisional selalu dirancang dan lebih diselaraskan untuk portabilitas kode sumber daripada biner.

Jika tidak memiliki perangkat keras khusus atau menjadi sumber sederhana seperti pada contoh Anda, Anda dapat memindahkannya tanpa masalah sama sekali dari antara apa saja versi Linux atau arsitektur sebagai kode sumber selama server tujuan menginstal paket pengembangan C , pustaka yang diperlukan, dan pustaka pengembangan terkait yang terpasang.

Sejauh mem-porting lebih banyak kode lanjutan dari versi Linux yang lebih lama dalam waktu lama, atau program yang lebih spesifik seperti modul kernel untuk versi kernel yang berbeda, Anda mungkin harus mengadaptasi dan memodifikasi kode sumber untuk memperhitungkan pustaka/API/ABI yang tidak digunakan lagi.


Linux
  1. Perintah Linux Sederhana yang Akan Memberitahu Saya Apa Itu Display Manager?

  2. Linux – Bagaimana Menguji Apakah Biner Linux Dikompilasi Sebagai Kode Independen Posisi?

  3. Linux – Apakah Kernel Linux/unix yang Berbeda Dapat Dipertukarkan?

  1. Bagaimana cara menjalankan program dengan direktori kerja yang berbeda dari saat ini, dari shell Linux?

  2. Apakah ada perbedaan antara file biner yang dapat dieksekusi antara distribusi?

  3. Menyematkan ikon di executable Linux

  1. Bagaimana cara membongkar, memodifikasi, dan kemudian memasang kembali executable Linux?

  2. Bagaimana cara membongkar biner yang dapat dieksekusi di Linux untuk mendapatkan kode perakitan?

  3. Gunakan versi PHP CLI yang berbeda yang dapat dieksekusi untuk satu perintah