Linux'un bir "tadı" nda derlenen bir Linux çalıştırılabilir dosyası farklı bir sürümde çalışacak mı?


59

Linux'un bir tadı üzerinde derlenen, aşağıda gösterilenler gibi küçük, son derece basit bir programın çalıştırılabilirliği farklı bir tada mı sahip olacak? Yoksa yeniden derlenmesi gerekiyor mu?

Böyle bir durumda makine mimarisi önemli mi?

int main()
{
  return (99);
}

2
Üstün cevaplar için herkese teşekkürler! Beklediğimden çok daha fazla şey öğrendim. Kodu yapay olarak basit bir şekilde basitleştirdim, böylece olabildiğince az kütüphaneye bağlı olacaktı; ama bunu gerçekten açık olarak söylemeliydim. C ++ platformlarımda kodladığım kodların çoğu, Visual Studio gibi bir Microsoft aracıyla geliştirme ve ardından kodu bir * nix sistemine taşıma ve yeniden derleme işlemlerini içeriyordu.
JCDeen

4
Burada ifade edilen birçok yön ve düşünceler beni şaşırttı! Dürüst olmak gerekirse birçoğu cevap olarak seçebilmeyi diliyorum. Herkese tekrar teşekkürler! İçtenlikle.
JCDeen

2
Android ayrıca Linux tabanlı bir işletim sistemidir. Ancak, şansın en iyisi, glibcorada derlenen herhangi bir kodu çalıştırmanız ya da tam tersi. Verilmiş, tamamen imkansız değil .
Ocak’ta

2
Bir komut satırı aracının maksimum uyumluluğu için, glibc yerine uClibc, musl veya dietlibc kullanmak ve 32-bit çalıştırılabilirinizi ( gcc -m32 -static) statik olarak bağlamak isteyebilirsiniz . Bu şekilde, herhangi bir i386 veya amd64 Linux çalıştırılabilir dosyayı çalıştırabilir.
pts

10
42'ye geri dönmelisin ! :)
Homunculus Reticulli 31:18

Yanıtlar:


49

Değişir. IA-32 (Intel 32-bit) için derlenen bir şey amd64'te çalışabilir çünkü Linux on Intel, 32-bit uygulamalarla (uygun bir yazılım yüklüyken) geriye dönük uyumluluğu korur. İşte codeRedHat 7.3 32-bit sistemde derlenmiş (yaklaşık 2002, gcc versiyon 2.96) ve sonra binary bir Centos 7.4 64-bit sisteme (2017 yaklaşık) kopyalandı ve çalıştırıldı:

-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

Eski RedHat 7.3 - Centos 7.4 (aslında RedHat Enterprise Linux 7.4) aynı "dağıtım" ailesinde kalıyor, bu yüzden muhtemelen 2002'den 2018'deki bazı rasgele "Linux sıfırdan" yüklemelerine göre daha iyi bir taşınabilirliğe sahip olacak .

Amd64 için derlenen bir şey 32 bit sadece Linux sürümlerinde yayınlanmaz (eski donanım yeni donanım hakkında bir şey bilmiyor). Bu aynı zamanda eski eski şeylerde çalıştırılması amaçlanan modern sistemlerde derlenen yeni yazılımlar için de geçerlidir, çünkü kütüphaneler ve hatta sistem çağrıları geriye doğru taşınabilir olmayabilir, bu nedenle derleme hileleri gerektirebilir veya eski bir derleyici vb. eski sistemde derleme. (Bu, eski eski şeylerin sanal makinelerini etrafta tutmak için iyi bir nedendir.)

Mimarlık önemli; amd64 (veya IA-32), ARM veya MIPS'den büyük ölçüde farklıdır, bu nedenle bunlardan birinden birinin ikili olarak çalıştırılması beklenmez. Montaj düzeyinde mainIA-32 üzerinde kod bölümü aracılığıyla derler gcc -S code.ciçin

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

hangi bir amd64 sistemi (Linux sisteminde - OpenBSD amd64 üzerinde tersine başa çıkabilirim değil 32 bitlik ikililer destekler; eski archs ile geriye dönük uyumluluk saldırganlar odası, örneğin deniyordum veriyor CVE-2014-8866 ve arkadaşları). Bu arada büyük bir endian MIPS sisteminde main bunun yerine aşağıdakileri derler:

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

Hangi bir Intel işlemcisinin ne yapılacağı konusunda hiçbir fikri olmayacak ve aynı şekilde MIPS'deki Intel montajı için de.

Yabancı kodu çalıştırmak için muhtemelen QEMU veya başka bir emülatör kullanabilirsiniz (belki de çok yavaş).

Ancak! Kodunuz çok basit bir koddur, bu nedenle her şeyden daha az taşınabilirlik sorunu olacaktır; programlar genellikle zaman içinde değişen kütüphaneleri kullanır (glibc, openssl, ...); onlar için ayrıca çeşitli kütüphanelerin eski sürümlerini kurmaları gerekebilir (örneğin RedHat, genellikle bunun için paket adında bir yere "uygunluk" koyar)

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

veya muhtemelen glibc kullanan eski usuller için ABI değişiklikleri (Uygulama İkili Arayüzü) veya C ++ 11 veya diğer C ++ sürümleri nedeniyle daha yakın zamanda meydana gelen değişiklikler hakkında endişelenebilirsiniz. Biri aynı zamanda, bazı eski ikili dosyaların eski Linux dağıtımının dinamik olan her şeyi (RedHat: evet) derleyip derlememesine bağlı olmasına bağlı olarak, kütüphane sorunlarından kaçınmaya çalışmak için statik (derleyicideki disk büyüklüğünün artması) derlenebilir. Öte yandan, gibi şeyler diğer kitaplıkları kullanmak için patchelfdinamik (ELF, ancak muhtemelen a.outbiçimlendirmeyen) ikili olarak kabul edebilir.

Ancak! Bir programı çalıştırabilmek bir şeydir ve aslında onunla birlikte yararlı bir şeyler yapmaktır. Eski 32-bit Intel ikili dosyalarında, bazı korkunç ve desteklenmeyen bir güvenlik sorunu olan OpenSSL sürümüne bağlı olmaları durumunda güvenlik sorunları olabilir veya program, modern web sunucuları ile (örneğin, modern sunucular eski protokolleri ve eski programın şifrelerini reddeder), veya SSH protokolü sürüm 1 artık desteklenmiyor veya ...


14
Birinci paragrafta: Hayır, Intel buna "Intel 64" diyor (bugünlerde daha önce başka isimlerden geçtikten sonra). IA-64, x86 uyumlu bir şey değil, Itanium anlamına gelir.
Hobbs

1
@ hobbs, bu referansları amd64 ile değiştirdim; Şeylerin adlarını Intel pazarlama departmanına bırakacağım.
15

3
neden statik bağlantıdan bahsetmiyoruz?
30:18 '

2
Değişen sadece kütüphane ABI'leri değil - çekirdeğin çağrı arayüzü de zaman içinde uzar. Çıktısında for GNU/Linux 2.6.32(veya böyle) dikkat edin file /usr/bin/ls.
Charles Duffy

1
@Wilbert Thrig’in, Red Hat Enterprise Linux’tan farklı olan Red Hat Linux’a atıfta bulunduğunu unutmuşsunuzdur .
Bob,

68

Kısacası: Aynı (veya uyumlu) bir mimariyi kullanarak derlenmiş bir ikiliyi bir ana bilgisayardan diğerine alıyorsanız , onu başka bir dağıtım için mükemmel şekilde alabilirsiniz . Ancak, kodun karmaşıklığı arttıkça, yüklenmemiş bir kütüphaneye bağlanma olasılığı; başka bir yere kurulmuş; veya farklı bir sürümde yüklü, artar. Örneğin , bir (Debian kaynaklı) Ubuntu Linux ana bilgisayarında lddderlendiğinde aşağıdaki bağımlılıkları bildiren kodunuzu alarak gcc -o exit-test exit-test.c:

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

Açıkçası, bu ikili, Mac ( ./exit-test: cannot execute binary file: Exec format error) diyelim . Bunu bir RHEL kutusuna taşımayı deneyelim:

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

Ah hayatım. Bu neden olabilir?

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

Bu kullanım durumunda dahi, paylaşılan kütüphanelerin eksikliğinden ötürü forklifti kullanmak başarısız oldu.

Bununla birlikte, onu gcc -static exit-test-static exit-test.cderlersem, kütüphaneler olmadan sisteme taşımak gayet iyi çalışıyor. Elbette, disk alanı pahasına:

$ 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

Uygun başka bir çözüm, zorunlu kütüphaneleri yeni ana bilgisayara kurmak olacaktır.

U&L evrendeki birçok şeyde olduğu gibi, bu, ikisi yukarıda belirtilen birçok derisi olan bir kedidir.


4
Aslında, statik ikili dosyaları unuttum. Bazı satıcılar statik ikilileri benimsemek ve bazı zararlı yazılım yazarlar da Linux sürümleri arasında ikili uyumluluğu maksimize etmek aynı mimarinin
Rui F Ribeiro

8
Forklifting ...?
kullanıcı253751

2
@ immibis Verinin hedef ortam için tasarlanmadığı bir ortamdan (dağıtılabilir) veriyi (çalıştırılabilir) kopyalamak anlamına gelir.
Wjandrea

13
Linux örneğiniz maalesef yapaydır ve dağıtımlardan ziyade mimariler hakkındaki noktanızı gösterir: Debian'da 32-bit bir ikili oluşturdunuz ve 64-bit RHEL'de çalıştırmayı denediniz; bunlar farklı mimariler ... Çok az kütüphane bağımlılığına sahip aynı mimarlık ikilileri kopyalanabilir.
Stephen Kitt,

7
@ MSalters Mantıksız olduğunu söylemiyorum, DopeGhoti'nin yapmaya çalıştığı noktaya bakıldığında bunun kötü bir örnek olduğunu söylüyorum (ikili dosyaları bir dağıtımdan diğerine kopyalayamazsınız - ki bu yanlış). Tabii ki Intel'deki 64-bit Linux, uygun altyapıya sahip 32-bit yürütülebilir dosyaları da çalıştırmayı destekler. Bu durumda geçerli bir örnek IMO bir amd64ikili yapı oluşturup başka bir amd64dağıtımda çalıştırıyor ya da bir i386ikili yapı oluşturup başka bir i386dağıtımda çalıştırıyor olabilir .
Stephen Kitt,

25

Mükemmel @thrig ve @DopeGhoti cevaplarına ekleme: Linux dahil Unix veya Unix benzeri işletim sistemleri, kaynak kodun taşınabilirliği için ikili dosyalardan daha geleneksel olarak her zaman geleneksel olarak tasarlandı ve dizildi.

Hiçbir şey donanım özgü olan ya da örnekte olduğu gibi basit bir kaynak olma durumunda, size hiç hoş çok arasına herhangi bir sorun olmadan hareket edebilir , herhangi bir kaynak kodu olarak Linux sürümünü veya mimarlık sürece hedef sunucular yüklü C geliştirme paketlerini olduğu gibi , gerekli kütüphaneler ve buna karşılık gelen geliştirme kütüphaneleri kuruldu.

Zaman içinde uzak olan eski Linux sürümlerinden daha gelişmiş kodlar veya farklı çekirdek sürümleri için çekirdek modülleri gibi daha belirli programlar aktarırken, kullanımdan kaldırılmış kütüphaneleri / API'leri / ABI'leri hesaba katacak kaynak kodunu uyarlamanız ve değiştirmeniz gerekebilir.


19

By varsayılan , neredeyse kesinlikle harici kütüphaneleri sorun haline çalıştırmak gerekir. Diğer cevapların bazıları bu sorunlar hakkında daha fazla ayrıntıya giriyor, bu yüzden işlerini çoğaltmayacağım.

Sen edebilirsiniz Linux sistemleri arasında taşınabilir olması - hatta önemsiz olmayan olanları - Ancak birçok program derlemek. Anahtar, Linux Standart Bankası olarak adlandırılan araç takımıdır . LSB taşınabilir uygulamaların sadece bu tür oluşturmak için tasarlanmıştır. LSB v5.0 için bir uygulama derleyin ve LSB v5.0'ı uygulayan herhangi bir Linux ortamında (aynı mimaride) çalışacaktır. Birkaç Linux dağıtım LSB uyumludur ve diğerleri kurulabilir bir paket olarak LSB araç setleri / kütüphaneleri içerir. Eğer LSB araçlarını kullanarak uygulama oluşturmak durumunda (gibi lsbcciçin sarmalayıcı gcckütüphanelerin LSB sürümüne ve bağlantı), taşınabilir bir uygulama oluşturmak gerekir.


ve qemufarklı mimariler için derlenmiş programları bile çalıştırabilir (yüksek performans göstermezler, fakat onları çalıştırabilirsiniz)
Jasen

1
Linux Standard Base araç setinin farkında bile değildim, o yüzden teşekkür ederim! C / C ++ ile çok uzun zaman önce çalışmaya başladım, bu cevaplardaki bilgilerin çoğu benim için yeni. Ve çok yardımcı oldu.
JCDeen

1
Wikipedia makalesi, Debian ve Ubuntu'nun LSB'yi uygulamadığını söylüyor (ve bunu yapmaya niyeti yok.)
BlackJack

2
@ BlackJack- Dağıtımın kendisi% 100'ü çekirdek işletim sisteminin bir parçası olarak uygulamaz, ancak LSB uyumluluk kitaplıklarını ve araç setlerini isteğe bağlı paketler olarak yükleyebilirsiniz. Örneğin, Suse ve Centos’da çalışan LSB uyumlu programlar oluşturmak için Ubuntu’yu kullandım apt-get install.
bta

10

Olabilir.

Kırılma eğiliminde olan şeyler arasında.

  1. Farklı mimariler Açıkçası, tamamen farklı mimariler işe yaramaz (binfmt_misc ile kullanıcı modu qemu gibi bir şeyiniz olmadıkça, ancak bu normal bir yapılandırma değildir). x86 ikili dosyaları amd64 üzerinde çalışabilir, ancak yalnızca gerekli 32 bit kitaplıklar varsa.
  2. Kütüphane sürümleri Dönüşüm yanlışsa kütüphaneyi hiç bulamaz. Dönüştürme aynıysa, ancak ikili kitaplığın yayınlandığından daha yeni bir sürümüne karşı oluşturulduysa, yeni semboller veya sembollerin yeni sürümleri nedeniyle yüklenemedi. Özellikle glibc, sembol sürümünün ağır bir kullanıcısıdır, bu nedenle daha yeni bir glibc'e karşı oluşturulan ikili dosyaların eski bir glibc ile başarısız olma ihtimalleri çok yüksektir.

Hızla değişen kütüphaneleri kullanmaktan kaçınırsanız, mimari değişikliklerden kaçının ve hedeflemek istediğiniz en eski dağıtım üzerine inşa edin, birçok dağıtımda bir ikili çalışma yapma şansınız var.


4

Daha önce bahsedilen bazı şeylere ek olarak, yürütülebilir dosya biçiminde bazı değişiklikler olmuştur. Çoğu zaman, linux ELF kullanır, ancak daha eski sürümler a.out veya COFF kullanır.

Wikihole başlangıcı:

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

Eski sürümleri daha yeni biçimlerde çalıştırmak için bir yol olabilir, ancak ben şahsen hiç incelemedim.


"Eski" şu anda olsa çok eski.
plugwash
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.