gcc, belirli bir CPU'nun '' komut seti '' anlamına gelen '' mimari '' terimlerini kullanır ve "hedef", ABI, libc, endian-ness ve diğer değişkenlerle birlikte CPU ve mimarinin kombinasyonunu kapsar (muhtemelen "çıplak metal" dahil). Tipik bir derleyici sınırlı sayıda hedef kombinasyonuna sahiptir (muhtemelen bir ABI, bir CPU ailesi, ancak muhtemelen hem 32 hem de 64 bit). Çapraz derleyici genellikle üzerinde çalıştığı sistemden başka bir hedefi olan bir derleyici veya birden çok hedefi veya ABI'si olan bir derleyici anlamına gelir (ayrıca buna bakın ).
İkili dosyalar farklı CPU mimarileri arasında taşınabilir mi?
Genel olarak, hayır. Geleneksel terimlerle ikili, belirli bir CPU veya CPU ailesi için yerel nesne kodudur . Ancak, orta derecede yüksek taşınabilirliğe sahip olabilecekleri birkaç durum vardır:
- bir mimari diğerinin bir üst kümesidir (genellikle en yeni ve en büyük x86 yerine x86 ikili dosyaları i386 veya i686'yı hedefler
-march=core2
)
- mimarilerden biri doğal öykünme veya diğerinin çevirisini sağlar ( Crusoe'yu duymuş olabilirsiniz ) veya uyumlu ortak işlemciler sağlar (örneğin PS2 )
- İşletim sistemi ve çalışma zamanı çoklu diziyi destekler (örn. x86_64'te 32 bit x86 ikili dosyalarını çalıştırma yeteneği) veya VM / JIT'i sorunsuz hale getirme ( Dalvik veya ART kullanan Android )
- her desteklenen mimari için esasen yinelenen kod içeren "şişman" ikili dosyalar için destek vardır
Bir şekilde bu sorunu çözmeyi başarırsanız, sayısız kütüphane sürümlerinin (glibc sana bakıyorum) diğer taşınabilir ikili sorunu o zaman kendini gösterecektir. (Çoğu yerleşik sistem sizi en azından bu sorundan kurtarır.)
Henüz yapmadıysanız, koşmak gcc -dumpspecs
ve gcc --target-help
neyle karşı karşıya olduğunuzu görmek için şimdi iyi bir zaman .
Yağ ikili dosyalarının çeşitli dezavantajları vardır , ancak yine de potansiyel kullanımları vardır ( EFI ).
Bununla birlikte, diğer cevaplarda eksik olan iki husus daha vardır: ELF ve ELF yorumlayıcısı ve rasgele ikili formatlar için Linux çekirdeği desteği . Burada gerçek olmayan işlemciler için ikili dosyalar veya baytlar hakkında ayrıntılı bilgi vermeyeceğim, ancak bunları "yerel" olarak ele almak ve Java veya derlenmiş Python bayt kodu ikili dosyalarını çalıştırmak mümkündür, ancak bu ikili dosyalar donanım mimarisinden bağımsızdır (ancak bunun yerine sonuçta yerel bir ikili dosya çalıştıran ilgili VM sürümünde).
Herhangi bir çağdaş Linux sistemi ELF ikili dosyalarını kullanacaktır ( bu PDF'deki teknik detaylar ), dinamik ELF ikili dosyaları söz konusu olduğunda, çekirdek görüntüyü belleğe yüklemekle sorumludur, ancak ELF'de ayarlanan '' tercüman '' ın görevidir. ağır kaldırma yapmak için üstbilgileri. Normalde bu, tüm bağımlı dinamik kitaplıkların kullanılabilir olmasını sağlar (kitaplıkları ve gerekli sembolleri listeleyen diğer bazı yapıları listeleyen '' Dinamik '' bölümün yardımıyla) - ancak bu neredeyse genel amaçlı bir dolaylama katmanıdır.
$ file /bin/ls
/bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses \
shared libs), stripped
$ readelf -p .interp /bin/ls
String dump of section '.interp':
[ 0] /lib/ld-linux.so.2
( /lib/ld-linux.so.2
aynı zamanda bir ELF ikili dosyasıdır, bir tercümanı yoktur ve yerel ikili koddur.)
ELF ile ilgili sorun, binary ( readelf -h /bin/ls
) içindeki başlığın belirli bir mimari, sınıf (32- veya 64-bit), endianess ve ABI (Apple'ın "evrensel" yağ ikili dosyaları Mach-O alternatif bir ikili format kullanmasıdır. bunun yerine bu sorunu çözer, bu NextSTEP'den kaynaklanır). Bu, bir ELF yürütülebilir dosyasının çalıştırılacağı sistemle eşleşmesi gerektiği anlamına gelir. Bir kaçış kapağı yorumlayıcıdır, bu herhangi bir yürütülebilir olabilir (başlangıçta ikili olan mimariye özgü alt bölümleri ayıklayan veya haritalayan ve bunları çağıran dahil), ancak yine de sisteminizin çalışmasına izin vereceği ELF türleriyle sınırlandırılırsınız . (FreeBSD ilginç bir yol var Linux ELF dosyalarını işleme , onun brandelf
değiştirir ELF ABI alanı.)
Linux'ta Mach-O desteği (kullanma binfmt_misc
) var, orada bir yağ (32- ve 64-bit) ikili oluşturmayı ve çalıştırmayı gösteren bir örnek var. Kaynak çatalları / ADS , başlangıçta Mac'te yapıldığı gibi, bir geçici çözüm olabilir, ancak yerel Linux dosya sistemi bunu desteklemez.
Aynı şey çekirdek modülleri .ko
için de geçerlidir, dosyalar da ELF'dir (tercüman kümeleri olmamasına rağmen). Bu durumda uname -r
, arama yolunda çekirdek sürümünü ( ) kullanan fazladan bir katman vardır, bunun yerine teorik olarak sürüm oluşturma ile ELF'de yapılabilir, ancak bazı karmaşıklık ve az kazançla şüphelenirim.
Başka bir yerde belirtildiği gibi, Linux doğal olarak yağ ikili dosyalarını desteklemez, ancak aktif bir yağ ikili projesi vardır: FatELF . Bu oldu senedir , bu (şimdi doldu) patent endişeleri kısmen standart Çekirdeğe entegre değildi. Şu anda hem çekirdek hem de araç zinciri desteği gerekiyor. Bu binfmt_misc
yaklaşımı kullanmaz , bu yan basamaklar ELF başlığı sorunudur ve yağ çekirdeği modüllerine de izin verir.
- Bir 'x86 hedefi, linux işletim sistemi sürümü xyz' üzerinde çalıştırmak için derlenmiş bir uygulama varsa, ben sadece aynı derlenmiş ikili başka bir sistemin 'ARM hedef, linux işletim sistemi sürümü xyz' çalıştırabilir miyim?
ELF ile değil, bunu yapmanıza izin vermez.
- Yukarıdaki doğru değilse, tek yol uygulama kaynak kodunu 'örneğin, arm-linux-gnueabi' ilgili araç zincirini kullanarak yeniden derlemek / yeniden derlemektir.
Basit cevap evet. (Karmaşık cevaplar öykünmeyi, ara gösterimleri, çevirmenleri ve JIT'i içerir; bir i686 ikilisinin yalnızca burada ilginç olmadıkları i386 opcodlarını kullanmak için "düşürülmesi" ve ABI düzeltmeleri potansiyel olarak yerel kodu çevirmek kadar zordur. )
- Benzer şekilde, bir 'x86 hedefi, linux işletim sistemi sürümü xyz' üzerinde çalışan yüklenebilir bir çekirdek modülü (aygıt sürücüsü) varsa, aynı derlenmiş .ko'yu başka bir sistemin 'ARM hedefi, linux işletim sistemi sürümü xyz' üzerine yükleyebilir / kullanabilir miyim ?
Hayır, ELF bunu yapmanıza izin vermeyecek.
- Yukarıdaki doğru değilse, tek yol sürücü kaynak kodunu 'örneğin, arm-linux-gnueabi' ilgili araç zincirini kullanarak yeniden derlemek / yeniden derlemek.
Basit cevap evet. FatELF'in .ko
çok mimarili bir yapı oluşturmanıza izin verdiğine inanıyorum , ancak bir noktada desteklenen her mimari için ikili bir sürüm oluşturulmalıdır. Çekirdek modülleri gerektiren şeyler genellikle kaynakla birlikte gelir ve gerektiği gibi oluşturulur, örneğin VirtualBox bunu yapar.
Bu zaten uzun bir saçma cevap, sadece bir yol daha var. Çekirdeğin zaten özel bir makine olsa da yerleşik bir sanal makinesi var: paketleri eşleştirmek için kullanılan BPF VM . İnsan tarafından okunabilir filtre "port 22 değil ana bilgisayar foo") bir bayt koduna derlenir ve çekirdek paket filtresi bunu yürütür . Yeni eBPF sadece paketler için değil, teorik olarak VM kodunun herhangi bir çağdaş linux arasında taşınabilir olduğunu ve llvm tarafından desteklendiğini, ancak güvenlik nedenleriyle büyük olasılıkla idari kurallar dışında herhangi bir şey için uygun olmayacağını belirtti.
Şimdi, bir ikili yürütülebilir dosya tanımı ile ne kadar cömert olduğunuza bağlı olarak, (ab) binfmt_misc
kabuk betiği ve ZIP dosyalarını bir kapsayıcı formatı ile yağ ikili desteği uygulamak için kullanabilirsiniz :
#!/bin/bash
name=$1
prog=${1/*\//} # basename
prog=${prog/.woz/} # remove extension
root=/mnt/tmpfs
root=$(TMPDIR= mktemp -d -p ${root} woz.XXXXXX)
shift # drop argv[0], keep other args
arch=$(uname -m) # i686
uname_s=$(uname -s) # Linux
glibc=$(getconf GNU_LIBC_VERSION) # glibc 2.17
glibc=${glibc// /-} # s/ /-/g
# test that "foo.woz" can unzip, and test "foo" is executable
unzip -tqq "$1" && {
unzip -q -o -j -d ${root} "$1" "${arch}/${uname_s}/${glibc}/*"
test -x ${root}/$prog && (
export LD_LIBRARY_PATH="${root}:${LD_LIBRARY_PATH}"
#readlink -f "${root}/${prog}" # for the curious
exec -a "${name}" "${root}/${prog}" "$@"
)
rc=$?
#rm -rf -- "${root}/${prog}" # for the brave
exit $rc
}
Buna "wozbin" deyin ve aşağıdaki gibi bir şeyle ayarlayın:
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
printf ":%s:%s:%s:%s:%s:%s:%s" \
"woz" "E" "" "woz" "" "/path/to/wozbin" "" > /proc/sys/fs/binfmt_misc/register
Bu, .woz
dosyaları çekirdeğe kaydeder ; wozbin
bunun yerine komut dosyası, ilk bağımsız değişkeni, çağrılan .woz
dosyanın yoluna ayarlandığında çağrılır .
Taşınabilir (yağ) bir .woz
dosya almak için, test.woz
bir dizin hiyerarşisine sahip bir ZIP dosyası oluşturmanız yeterlidir :
i686/
\- Linux/
\- glibc-2.12/
armv6l/
\- Linux/
\- glibc-2.17/
Her kemer / OS / libc dizininin içine (rasgele bir seçim) mimariye özgü test
ikili .so
dosyaları ve dosyalar gibi bileşenleri yerleştirin . Çağırdığınızda, gerekli alt dizin bir tmpfs bellek içi dosya sistemine ( /mnt/tmpfs
burada) çıkarılır ve çağrılır.