Apakah Linux yang dapat dieksekusi dikompilasi pada satu "rasa" Linux berjalan pada yang berbeda?

59

Apakah program kecil, sangat sederhana yang dapat dieksekusi, seperti yang ditunjukkan di bawah ini, yang dikompilasi pada satu rasa Linux berjalan pada rasa yang berbeda? Atau apakah perlu dikompilasi ulang?

Apakah arsitektur mesin penting dalam kasus seperti ini?

int main()
{
  return (99);
}
JCDeen
sumber
2
Terima kasih untuk semua orang atas jawaban yang luar biasa! Saya belajar lebih dari yang saya perkirakan. Saya sengaja membuat kode secara sengaja sehingga akan tergantung pada sesedikit mungkin perpustakaan; tapi aku benar-benar harus menyatakan itu di muka. Sebagian besar coding C ++ saya di seluruh platform melibatkan pengembangan dengan alat Microsoft seperti Visual Studio & kemudian porting kode ke sistem * nix dan kompilasi ulang.
JCDeen
4
Banyak aspek & pertimbangan yang diungkapkan di sini telah membuat saya takjub! Jujur saya berharap saya bisa memilih beberapa sebagai jawaban. Sekali lagi terima kasih untuk semuanya! Hormat kami.
JCDeen
2
Android juga merupakan sistem operasi berbasis Linux. Best of luck, bagaimanapun, menjalankan kode yang dikompilasi di glibcsana, atau sebaliknya. Memang, itu tidak sepenuhnya mustahil .
Undercat
2
Untuk kompatibilitas maksimum dari alat baris perintah, Anda mungkin ingin menggunakan uClibc, musl atau dietlibc sebagai ganti glibc, dan secara statis menautkan 32-bit Anda yang dapat dieksekusi ( gcc -m32 -static). Dengan melakukan hal itu, Linux i386 atau amd64 apa pun dapat menjalankan executable.
Poin
10
Anda harus mengembalikan 42 ! :)
Homunculus Reticulli

Jawaban:

49

Tergantung. Sesuatu yang dikompilasi untuk IA-32 (Intel 32-bit) dapat berjalan pada amd64 karena Linux pada Intel mempertahankan kompatibilitas mundur dengan aplikasi 32-bit (dengan perangkat lunak yang sesuai diinstal). Ini adalah codekompilasi Anda pada sistem RedHat 7.3 32-bit (sekitar 2002, gcc versi 2.96) dan kemudian biner disalin ke dan dijalankan pada sistem Centos 7.4 64-bit (sekitar 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 Kuno 7,3 hingga Centos 7.4 (pada dasarnya RedHat Enterprise Linux 7.4) tetap dalam keluarga "distribusi" yang sama, sehingga kemungkinan akan memiliki portabilitas yang lebih baik daripada menginstal dari beberapa "Linux dari awal" instal dari 2002 ke beberapa distribusi Linux acak lainnya pada 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 mundur portabel, sehingga mungkin memerlukan trik kompilasi, atau mendapatkan kompiler lama dan sebagainya, atau mungkin sebaliknya kompilasi pada sistem lama. (Ini adalah alasan yang baik untuk menjaga mesin virtual dari barang-barang tua kuno di sekitar.)

Arsitektur memang penting; amd64 (atau IA-32) sangat berbeda dari ARM atau MIPS sehingga biner dari salah satu dari mereka tidak akan diharapkan untuk dijalankan pada yang lain. Pada tingkat perakitan, mainbagian kode Anda pada IA-32 mengkompilasi melalui gcc -S code.cke

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

dimana sistem amd64 dapat menangani (pada sistem Linux - OpenBSD sebaliknya pada amd64 tidak mendukung binari 32-bit; kompatibilitas ke belakang dengan lengkungan lama memang memberi ruang gerak penyerang ruang gerak, misalnya CVE-2014-8866 dan teman-teman). Sementara itu pada sistem MIPS big-endian main bukannya 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

dimana prosesor Intel tidak akan tahu harus melakukan apa, dan juga untuk perakitan Intel pada 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 akan memiliki masalah portabilitas lebih sedikit daripada yang lain; program biasanya menggunakan perpustakaan yang telah berubah dari waktu ke waktu (glibc, openssl, ...); untuk yang satu 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 yang lebih baru karena C ++ 11 atau rilis C ++ lainnya. Kita juga dapat mengkompilasi statis (sangat meningkatkan ukuran biner pada disk) untuk mencoba menghindari masalah pustaka, meskipun apakah beberapa biner lama melakukan ini tergantung pada apakah distribusi Linux lama mengkompilasi sebagian besar semuanya dinamis (RedHat: ya) atau tidak. Di sisi lain, hal-hal seperti patchelfdapat rejigger dinamis (ELF, tetapi mungkin tidak a.outmemformat) biner untuk menggunakan perpustakaan lain.

Namun! Mampu menjalankan suatu program adalah satu hal, dan benar-benar melakukan sesuatu yang bermanfaat dengannya. Binari Intel 32-bit yang 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 yang modern server menolak protokol dan sandi lama dari program lama), atau protokol SSH versi 1 tidak lagi didukung, atau ...

thrig
sumber
14
kembali paragraf pertama: tidak, Intel menyebutnya "Intel 64" (hari ini, setelah melalui beberapa nama lain sebelumnya). IA-64 mengacu pada Itanium, bukan apa pun yang kompatibel dengan x86.
hobbs
1
@ hobbs terima kasih, saya telah mengganti referensi tersebut dengan amd64; Saya akan menyerahkan penamaan barang ke departemen pemasaran Intel.
Thrig
3
mengapa tidak menyebutkan tautan statis?
bekerja
2
Bukan hanya pustaka ABI yang berubah - antarmuka syscall kernel juga akan diperpanjang dari waktu ke waktu. Catat for GNU/Linux 2.6.32(atau semacamnya) di output dari file /usr/bin/ls.
Charles Duffy
1
@ Willbert Anda mungkin kehilangan bahwa thrig merujuk ke Red Hat Linux yang berbeda dari Red Hat Enterprise Linux.
Bob
67

Singkatnya: Jika Anda membawa biner yang dikompilasi dari satu host ke host lain menggunakan arsitektur yang sama (atau yang kompatibel) , Anda mungkin akan membawanya ke distribusi lain . Namun seiring meningkatnya kompleksitas kode, kemungkinan tertaut dengan pustaka yang tidak diinstal; dipasang di lokasi lain; atau diinstal pada versi yang berbeda, meningkat. Misalnya, mengambil kode Anda, yang lddmelaporkan dependensi berikut ketika dikompilasi dengan gcc -o exit-test exit-test.chost 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 menendang ke, katakanlah, Mac ( ./exit-test: cannot execute binary file: Exec format error). Mari kita coba memindahkannya ke kotak RHEL:

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

Oh sayang. Kenapa 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, forklifting gagal karena tidak ada perpustakaan bersama.

Namun, jika saya mengompilasinya gcc -static exit-test-static exit-test.c, porting ke sistem tanpa pustaka 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 dengan menginstal pustaka yang diperlukan pada host baru.

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

DopeGhoti
sumber
4
Memang, saya lupa tentang binari statis. Beberapa vendor mengadopsi binari statis, dan beberapa pembuat malware juga untuk memaksimalkan kompatibilitas biner antara versi Linux dengan arsitektur yang sama
Rui F Ribeiro
8
Forklifting ...?
user253751
2
@immibis Saya pikir itu berarti menyalin data (yang dapat dieksekusi) dari satu lingkungan (distro) ke yang lain, di mana data tidak dirancang untuk lingkungan tujuan.
wjandrea
13
Contoh Linux Anda agak artifisial, dan mengilustrasikan poin Anda tentang arsitektur daripada distribusi: Anda membuat biner 32-bit pada Debian dan mencoba menjalankannya di RHEL 64-bit; itu adalah arsitektur yang berbeda ... Binari dengan arsitektur yang sama dengan sedikit ketergantungan perpustakaan dapat disalin dengan baik.
Stephen Kitt
7
@ MSalters Saya tidak mengatakan itu tidak masuk akal, saya mengatakan itu adalah contoh yang buruk mengingat titik DopeGhoti sedang mencoba untuk membuat (Anda tidak dapat menyalin binari dari satu distribusi ke yang lain - yang salah). Tentu saja Linux 64-bit pada Intel mendukung menjalankan executable 32-bit juga, dengan infrastruktur yang sesuai. Contoh yang valid dalam hal ini IMO akan membangun amd64biner dan menjalankannya pada amd64distribusi lain , atau membangun i386biner dan menjalankannya pada i386distribusi lain .
Stephen Kitt
25

Menambahkan ke jawaban @thrig dan @DopeGhoti yang sangat baik: OS Unix atau Unix-like, termasuk Linux, secara tradisional selalu dirancang dan diselaraskan lebih untuk portabilitas kode sumber daripada binari.

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

Sejauh porting kode lebih lanjut dari versi lama Linux dalam waktu yang lama, atau program yang lebih spesifik seperti modul kernel untuk versi kernel yang berbeda, Anda mungkin harus menyesuaikan dan memodifikasi kode sumber ke akun untuk pustaka / API / ABI yang sudah usang.

Rui F Ribeiro
sumber
19

Secara default , Anda hampir pasti akan mengalami masalah dengan perpustakaan eksternal. Beberapa jawaban lain menjelaskan lebih detail tentang masalah-masalah itu, jadi saya tidak akan menduplikasi pekerjaan mereka.

Anda dapat , bagaimanapun, mengkompilasi banyak program - bahkan yang non-sepele - menjadi portabel di antara sistem Linux. Kuncinya adalah toolkit yang disebut Basis Standar Linux . The LSB dirancang untuk menciptakan hanya jenis aplikasi portabel. Kompilasi aplikasi untuk LSB v5.0 dan itu akan berjalan di lingkungan Linux lainnya (dengan arsitektur yang sama) yang mengimplementasikan LSB v5.0. Beberapa distro Linux sesuai dengan LSB, dan yang lain menyertakan LSB toolkit / pustaka sebagai paket yang dapat diinstal. Jika Anda membuat aplikasi menggunakan alat LSB (seperti lsbccpembungkus untuk gcc) dan menautkan ke perpustakaan versi LSB, Anda akan membuat aplikasi portabel.

bta
sumber
dan dengan qemuAnda bahkan dapat menjalankan program yang dikompilasi untuk arsitektur yang berbeda, (tidak berkinerja tinggi, tetapi Anda dapat menjalankannya)
Jasen
1
Saya bahkan tidak mengetahui toolkit Basis Standar Linux, jadi terima kasih! Saya mulai bekerja dengan C / C ++ sejak lama, begitu banyak info dalam jawaban ini baru bagi saya. Dan sangat membantu.
JCDeen
1
Artikel Wikipedia mengatakan Debian dan Ubuntu tidak menerapkan LSB (dan tidak punya niat untuk melakukannya.)
BlackJack
2
@ BlackJack- Distro itu sendiri tidak mengimplementasikan 100% dari itu sebagai bagian dari OS inti, tetapi Anda dapat menginstal perpustakaan dan toolkit kompatibilitas LSB sebagai paket opsional. Saya telah menggunakan Ubuntu (misalnya) untuk membangun program yang kompatibel dengan LSB yang kemudian dijalankan pada Suse dan Centos, Anda hanya perlu apt-get installbeberapa paket.
bta
10

Mungkin.

Hal-hal yang cenderung merusaknya termasuk.

  1. Arsitektur yang berbeda. Jelas sekali arsitektur yang benar-benar berbeda tidak akan berfungsi (kecuali jika Anda memiliki sesuatu seperti mode pengguna qemu dengan binfmt_misc tetapi itu bukan konfigurasi yang normal). binari x86 dapat bekerja pada amd64 tetapi hanya jika pustaka 32-bit yang diperlukan tersedia.
  2. Versi perpustakaan. Jika pencarian salah, maka perpustakaan tidak akan menemukan sama sekali. Jika soversionnya sama tetapi biner dibangun melawan versi pustaka yang lebih baru daripada yang ditentang maka mungkin gagal memuat karena simbol baru atau versi baru simbol. Secara khusus glibc adalah pengguna yang berat versi simbol, jadi biner dibangun melawan glibc yang lebih baru sangat mungkin gagal dengan glibc yang lebih tua.

Jika Anda menghindari menggunakan perpustakaan yang cepat berubah, hindari perubahan arsitektur dan bangun di distro tertua yang ingin Anda targetkan. Anda memiliki peluang bagus untuk membuat satu karya biner di banyak distro.

plugwash
sumber
4

Selain beberapa hal yang disebutkan sebelumnya, ada beberapa perubahan dalam format file yang dapat dieksekusi. Untuk sebagian besar, linux menggunakan ELF, tetapi versi yang lebih lama menggunakan a.out atau COFF.

Awal dari wikihole:

https://en.wikipedia.org/wiki/Comparison_of_executable_file_formats

Mungkin ada cara untuk mendapatkan versi yang lebih lama untuk menjalankan format yang lebih baru, tetapi saya pribadi tidak pernah melihatnya.

Ben
sumber
"lebih tua" pada saat ini sudah sangat tua sekarang.
plugwash