Dipende se la tua implementazione utilizza C interfaccia per utilità di basso livello o meno.
Se la tua implementazione linguistica dà accesso diretto alle chiamate di sistema senza passare attraverso la C wrapper non è necessario utilizzare VDSO (potresti ad esempio generare l'appropriato SYSENTER
istruzioni macchina per eseguire la chiamata di sistema), ma potresti decidere di utilizzare VDSO e quindi trarne vantaggio. In tal caso, la tua lingua non ha nemmeno bisogno di seguire tutte le convenzioni ABI, solo le convenzioni del kernel. (ad esempio, non hai bisogno del distinguo calle-safe caller-safe fornito da ABI sui registri e potresti anche evitare di utilizzare qualsiasi stack).
Un esempio di implementazione del linguaggio che non utilizza nemmeno libc.so
è lo schema delle ossa. Potresti trovarne altri.
La mia comprensione del VDSO è che si tratta di un'astrazione, fornita dal kernel, per astrarre le varie piccole differenze (relative alle transizioni user-land -> kernel) nell'implementazione delle chiamate di sistema, tra le varie famiglie di processori x86. Se hai scelto un particolare obiettivo del processore, non hai bisogno di VDSO e puoi sempre evitarlo.
AFAIU, il VDSO è un oggetto condiviso ELF, seduto (sulla mia Debian/AMD64 con un kernel 3.8.3 compilato di recente) nel segmento ffffffffff600000-ffffffffff601000
; controlla esattamente con cat /proc/self/maps
dove è). Quindi devi solo capire l'organizzazione degli oggetti condivisi ELF e recuperare i simboli da esso. Vedi questo e quello link. Il VDSO utilizza le convenzioni C per le chiamate documentate nella specifica ABI x86-64.
ELF è un formato ben documentato. E così sono le convenzioni ABI x86-64 (che definiscono precisamente le convenzioni di chiamata C e come inizia esattamente l'immagine di un processo. Vedi anche la pagina man di execve (2)) e, naturalmente, la documentazione del kernel, quindi non capisco qual è il tuo problema. Sono d'accordo che la comprensione dell'ELF richieda tempo (l'ho fatto 10 anni fa, ma la mia memoria è arrugginita). Leggi anche il <elf.h>
file di intestazione sulla tua macchina.
Per esempio; in esecuzione (sotto zsh
su Debian x86-64 a 64 bit)
% file $(which sash)
/bin/sash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
statically linked, for GNU/Linux 2.6.26,
BuildID[sha1]=0x0347fcc08fba2f811f58af99f26111d0f579a9f6, stripped
% ldd $(which sash)
not a dynamic executable
% sash
Stand-alone shell (version 3.7)
> ps |grep sash
21635 pts/3 00:00:00 sash
> cat /proc/21635/maps
00400000-004da000 r-xp 00000000 08:01 4985590 /bin/sash
006da000-006dc000 rw-p 000da000 08:01 4985590 /bin/sash
006dc000-006e1000 rw-p 00000000 00:00 0
017e3000-01806000 rw-p 00000000 00:00 0 [heap]
7fe4950e5000-7fe4950e7000 rw-p 00000000 00:00 0
7fff3f130000-7fff3f151000 rw-p 00000000 00:00 0 [stack]
7fff3f173000-7fff3f175000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Vedi anche questa risposta.
Probabilmente vorrai all'interno del tuo runtime una versione minima di un linker dinamico in grado di analizzare semplicemente il VDSO. Sicuramente vuoi capire lo stato esatto in cui viene avviato un processo, e in particolare il ruolo di auxv
, il vettore ausiliario (dimentico davvero questi dettagli, ma ricordo che sono importanti). Vedi ad es. questo articolo
In realtà, avviare in modo affidabile il tuo runtime è probabilmente più difficile del problema VDSO.
Potresti anche voler leggere l'assembly linux howto che spiega anche alcune cose (ma più su x86 che su x86-64)
A proposito, il codice di http://musl-libc.org/ (che è una libc alternativa) è molto più facile da leggere e capire (e imparerai facilmente come fanno il collegamento dinamico, i pthread, ecc.)
Ho trovato utili questi file nell'albero del kernel di Linux:
Documentation/ABI/stable/vdso
(cos'è l'oggetto vDSO?)Documentation/vDSO/parse_vdso.c
(Parser di riferimento per l'oggetto vDSO)
L'oggetto vDSO è un oggetto condiviso dinamico virtuale che viene sempre mappato nello spazio degli indirizzi di un processo amd64 in Linux. Può essere utilizzato per implementare chiamate di sistema rapide. Per accedere alle funzioni all'interno dell'oggetto vDSO, è necessario
- individuare l'oggetto
- estrarre un indirizzo dalla tabella dei simboli
Entrambe le cose possono essere fatte con l'implementazione di riferimento con licenza CC0 parse_vdso.c.