Wat is Positie-onafhankelijke code (PIC)?
Machinecode die op elk geheugenadres kan worden geladen en werken zonder de code aan te passen. Gebruikt PC-relatieve verwijzingen en de GOT, en wordt toegepast in gedeelde bibliotheken en PIE.
Japanse benaming: 位置独立コード
“Positie-onafhankelijke code (PIC)” komt voor in 3 oefenvragen uit 3 onderwerpen, bijv. Siliciumfotonica, Linker, loader en uitvoerbare formaten, Instructieset en assembly.
Vakgebied: Linker, loader en uitvoerbare formaten
Hoe PIC code en data adresseert
Positie-onafhankelijke code (position-independent code, PIC) bevat nooit absolute adressen in haar instructies. Sprongen en aanroepen geven hun doel aan als afstand ten opzichte van de programmateller, en die blijft gelijk waar de hele module ook wordt geplaatst. Voor doelen die verder liggen dan een branchveld kan bereiken, combineert RISC-V auipc, dat een 20-bit immediate, 12 bits naar links geschoven, bij de PC optelt, met jalr of een load die de onderste 12 bits levert; zo wordt ongeveer ±2 GiB rond de huidige instructie bereikt. x86-64 biedt voor hetzelfde doel RIP-relatieve adressering, waardoor positie-onafhankelijke code bijna even snel is als code met vaste adressen.
PIC vs. PIE en de link met beveiliging
Een position-independent executable (PIE) past dezelfde techniek toe op het hoofdprogramma, meestal gebouwd met de opties -fPIE en -pie in GCC of Clang, terwijl gedeelde bibliotheken -fPIC gebruiken. Oudere uitvoerbare bestanden gingen uit van een vast laadadres, zodat address space layout randomization (ASLR) wel bibliotheken en de stack kon verplaatsen, maar niet de code van het hoofdprogramma, waarvan de adressen dus voorspelbaar bleven voor aanvallers. Een PIE kan overal worden geladen, dus ook zijn code wordt gerandomiseerd, en veel huidige Linux-distributies bouwen standaard PIE's. De prijs is een kleine overhead door de indirectie via de GOT, die op 32-bit x86 merkbaar groter was.
Veelgestelde vragen
Waar staat PIC voor?
PIC staat voor position-independent code: machinecode die zonder aanpassing correct draait op elk laadadres. Ze steunt op PC-relatieve adressering en de global offset table.
Wat is het verschil tussen -fPIC en -fPIE?
Beide genereren positie-onafhankelijke code; -fPIC is bedoeld voor gedeelde bibliotheken, waarvan de symbolen door andere modules kunnen worden overschreven, terwijl -fPIE bedoeld is voor het hoofdprogramma en iets goedkopere directe verwijzingen naar zijn eigen symbolen kan gebruiken. Een programma dat met -fPIE is gecompileerd, wordt met -pie gelinkt om een PIE te maken.
Waarom is de global offset table nodig?
Code kan het adres van een symbool in een andere module niet zelf bevatten, omdat dat adres pas na het laden bekend is. De GOT bevat die adressen, ingevuld door de dynamische linker, en de code bereikt de GOT via een PC-relatieve verwijzing.