Kod oluşturma kuralları için GCC seçenekleri hakkında okudum , ama "Konum bağımsız kod (PIC) üret" ne yaptığını anlayamadım. Lütfen bunun ne anlama geldiğini açıklamak için bir örnek verin.
Kod oluşturma kuralları için GCC seçenekleri hakkında okudum , ama "Konum bağımsız kod (PIC) üret" ne yaptığını anlayamadım. Lütfen bunun ne anlama geldiğini açıklamak için bir örnek verin.
Yanıtlar:
Bağımsız Kod Konumu, üretilen makine kodunun çalışmak için belirli bir adreste bulunmasına bağlı olmadığı anlamına gelir.
Örneğin, sıçramalar mutlaktan ziyade göreli olarak üretilirdi.
Pseudo-montaj:
PIC: Kod 100 veya 1000 adresinde olsun, bu işe yarar
100: COMPARE REG1, REG2
101: JUMP_IF_EQUAL CURRENT+10
...
111: NOP
PIC olmayan: Bu, yalnızca kod 100 adresinde olduğunda çalışır
100: COMPARE REG1, REG2
101: JUMP_IF_EQUAL 111
...
111: NOP
EDIT: Yoruma yanıt olarak.
Kodunuz -fPIC ile derlenmişse, kitaplığa eklenmek için uygundur - kitaplık bellekte tercih edilen konumundan başka bir adrese taşınabilmelidir, kitaplığınızın tercih ettiği adreste önceden yüklenmiş başka bir kitaplık olabilir.
-fPIC
Bir programı veya statik kitaplığı derlerken atlayabilirsiniz , çünkü bir işlemde yalnızca bir ana program bulunacaktır, bu nedenle çalışma zamanının yeniden konumlandırılması gerekmez. Bazı sistemlerde, programlar daha fazla güvenlik için konumdan bağımsız hale getirilmektedir.
Daha önce söylenenleri daha basit bir şekilde açıklamaya çalışacağım.
Paylaşılan bir lib yüklendiğinde, yükleyici (çalıştırdığınız herhangi bir programı yükleyen işletim sistemi üzerindeki kod), nesnenin yüklendiği yere bağlı olarak koddaki bazı adresleri değiştirir.
Yukarıdaki örnekte, PIC olmayan koddaki "111" ilk yüklendiğinde yükleyici tarafından yazılmıştır.
Paylaşılmayan nesneler için bunun böyle olmasını isteyebilirsiniz, çünkü derleyici bu kod üzerinde bazı optimizasyonlar yapabilir.
Paylaşılan nesne için, başka bir işlem bu koda "bağlantı vermek" istiyorsa, aynı sanal adreslere okuması gerekir ya da "111" hiçbir anlam ifade etmez. ancak bu sanal alan ikinci işlemde zaten kullanılıyor olabilir.
Whenever a shared lib is loaded, the loader changes some addresses in the code depending on where the object was loaded to.
-Fpic ile derlenmişse ve performans nedenlerinden dolayı ya da yeniden yerleştirilemeyen bir yükleyiciniz olduğu için ya da farklı konumlarda ya da daha fazla nedenden dolayı birden fazla kopyaya ihtiyacınız olduğu için bunun doğru olmadığını düşünüyorum.
Paylaşılan kitaplıklara yerleşik kod normal olarak konumdan bağımsız bir kod olmalıdır, böylece paylaşılan kitaplık bellekteki herhangi bir adrese (az ya da çok) kolayca yüklenebilir. -fPIC
Seçenek GCC böyle bir kod üretmesini sağlar.
-fPIC
bayrağa sahip olmadan bellekteki hiçbir adrese yüklenmeyecek ? programa bağlı değil mi? program çalışırken, işletim sistemi programı belleğe yükler. Bir şey mi kaçırıyorum?
-fPIC
Bu lib'in , bağlanan süreçteki herhangi bir sanal adrese yüklenebilmesini sağlamak için bayrak kullanılıyor mu? çift yorum için üzgünüm 5 dakika geçti öncekini düzenleyemezsiniz.
libwotnot.so
) ve onunla bağlantı kurma ( ) arasında ayrım yapın -lwotnot
. Bağlarken, uğraşmanıza gerek yok -fPIC
. Paylaşılan kitaplığı oluştururken, paylaşılan kitaplığın -fPIC
içine yerleştirilecek tüm nesne dosyalarının kullanıldığından emin olmanız gerekiyordu . Derleyiciler bugünlerde varsayılan olarak PIC kodu ile oluşturulduğu için kurallar değişmiş olabilir. Bu yüzden, 20 yıl önce kritik olan ve 7 yıl önce önemli olabilecek şeylerin bu günlerde daha az önemli olduğuna inanıyorum. O / s çekirdeğinin dışındaki adresler 'her zaman' sanal adreslerdir '.
-fPIC
. Bu bayrağı geçmeden, .so oluşturulurken oluşturulan kod kullanımda olabilecek belirli sanal adreslere yüklenmelidir?
Daha fazla ekleniyor ...
Her işlemin aynı sanal adres alanı vardır (Linux adresinde bir bayrak kullanılarak sanal adresin rasgele seçilmesi durdurulursa) (Daha fazla bilgi için Adres alanı düzeni rasgeleleştirmeyi yalnızca kendim için devre dışı bırak ve yeniden etkinleştir )
Dolayısıyla, paylaşılan bir bağlantı içermeyen bir exe (Varsayımsal senaryo) ise, aynı sanal adresi her zaman zarar vermeden aynı asm komutuna verebiliriz.
Ancak paylaşılan nesneyi exe'ye bağlamak istediğimizde, paylaşılan nesnelerin bağlanma sırasına bağlı olacağı için paylaşılan nesneye atanan başlangıç adresinden emin değiliz. bağlandığı sürece bağlı olarak farklı sanal adres.
Bu nedenle, bir işlem kendi sanal alanında 0x45678910 olarak başlangıç adresini verebilir ve aynı anda diğer işlem 0x12131415'in başlangıç adresini verebilir ve göreli adresleme kullanmazlarsa .so hiç çalışmaz.
Bu yüzden her zaman göreli adresleme modunu ve dolayısıyla fpic seçeneğini kullanmak zorundadırlar.
Dinamik kitaplıktaki bir işleve bağlantı, kitaplık yüklendiğinde veya çalışma zamanında çözümlenir. Bu nedenle, program çalıştırıldığında hem yürütülebilir dosya hem de dinamik kitaplık belleğe yüklenir. Dinamik bir kitaplığın yüklendiği bellek adresi önceden belirlenemez, çünkü sabit bir adres aynı adresi gerektiren başka bir dinamik kitaplıkla çakışabilir.
Bu sorunla başa çıkmak için yaygın olarak kullanılan iki yöntem vardır:
1.Relocation. Koddaki tüm işaretçiler ve adresler gerekirse gerçek yükleme adresine uyacak şekilde değiştirilir. Yer değiştirme, bağlayıcı ve yükleyici tarafından yapılır.
2.Konumdan bağımsız kod. Koddaki tüm adresler geçerli konuma göredir. Unix benzeri sistemlerde paylaşılan nesneler varsayılan olarak konumdan bağımsız kod kullanır. Bu, program uzun süre, özellikle 32 bit modunda çalışıyorsa, yer değiştirme işleminden daha az verimlidir.
" Konumdan bağımsız kod " adı aslında aşağıdakileri içerir:
Kod bölümü, yeniden konumlandırılması gereken mutlak adresler içermez, yalnızca kendi göreli adreslerini içerir. Bu nedenle, kod bölümü isteğe bağlı bir bellek adresine yüklenebilir ve birden çok işlem arasında paylaşılabilir.
Veri bölümü, genellikle yazılabilir veriler içerdiği için birden çok işlem arasında paylaşılmaz. Bu nedenle, veri bölümü, yeniden konumlandırılması gereken işaretçiler veya adresler içerebilir.
Linux'ta tüm genel işlevler ve genel veriler geçersiz kılınabilir. Ana yürütülebilir dosyadaki bir işlev, paylaşılan bir nesnedeki bir işlevle aynı ada sahipse, ana sürüm yalnızca anadan çağrıldığında değil, aynı zamanda paylaşılan nesneden çağrıldığında da öncelik kazanacaktır. Benzer şekilde, genel bir global değişken, paylaşılan nesnede bir global değişkenle aynı ada sahip olduğunda, ana nesnede, paylaşılan nesneden erişilse bile kullanılır.
Bu sembol interpozisyonunun statik kütüphanelerin davranışını taklit etmesi amaçlanmıştır.
Paylaşılan bir nesnenin bu "geçersiz kılma" özelliğini uygulamak için işlevlerine yönelik bir prosedürler tablosu, prosedür bağlantı tablosu (PLT) ve değişkenleri için genel ofset tablosu (GOT) olarak işaretçiler tablosu bulunur. İşlevlere ve genel değişkenlere tüm erişim bu tablolardan geçer.
ps Dinamik bağlantıdan kaçınılamıyorsa, konumdan bağımsız kodun zaman alıcı özelliklerinden kaçınmanın çeşitli yolları vardır.
Bu makaleden daha fazla bilgi edinebilirsiniz: http://www.agner.org/optimize/optimizing_cpp.pdf
Daha önce gönderilmiş cevaplara küçük bir ekleme: konumdan bağımsız olarak derlenmemiş nesne dosyaları yeniden konumlandırılabilir; yer değiştirme tablosu girdileri içerirler.
Bu girişler, yükleyicinin (bir programı belleğe yükleyen kod biti) sanal adres alanındaki gerçek yükleme adresini ayarlamak için mutlak adresleri yeniden yazmasına izin verir.
Bir işletim sistemi, belleğe yüklenen bir "paylaşılan nesne kitaplığının" tek bir kopyasını, aynı paylaşılan nesne kitaplığına bağlı tüm programlarla paylaşmaya çalışır.
Kod adres alanının (veri alanının bölümlerinin aksine) bitişik olması gerekmediğinden ve belirli bir kitaplığa bağlanan çoğu programın oldukça sabit bir kütüphane bağımlılığı ağacı olduğundan, bu çoğu zaman başarılı olur. Bir tutarsızlığın olduğu nadir durumlarda, evet, bellekte paylaşılan bir nesne kitaplığının iki veya daha fazla kopyasına sahip olmak gerekebilir.
Açıkçası, bir kütüphanenin yük adresini programlar ve / veya program örnekleri arasında rastgele kullanma girişimleri (sömürülebilir bir desen oluşturma olasılığını azaltmak için) bu tür vakaları nadir değil, yaygın hale getirecektir, böylece bir sistem bu özelliği etkinleştirdiğinde, paylaşılan tüm nesne kitaplıklarını konum bağımsız olarak derlemek için her girişimde bulunulmalıdır.
Bu kütüphanelere ana programın gövdesinden yapılan çağrılar da yeniden yerleştirilebilir hale getirileceğinden, bu paylaşılan bir kütüphanenin kopyalanması olasılığını azaltır.