Linux ikili dosyası neden çalışmaz: glibc ve musl farkı
GLIBC_2.34 not found hatası, derleme yapılan makinenin sürüm sınırını belirlemesinden kaynaklanır. İkili dosyanın bağımlılıklarını inceleyip taşınabilir dağıtım yöntemlerini öğrenin.
Bir Linux ikili dosyasının eski bir sunucuda çalışmama nedeni
Taşınabilir bir Linux ikili dosyası üretmek zordur çünkü GNU C kütüphanesi olan glibc, yalnızca tek yönlü uyumluluk vaat eder. Eski bir ikili dosya, yeni bir glibc üzerinde çalışmaya devam eder. Ancak yeni bir ikili dosya, eski bir glibc üzerinde çalışmaz. Derleme yaptığınız makine, dağıtım yapacağınız tüm makineler için alt sınırı belirler.
Hata mesajı, ihtiyaç duyulan tam sürümü belirtir:
./mytool: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found (required by ./mytool)Dosyada bir bozulma veya yanlış yapılandırma yoktur. Dinamik yükleyici, ikili dosyanın içine kaydedilmiş bir sürüm etiketini okumuş, bu etiketi sistem libc'si içinde aramış, bulamamış ve programı başlatmayı reddetmiştir. Dosyayı yeniden indirmek ve chmod +x çalıştırmak hiçbir şeyi değiştirmez çünkü gereksinim dosyanın kendi içine yazılmıştır. Ya ikili dosyanın oluşturulma biçimini değiştirmeli ya da dağıttığınız dosyayı değiştirmelisiniz.
glibc sembol sürümlemenin gerçek işlevi
glibc tarafından dışa aktarılan her fonksiyon bir sürüm etiketi taşır. printf içindeki libc.so.6 aslında printf@@GLIBC_2.2.5'dır. glibc bir fonksiyonun davranışını veya ABI'sini (uygulama ikili arayüzü) değiştirdiğinde, eskisini silmez. Eski kodu eski etiket altında tutar ve yeni kodu yeni bir etiketle ekler; böylece tek bir libc.so.6 aynı anda aynı sembolün birkaç sürümünü barındırabilir. 2009 yılından kalma bir ikili dosya, 2009 etiketini yerinde bulur; ileriye dönük uyumluluğun bu kadar iyi çalışmasının nedeni budur.
Bağlama adımı, kullanılan sürümü kaydeder. İkili dosyanız, özetle "libc.so.6 içinden GLIBC_2.38'a ihtiyacım var" diyen bir .gnu.version_r bölümü edinir. Daha eski bir libc bu etikete hiçbir zaman sahip olmadığı için, yükleyici main çalışmadan önce durur. Bir geri dönüş (fallback) mekanizması yoktur, çünkü geri dönüş, programın derlendiği fonksiyondan farklı bir fonksiyonun sessizce programa verilmesi anlamına gelir.
2021'den bu yana en yaygın tetikleyici glibc 2.34 sürümüdür. Bu sürüm, libpthread ve libdl'ü libc içinde birleştirmiş ve her C programını başlatan fonksiyon olan __libc_start_main'i GLIBC_2.34 etiketine taşımıştır. Bu nedenle, glibc 2.34 veya daha yeni bir sürüme sahip herhangi bir dağıtımda derlenen bir "hello-world" programı, kaynak kod modern hiçbir şey çağırmasa bile GLIBC_2.34 gerektirir. Kendi kodları yıllardır değişmeyen kişiler için sorunun aniden ortaya çıkmasının nedeni budur.
Dağıtımım hangi glibc sürümünü kullanıyor?
The data behind this chart
[
{
"distro": "CentOS 7",
"glibc": 2.17
},
{
"distro": "RHEL 8",
"glibc": 2.28
},
{
"distro": "Ubuntu 20.04",
"glibc": 2.31
},
{
"distro": "Debian 11",
"glibc": 2.31
},
{
"distro": "RHEL 9",
"glibc": 2.34
},
{
"distro": "Ubuntu 22.04",
"glibc": 2.35
},
{
"distro": "Debian 12",
"glibc": 2.36
},
{
"distro": "Ubuntu 24.04",
"glibc": 2.39
},
{
"distro": "Debian 13",
"glibc": 2.41
}
]Bunlar, dağıtımlar tarafından yayınlanan ve Ağustos 2026 itibarıyla güncel olan, her dağıtımın kendi depolarında sunduğu sürümlerdir. CentOS 7'nin kullanım ömrü çoktan dolmuştur; ancak devralınan sunucularda hala çalıştırıldığı için listede tutulmaktadır. Sahip olduğunuz herhangi bir sunucuyu, ilk satırında glibc sürümünü yazdıran ldd --version komutuyla veya getconf GNU_LIBC_VERSION ile kontrol edin.
Bu 9 satırı bir merdiven gibi okuyun. Debian 13 üzerinde glibc 2.41 sürümüyle derleme yaparsanız, elde ettiğiniz sonuç Debian 13'ten daha eski hiçbir sistemde çalışmaz. Ubuntu 20.04 üzerinde glibc 2.31 sürümüyle derleme yaparsanız, aynı kaynak kod bu satırın üzerindeki tüm sistemlerde (Debian 13 dahil) çalışır. Desteklemeniz gereken en eski sunucu, dikkate almanız gereken tek derleme ana bilgisayarıdır; bu nedenle standartlaştırdığınız dağıtım, derlediğiniz her şey için ABI tabanını belirler. Bu karar, VPS üzerinde hangi işletim sisteminin çalıştırılacağının seçilmesi sürecindeki diğer ödünleşimlerle birlikte, sunucu filosu kurulmadan önce verilmelidir.
Bir binary dosyasının ihtiyaç duyduğu minimum glibc sürümü nasıl bulunur?
Bunu dosyanın içinden okuyun. Bu yöntem, derleme notları olmayan ve bir tedarikçi tarafından sağlanan binary dosyaları dahil olmak üzere her şey üzerinde çalışır.
objdump -T ./mytool | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -5Son satır alt sınırı belirtir. Eğer objdump eksikse, binutils paketini kurun. Eğer o sunucuya herhangi bir şey kuramıyorsanız, strings -a ./mytool | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -5 komutu yaklaşık bir sonuç verir; çünkü etiketler dosya içinde düz metin dizileri olarak saklanır.
readelf -V ./mytool komutu aynı gereksinimi yapısal olarak gösterir. Version needs section '.gnu.version_r' başlığı altındaki bloğu inceleyin. Bu blok, ilgili kütüphane altında her etiket için bir Name: GLIBC_x.y satırı listeler.
Alt sınırı hangi fonksiyonun belirlediğini bulmak için etiketi grep ile aratın: objdump -T ./mytool | grep GLIBC_2.38. Bu genellikle tek bir semboldür ve bazen kaçınabileceğiniz bir sembol olabilir. Eğer objdump -T hiçbir çıktı vermiyorsa, binary statik olarak bağlanmıştır; dolayısıyla dinamik sembol tablosu ve yazdırılacak bir sürüm gereksinimi yoktur.
Birinin size verdiği bir binary hakkında file ve readelf -d size neler söyler
file, mimariyi ve bağlantı türünü tek bir satırda verir.
file ./mytoolSıradan bir glibc derlemesi şu şekilde okunur:
ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=..., for GNU/Linux 3.2.0, not strippedStatik bir derleme statically linked çıktısını verir ve herhangi bir yorumlayıcı belirtmez. Bir musl derlemesi ise farklı bir yorumlayıcı belirtir:
ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, ...Önemli olan alan yorumlayıcıdır. Bu, çekirdeğin programınızdan önce çalıştırdığı dinamik yükleyicidir ve o tam yolun hedef makinede mevcut olması gerekir. /lib/ld-musl-x86_64.so.1, bir Debian veya Ubuntu sunucusunda musl yüklü değilse mevcut değildir.
readelf -d ./mytool, binary'nin talep ettiği paylaşımlı kütüphaneleri ismen listeler:
Dynamic section at offset 0x2d58 contains 27 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libssl.so.3]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/../lib]Her NEEDED girdisi, soname ile eşleşen zorunlu bir gereksinimdir. libssl.so.3, OpenSSL 3'tür; dolayısıyla bu binary, yalnızca libssl.so.1.1 içeren bir sunucuda yüklenmeyecektir ve bunun nedeni soname'dir: farklı bir soname, kasten uyumsuz bir ABI anlamına gelir. RUNPATH, yükleyiciye önce nerede arama yapacağını söyler ve $ORIGIN, binary'yi barındıran dizine genişler; kendi kendine yeten bir paketin kendi kütüphanelerini bu şekilde bulması sağlanır.
Güvenmediğiniz bir binary üzerinde ldd çalıştırmayın. glibc üzerinde ldd, bağımlılıkları programı yükleyici altında çalıştırarak çözümleyebilir, bu nedenle kötü niyetli bir dosya kod çalıştırma imkanı bulur. readelf ve objdump yalnızca baytları okur. Tüm bunlardan önce, indirilen dosyanın projenin gerçekten yayınladığı dosya olduğunu doğrulayın; çünkü yayınlanan sağlama toplamı ile indirmeyi doğrulama, elinizdeki baytların kime ait olduğunu söyleyen tek adımdır.
Karşılaşacağınız hatalar ve her birinin anlamı
Yükleyici, bulamadığı bir GLIBC sürümünü belirtiyor. İkili dosya, hedef sistemdekinden daha yeni bir glibc sürümüne karşı derlenmiştir. Hedef sistemde yüklü olan hiçbir şey bunu güvenli bir şekilde düzeltemez. Aşağıdaki dört seçenekten birini seçin.
Kabuk, açıkça görebildiğiniz bir dosya için No such file or directory hatası veriyor. Eksik olan şey ikili dosya değil, yorumlayıcıdır. ELF başlığında yükleyici yolu bulunmadığında execve komutu ENOENT çıktısını verir ve kabuk, elindeki tek hata mesajını yazdırır. file komutunu çalıştırın ve yorumlayıcı yolunu okuyun. Sadece glibc içeren bir sunucuda musl ile bağlanmış bir ikili dosya tam olarak bu belirtiyi verir.
cannot execute binary file: Exec format error, mimarinin yanlış olduğu anlamına gelir: arm64 sunucuda x86-64 ikili dosyası veya tam tersi. file çıktısının ilk satırı, elinizdekinin hangisi olduğunu size söyler.
error while loading shared libraries: libssl.so.3: cannot open shared object file, bir NEEDED kütüphanesinin eksik olduğu veya farklı bir soname altında bulunduğu anlamına gelir. Eşleşen dağıtım paketini yükleyin. Paket isimleri aileler arasında farklılık gösterir, bu nedenle bir README dosyasından apt satırını kopyalamadan önce çeviri yapın; dnf ve apt komut karşılıkları bu eşlemeyi kapsar.
Glibc altında sorunsuz çalışan bir musl derlemesinden gelen boş bir Segmentation fault. Genellikle 2. seçenek altında ele alınan iş parçacığı yığını (thread stack) boyutuyla ilgilidir.
Taşınabilir bir Linux binary dosyasını dağıtmanın dört yolu
Her yöntemin kendine has bir maliyeti vardır. Seçiminizi programınızın çalışma zamanındaki davranışına göre yapın; kulağa en temiz gelen yöntemi seçmeyin.
Seçenek 1: Desteklediğiniz en eski dağıtım üzerinde derleme yapın
En sıkıcı ancak genellikle en doğru yöntem budur. Desteklemeyi taahhüt ettiğiniz en eski dağıtımın container imajı içerisinde derleme yapın. Bağlayıcı (linker), yalnızca eski glibc sürümünde mevcut olan etiketleri kaydedebilir; bu sayede ikili dosya (binary), tüm glibc davranışlarını koruyan standart bir dinamik ikili dosya olarak kalırken, alt sınır o sürüme çekilmiş olur.
docker run --rm -v "$PWD:/src" -w /src ubuntu:20.04 sh -c 'apt-get update && apt-get install -y build-essential && make'Çıktı, 2.31 ve üzerindeki tüm glibc sürümlerinde çalışır. Varsayımlarla hareket etmek yerine doğrulama yapın: daha önce belirtilen objdump -T tek satırlık komutunu sonuç üzerinde çalıştırın ve en yüksek etiketin beklediğiniz sürüm olup olmadığını kontrol edin.
Bunun maliyeti araç zinciridir (toolchain). Eski bir temel imaj, aynı zamanda eski bir derleyici içerir; bu durum, kodunuz güncel bir C++ standardına ihtiyaç duyduğunda sorun yaratır. Go ve Rust dilleri, araç zincirlerini dağıtım paketlerinden bağımsız olarak container içine kurdukları için bu sorundan büyük ölçüde etkilenmezler. C ve C++ için dağıtımın kendi araç zinciri kanalından daha yeni bir derleyici ekleyebilir veya tam olarak eski bir glibc ile güncel bir GCC'yi birleştirmek amacıyla oluşturulmuş manylinux imajlarını kullanabilirsiniz. Zig'in beraberinde gelen C derleyicisi de zig cc -target x86_64-linux-gnu.2.28 örneğinde olduğu gibi doğrudan hedeflenen bir glibc sürümünü baz alabilir; bu sayede eski bir imajı tutmanıza gerek kalmadan aynı alt sınır elde edilir.
Seçenek 2: musl ile statik bağlantı kurma
musl, statik bağlantı (static linking) göz önünde bulundurularak yazılmış küçük bir C kütüphanesidir. Statik bir musl ikili dosyası kendi libc'sini içerir, herhangi bir yorumlayıcı (interpreter) belirtmez ve doğru mimariye sahip herhangi bir Linux çekirdeği üzerinde çalışır. Tek dosya olarak indirilen araçların çoğu bu şekilde oluşturulur.
sudo apt install -y musl-tools
musl-gcc -static -O2 hello.c -o hello
file ./hellofile artık yorumlayıcı alanı olmadan statically linked çıktısını vermelidir. Rust için hedefi ekleyin ve ona göre derleyin:
rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-muslGo için bunlara gerek yoktur. CGO_ENABLED=0 go build ile sonuç zaten statiktir ve hiçbir libc ile bağlantı kurmaz.
NSS aramaları değişir. glibc, kullanıcıları ve ana bilgisayar adlarını, program çalışırken dlopen ile libnss_* modüllerini yükleyen NSS (name service switch) aracılığıyla çözer. Statik olarak bağlanmış bir glibc bunu yapamaz ve bağlayıcı (linker) sizi şu sözlerle uyarır:
warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linkingmusl, NSS'yi hiç uygulamayarak bu uyarıyı devre dışı bırakır. Kendi çözümleyicisine sahiptir ve doğrudan /etc/resolv.conf ile /etc/hosts dosyalarını okur. Sıradan bir VPS üzerinde bu durum sorunsuzdur ve daha basittir. Hesapların veya isimlerin LDAP ya da SSSD'den geldiği bir ana bilgisayarda, ikili dosyanız bunları göremezken kutudaki diğer tüm programlar görebilir. musl'un çözümleyicisi de glibc'ninkinden daha yenidir: 512 bayttan büyük DNS yanıtları için TCP yedekleme özelliği musl 1.2.4 sürümüne 2023 yılında gelmiştir; bu nedenle daha eski musl sürümleriyle yapılan derlemeler büyük yanıtları keser.
dlopen çalışmaz. Statik bir musl ikili dosyasında dlopen her zaman başarısız olan bir taslaktır (stub). Çalışma zamanında kod yükleyen her şey devre dışı kalır: eklenti sistemleri, PAM modülleri, GPU sürücüleri, glibc'nin kendi iconv karakter seti modülleri. Programınız dlopen gerektiriyorsa statik bağlantı seçeneği elenir ve diğer üç çözümden birine ihtiyacınız olur.
Güvenlik güncellemeleri sizin sorumluluğunuzdadır. Dinamik olarak bağlanmış bir ikili dosya, sunucu paket yükseltmesini çalıştırdığı anda bir libc düzeltmesini alır. Statik bir ikili dosya ise asla almaz. libc'nize veya paketlediğiniz statik OpenSSL'e karşı bir CVE (ortak güvenlik açıkları ve maruziyetler) kaydı düştüğünde, yeniden derleyip dağıtmanız gerekir; aksi takdirde dağıtılan her kopya, birisi dosyayı değiştirene kadar savunmasız kalır. Neleri bağladığınızın kaydını tutun, çünkü hedef sistemdeki hiçbir şey bir yöneticiye tek dosyalık ikili dosyanızın iki yıl öncesine ait bir kütüphane içerdiğini söyleyemez.
Lisans değişir. glibc LGPL'dir ve statik bağlantı, LGPL'nin yeniden bağlama yükümlülüğünü tetikler: alıcılara programınızı farklı bir glibc ile yeniden bağlamaları için gerekenleri vermelisiniz. musl ise MIT lisanslıdır ve böyle bir koşul taşımaz. Tek dosyalık ikili dosyalar dağıtan projelerin statik glibc yerine musl'u tercih etmesinin temel nedeni budur.
İki çalışma zamanı farkı kafa karıştırıcı çökmelere neden olur. musl'un varsayılan iş parçacığı yığını (thread stack) glibc'deki 8 MiB'a karşılık 128 KiB'tır; bu nedenle iş parçacığı yığınına büyük bir arabellek koyan kod, hiçbir mesaj veya günlük satırı olmadan segfault hatası verir. Boyutu pthread_attr_setstacksize ile açıkça ayarlayın veya arabelleği yığına (heap) taşıyın. musl'un ayırıcısı da aynı anda çok sayıda iş parçacığının bellek ayırmasından ziyade küçük boyut ve öngörülebilir davranış için yazılmıştır; bu nedenle bellek ayırma yoğunluklu iş parçacıklı programlar gözle görülür şekilde daha yavaş çalışabilir. Her iki kütüphanenin itibarına güvenmek yerine kendi iş yükünüzü kıyaslayın (benchmark).
Seçenek 3: Yükleyiciyi ve kütüphaneleri paketlemek
Kütüphaneleri, eşleşen yükleyici ile birlikte ikili dosyanın yanına yerleştirin ve ardından programı bu yükleyici üzerinden başlatın.
./ld-linux-x86-64.so.2 --library-path ./lib ./mytoolBunu kalıcı hale getirmek için yolları patchelf ile dosyaya yazın:
patchelf --set-interpreter "$PWD/lib/ld-linux-x86-64.so.2" --set-rpath '$ORIGIN/lib' ./mytoolBunun çalışıp çalışmayacağına tek bir kural karar verir: yükleyici ve libc.so.6 aynı glibc sürümünden gelmelidir. Bunlar eşleşen bir çifttir; ana makinenin yükleyicisini paketlenmiş bir libc ile karıştırmak, okunabilir bir hata yerine başlatma sırasında çökmeye neden olur. Ya ikisini de paketleyin ya da hiçbirini paketlemeyin.
AppImage, bu modelin paketlenmiş halidir; yük (payload) bir squashfs imajı içindedir ve bunu bağlayan (mount) küçük bir çalışma zamanı (runtime) bulunur. İnsanların gözden kaçırdığı bir özelliği vardır: AppImage, glibc'yi paketlemez. Bu nedenle, güncel bir dağıtımda oluşturulan bir AppImage, eski bir sunucuda aynı sürüm hatasıyla başarısız olmaya devam eder. AppImage'ın kendi kılavuzu, desteklediğiniz en eski temel üzerinde derleme yapmanızı önerir; bu da onu bir alternatiften ziyade, 1. seçeneğin üzerine katmanlanmış bir dağıtım formatı haline getirir.
Başsız (headless) bir sunucuda AppImage, yükünü bağlamak için FUSE (filesystem in userspace) gerektirir ve minimal VPS imajları genellikle bunu içermez. Hata libfuse.so.2 olarak adlandırılır. Bağlama işlemini tamamen atlamak için, geçici bir dizine açıp oradan çalıştıran ./App.AppImage --appimage-extract-and-run komutunu kullanabilirsiniz.
Seçenek 4: Container imajı dağıtmak
Programla birlikte tüm kullanıcı alanını (userland) taşıyın. İmaj kendi libc kütüphanesini taşıdığı için ana makinenin glibc sürümü önemini yitirir; yalnızca çekirdek ve mimarinin uyumlu olması yeterlidir. Bu en az zekice olan seçenektir ancak tüm sorun sınıfını ortadan kaldırdığı için pek çok sunucu yazılımı bu şekilde dağıtılır. VPS üzerinde Docker çalıştırmak, bu yöntemi kullanmanın alışılagelmiş yoludur.
Ana makine çekirdeği yine de bir sınır belirler. Daha yeni glibc sürümleri daha yeni sistem çağrıları kullanır ve eski bir container ana makinesi bunları engelleyebilir: glibc 2.34 ve sonrası clone3 kullanır; eski varsayılan seccomp profilleri bunu reddeder. Belirti, glibc'den hiç bahsedilmeyen Operation not permitted hatasıyla anında başarısız olmaktır. Ana makinedeki container çalışma zamanını (runtime) yükseltmek bu sorunu çözer, çünkü engelleme çekirdekte değil, çalışma zamanının sistem çağrısı filtresindedir.
Maliyetler standarttır. Hedef sistemin bir container çalışma zamanına ve bunu kullanma iznine ihtiyacı vardır. İndirme boyutunuz tek bir dosyadan onlarca veya yüzlerce megabayta çıkar. Artık bir temel imaja ve onun yama takvimine sahipsiniz; bu nedenle 2. seçenekte kaçındığınız güvenlik iş yükü, imajı yeniden oluşturma gerekliliği olarak geri döner. Uzun süre çalışan bir servis için bu makul bir takastır. Birinin tek seferlik çalıştırdığı bir komut satırı aracı için ise değildir.
Hangi seçeneği tercih etmelisiniz?
- Kontrolünüz altındaki ve tamamı aynı dağıtımı çalıştıran sunucular için bir dahili araç: dinamik olarak o dağıtım üzerinde derleyin ve orada bırakın.
- Yabancıların indirip çalıştıracağı tek bir dosya: programın
dlopenihtiyacı yoksa ve NSS destekli aramalara gereksinim duymuyorsa, statik musl kullanın. - Eklentileri veya GPU erişimi olan bir program: dinamik yapıda kalın, eski bir temel üzerinde derleyin ve teslim etmek için 3. seçeneği kullanın.
- Halihazırda bir çalışma zamanına sahip bir makinede uzun süre çalışan bir servis: imajı gönderin.
Ne seçerseniz seçin, bunu not edin ve kontrol edin. Derleme sunucusunun glibc sürümü artık sürüm sürecinizin bir parçasıdır; bir LTS sürümünden diğerine yükseltilen bir derleme makinesi, alt sınırı sessizce yükseltir ve geçen ay sorunsuz çalışan kullanıcıların sistemini bozar. Derleme imajını etiket (tag) ile sabitleyin ve çıktıdaki en yüksek GLIBC_ etiketini bir derleme adımı olarak doğrulayın; böylece kontrol, başkasının terminali yerine kendi işlem hattınızda (pipeline) başarısız olur.
FAQ
Sunucumda neden "version GLIBC_2.38 not found" hatası alıyorum?
İkili dosya (binary), sunucunuzdakinden daha yeni bir glibc sürümüne sahip bir makinede derlenmiştir. glibc sembol sürümleme sistemi yalnızca ileriye dönük uyumluluk sağlar: eski ikili dosyalar yeni glibc üzerinde çalışır, ancak yeni ikili dosyalar eski glibc üzerinde çalışmaz. Bunun nedeni, yükleyicinin dosya içinde kayıtlı olan tam sürüm etiketine ihtiyaç duyması ve eski libc sürümlerinin bu etikete sahip olmamasıdır. Sunucuya kuracağınız hiçbir şey bu sorunu güvenli bir şekilde çözmez. Daha eski bir temel üzerinde yeniden derleme yapın, statik bir musl sürümü dağıtın, kütüphaneleri eşleşen yükleyicileriyle birlikte paketleyin veya bir container imajı kullanın.
Bir ikili dosyanın hangi glibc sürümüne ihtiyaç duyduğunu nasıl anlarım?
objdump -T ./mytool | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -5 komutu ile dosyadaki sürüm etiketlerini okuyun. Son satır, dosyayı yükleyebilecek en düşük glibc sürümünü gösterir. readelf -V ./mytool, aynı gereksinimleri .gnu.version_r bölümünde, bunları sağlaması gereken kütüphanelere göre gruplandırılmış şekilde gösterir. Eğer objdump -T hiçbir çıktı vermiyorsa, ikili dosya statiktir ve herhangi bir glibc gereksinimi yoktur. Sonucu, ldd --version komutu ile sunucunuzun kendi sürümüyle karşılaştırın.
Bir musl ikili dosyası, glibc ikili dosyasından daha mı yavaştır?
Bu, iş yüküne bağlıdır; dürüst cevap ölçüm yapmaktır. Statik bir musl ikili dosyası daha hızlı başlar, çünkü çalıştırılacak bir yükleyici yoktur ve yürütme anında yeniden konumlandırma (relocation) işlemi gerekmez. Buna karşılık, musl'un bellek ayırıcısı (allocator) aynı anda çok sayıda iş parçacığının bellek ayırdığı durumlar yerine, küçük boyut ve öngörülebilir davranış için tasarlanmıştır. Ayrıca musl, glibc'ye kıyasla daha az el ile optimize edilmiş dizgi ve bellek rutinleri içerir; bu nedenle bellek ayırma veya dizgi işlemlerinin yoğun olduğu çok iş parçacıklı programlar belirgin şekilde daha yavaş olabilir. Herhangi bir iddiayı kabul etmeden önce kendi programınızı kendi sunucunuzda kıyaslayın (benchmark).
Bash, mevcut olan bir dosya için neden "No such file or directory" diyor?
Eksik olan dosya ikili dosyanız değil, dinamik yükleyicidir. Çekirdek, yorumlayıcı yolunu ELF başlığından okur ve bu yol mevcut olmadığında ENOENT hatası döner; kabuk (shell) ise bunu elindeki tek mesajla bildirir. file ./mytool komutunu çalıştırın ve interpreter alanını okuyun. Eğer bir Debian veya Ubuntu sunucusunda /lib/ld-musl-x86_64.so.1 çıktısını alıyorsanız, glibc tabanlı bir sistemde musl ile bağlanmış bir ikili dosya kullanıyorsunuz demektir; bu durumda musl uyumlu bir indirme veya statik bir derleme kullanmanız gerekir.
Bunu düzeltmek için libc.so.6 dosyasını daha yeni bir sunucudan kopyalayabilir miyim?
Hayır. libc.so.6 ve ld-linux-x86-64.so.2, tek bir glibc derlemesinden gelen eşleşmiş bir çifttir ve makinedeki her süreç bunları kullanır. Sistem kopyasının üzerine yazmak, geri alma işlemini yapacak araçlar dahil olmak üzere sunucudaki hiçbir şeyin çalışmamasına neden olabilir. Eğer daha yeni bir ikili dosyayı eski bir ana makinede çalıştırmanız gerekiyorsa, daha yeni glibc'yi özel bir dizine açın ve o programı kendi yükleyicisi üzerinden --library-path ile başlatın; bu işlem yalnızca ilgili süreci etkiler. Eski glibc sürümüne göre yeniden derlemek, altı ay sonra sizi şaşırtmayacak tek çözümdür.