GCC -fPIC seçeneği


Yanıtlar:


526

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.


36
Bu örnek açıktır, ancak seçenek olmadan paylaşılan bir labrary (.so) dosyası oluşturursam kullanıcı olarak fark ne olur? -FPIC olmadan lib'imin geçersiz olacağı bazı durumlar var mı?
Narek

16
Evet, PIC olmayan bir paylaşılan kitaplık oluşturmak bir hata olabilir.
John Zwinck

92
Daha açık olmak gerekirse, paylaşılan kitaplığın süreçler arasında paylaşılması beklenir, ancak kitaplığın her ikisinde de aynı adreste yüklenmesi her zaman mümkün olmayabilir. Kod konumdan bağımsız olmasaydı, her işlem kendi kopyasını gerektirirdi.
Simon Richter

19
@Narek: bir işlem aynı sanal adrese birden fazla paylaşılan kitaplık yüklemek isterse hata oluşur. Kütüphaneler başka hangi kütüphanelerin yüklenebileceğini tahmin edemediğinden, geleneksel paylaşılan kütüphane konseptinde bu sorun kaçınılmazdır. Sanal adres alanı burada yardımcı olmuyor.
Philipp

6
-fPICBir 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.
Simon Richter

61

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.
robsn

Neden her zaman -fpic kullanmıyorsunuz?
Jay

1
@Jay - çünkü her fonksiyon çağrısı için bir hesaplama daha (fonksiyon adresi) gerekecektir. Performans açısından, eğer gerekli değilse, kullanmamak daha iyidir.
Roee Gavirel

45

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. -fPICSeçenek GCC böyle bir kod üretmesini sağlar.


Paylaşılan bir kitaplık neden -fPICbayrağ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?
Tony Tannous

1
-fPICBu 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.
Tony Tannous

1
Paylaşılan kitaplığı oluşturma (oluşturma 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 -fPICiç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 '.
Jonathan Leffler

Bu yüzden daha önce -fPIC. Bu bayrağı geçmeden, .so oluşturulurken oluşturulan kod kullanımda olabilecek belirli sanal adreslere yüklenmelidir?
Tony Tannous

1
Evet, çünkü PIC bayrağını kullanmadıysanız, kod güvenilir bir şekilde yeniden konumlandırılamazdı. Kod PIC değilse (veya en azından etkili bir şekilde imkansız olduklarını elde etmek o kadar zorsa) ASLR (adres alanı düzeni rasgeleleştirmesi) gibi şeyler mümkün değildir.
Jonathan Leffler

21

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.


1
Sanal adres açıklaması için teşekkürler.
Hot.PxL

2
Herkes bunun statik bir kitaplıkla nasıl bir sorun olmadığını açıklayabilir, neden statik bir kitaplıkta -fPIC kullanmak zorunda değilsiniz? Bağlamanın derleme zamanında (veya hemen sonra) yapıldığını anlıyorum, ancak konuma bağlı kodla 2 statik kitaplığınız varsa, nasıl bağlanacaklar?
Michael P

3
@MichaelP nesne dosyasında konuma bağlı etiketler tablosu vardır ve belirli obj dosyası bağlandığında tüm etiketler buna göre güncellenir. Bu paylaşılan kütüphaneye yapılamaz.
Slava

16

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


9

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.

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.