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.

De GOT en de PLT

PC-relatieve afstanden werken binnen één module, maar het adres van een variabele of functie in een andere gedeelde bibliotheek is pas tijdens runtime bekend. PIC bereikt zulke symbolen daarom via de global offset table (GOT), een tabel met adressen per module die op een vaste afstand van de code staat. De code laadt het benodigde adres uit de GOT, en de dynamische linker vult bij het laden de echte adressen in. Op ELF-systemen lopen aanroepen naar externe functies bovendien via kleine stubs in de procedure linkage table (PLT), die elke functie lui (lazy) kunnen oplossen bij haar eerste aanroep.

Waarom gedeelde bibliotheken het nodig hebben

Een gedeelde bibliotheek kan in elk proces dat haar gebruikt op een ander virtueel adres worden gemapt. Als haar code absolute adressen bevatte, zou de loader de instructies voor elk adres moeten aanpassen, waardoor gedeelde read-only pagina's private beschrijfbare kopieën worden en het delen zijn doel mist. Met PIC verschilt alleen de kleine beschrijfbare GOT tussen processen, zodat de codepagina's niet hoeven te worden aangepast en één fysieke kopie in alle processen wordt gemapt. Dat bespaart geheugen en laat de bibliotheek snel laden, waar ze ook terechtkomt.

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.

Nu oefenen: vragen over Positie-onafhankelijke code (PIC)

Wat is een juiste reden voor een opbouw waarbij een chip met optische componenten (PIC) en een chip met elektronische schakelingen zoals drivers en TIA's (EIC) afzonderlijk worden gemaakt, gestapeld en verbonden?

  1. AOptische componenten en snelle transistors kunnen principieel niet samen op dezelfde wafer worden gemaakt
  2. BVoor elk kan het geschikte productieproces worden gekozen, en met korte verbindingen wordt de parasitaire capaciteit verkleind voor hogere snelheid en lager energieverbruik
  3. CHoe verder PIC en EIC uit elkaar worden geplaatst, hoe kleiner de capaciteit van de bedrading en hoe sneller het signaal zich voortplant
Antwoord en toelichting tonen

Antwoord: B. Voor elk kan het geschikte productieproces worden gekozen, en met korte verbindingen wordt de parasitaire capaciteit verkleind voor hogere snelheid en lager energieverbruik

Voor optische componenten volstaan afmetingen van enkele honderden nm, zodat ze met processen van een relatief oude generatie kunnen worden gemaakt, terwijl drivers en TIA's die op enkele tientallen GHz werken beter in fijne CMOS- of SiGe-processen met snelle transistors kunnen worden gemaakt. Door ze als afzonderlijke chips te maken, kan voor elk het optimale proces worden gekozen. Door ze vervolgens met microbumps of hybride bonding verticaal te stapelen, worden de verbindingen zeer kort en worden parasitaire capaciteit en inductantie klein, wat bijdraagt aan hogere snelheid en lager energieverbruik. Er zijn ook producten met monolithische integratie, waarbij optische en elektronische schakelingen op dezelfde chip worden gemaakt, die in de praktijk worden toegepast.

Welke omschrijving van position-independent code (PIC) is juist?

  1. AMachinecode die op elke CPU op dezelfde manier werkt
  2. BMachinecode die tijdens uitvoering voortdurend haar eigen plaats verplaatst
  3. CMachinecode die zo is gemaakt dat ze correct werkt zonder herschrijven, op welk geheugenadres ze ook wordt geladen
Antwoord en toelichting tonen

Antwoord: C. Machinecode die zo is gemaakt dat ze correct werkt zonder herschrijven, op welk geheugenadres ze ook wordt geladen

Gedeelde bibliotheken kunnen per proces op een ander adres worden geladen. Position-independent code verwijst naar functies en data niet via vaste adressen maar via de afstand vanaf PC of via een tabel met adressen (GOT). Zo hoeven de codepagina's ook bij een ander laadadres niet te worden herschreven, en kan één kopie in het fysieke geheugen door veel processen worden gedeeld.

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.

“Positie-onafhankelijke code (PIC)” in de toelichting

Vragen met “Positie-onafhankelijke code (PIC)” (3)

  1. Wat is een juiste reden voor een opbouw waarbij een chip met optische componenten (PIC) en een chip met elektronische schakelingen zoals drivers en TIA's (EIC) afzonderlijk worden gemaakt, gestapeld en verbonden?
  2. Welke omschrijving van position-independent code (PIC) is juist?
  3. Welk voordeel van PC-relatieve adressering voor sprongen is juist?

Verwante termen

Transimpedantieversterker (TIA) CMOS SiGe (silicium-germanium) Hybride bonding (hybrid bonding) Via GOT (global offset table) PC-relatieve adressering Sprongvoorspelling (branch prediction) ASLR BSS-sectie

Naar de woordenlijst