2013-03-24 15 views
6

I kernel Linux recenti (almeno su amd64) forniscono un file di oggetto magico chiamato linux-vdso.so.1 che astrae l'interfaccia di syscall al kernel, consentendo al kernel di scegliere la convenzione di chiamata ottimale. Se scrivi il codice in C, glibc usa automaticamente questo oggetto.Come sfruttare l'oggetto VDSO con il proprio linguaggio di programmazione?

Ora, se voglio scrivere un programma senza usare glibc, come posso usare questo oggetto? L'interfaccia che fornisce è documentata da qualche parte? Che mi dici della convenzione di chiamata?

+0

Per curiosità, qual è il tuo linguaggio che non usa l'interfaccia * C * per le syscalls? Fornisci un'implementazione software gratuita per questo? –

+0

@Basile Cerco di scrivere un Forth per sapere come funziona Forth. Voglio programmare in assembly senza alcuna libreria esistente, simile a [jonesforth] (http://git.annexia.org/?p=jonesforth.git). L'oggetto VDSO è solo un modo piacevole ed efficace per implementare le chiamate di sistema. – fuz

risposta

6

Dipende se l'implementazione utilizza C interfaccia per i servizi di basso livello o no.

Se la lingua consente di accedere direttamente alle chiamate di sistema senza passare attraverso il C involucro non è necessario utilizzare VDSO (si potrebbe per esempio generare l'istruzione di SYSENTER macchina adeguata per fare la chiamata di sistema). In quel caso, la tua lingua non ha nemmeno bisogno di seguire tutte le convenzioni ABI, solo le convenzioni del kernel. (per esempio, non è necessario che l'ABI fornisca distinguo sicuro per i chiamanti sicuro da calle sui registri, e si potrebbe persino evitare di utilizzare qualsiasi stack).

La mia comprensione del VDSO è che è un'astrazione, fornita dal kernel, per astrarre le varie piccole differenze (relative a user-land -> transizioni del kernel) nell'implementazione di syscalls, tra varie famiglie di processori x86. Se hai scelto un particolare target del processore, non hai bisogno di VDSO e puoi sempre evitarlo.

AFAIU, il VDSO è un oggetto ELF condiviso, seduto (sul mio Debian/AMD64 con un kernel 3.8.3 recentemente compilato) nel segmento ffffffffff600000-ffffffffff601000; controllare esattamente con cat /proc/self/maps dove si trova). Quindi devi solo capire l'organizzazione degli oggetti condivisi ELF e recuperare i simboli da esso. Vedi i link this & that. Il VDSO utilizza le convenzioni C per le chiamate documentate nella specifica ABI x86-64.

Cioè, se si estrae dal proprio spazio di elaborazione VDSO e scrivere su un file su disco, il risultato è un oggetto ELF condiviso ben formato

ELF è un formato ben documentato. E lo è anche lo x86-64 ABI conventions (che definisce con precisione le convenzioni di chiamata C e come esattamente l'immagine di un processo inizia. Vedere anche execve(2)) man page e, naturalmente, la documentazione del kernel, quindi non capisco qual è il problema. Sono d'accordo che la comprensione dell'ELF richiede tempo (l'ho fatto 10 anni fa, ma la mia memoria è arrugginita). Leggi anche il file di intestazione <elf.h> sul tuo computer.

Ad esempio; esecuzione (sotto zsh su 64 bit Debian x86-64)

% 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 this answer.

Probabilmente si desidera all'interno del proprio runtime una versione minima di un linker dinamico in grado di analizzare semplicemente VDSO.Certamente vuoi capire lo stato esatto in cui è stato avviato un processo, e in particolare il ruolo di auxv, il vettore ausiliario (ho davvero dimenticato questi dettagli, ma ricordo che sono importanti). Vedi per es. this article

In realtà, l'avvio affidabile del runtime è probabilmente più difficile del problema VDSO.

Si consiglia inoltre di leggere il linux assembly howto che spiega anche alcune cose (ma di più su x86 di x86-64)

BTW, il codice di http://musl-libc.org/ (che è un libc alternativa) è molto più facile da leggere e capire (e imparerete facilmente come lo fanno il collegamento dinamico, pthreads, ecc ..)

+0

Cerco di implementare una libreria runtime per un linguaggio di programmazione, senza utilizzare alcuna parte di glibc. Ho bisogno di primitive per le chiamate di sistema che avvolgono le istruzioni nude. Mi piacerebbe utilizzare VDSO per la velocità in quanto utilizza il metodo più veloce disponibile per eseguire una chiamata di sistema. – fuz

+0

Quindi, progettalo e implementalo per primo e ottimizzalo in seguito. VDSO è un'ottimizzazione, e non molto importante nella pratica, specialmente in un nuovo linguaggio di programmazione (la maggior parte dei programmi non sono collegati a syscall ma user-CPU o IO-bound), quindi VDSO non conta molto. AFAIK, i file binari collegati staticamente (anche in C) non stanno utilizzando il VDSO, anche se rimane nel loro spazio indirizzo. –

+0

La tua risposta e il tuo commento non rispondono a nessuna delle mie domande.È terribilmente inutile se chiedo "Howto A" e la risposta è fondamentalmente "Do A later". – fuz

4

a scavare internet ho trovato questo link

http://www.linuxjournal.com/content/creating-vdso-colonels-other-chicken

Penso che risponde alla tua domanda

+0

Questo articolo non aiuta affatto. Descrive come aggiungere un syscall a VDSO dal lato del kernel; non dice quasi nulla sul lato userland, eccetto come ottenere quell'oggetto se è già collegato (cosa che non avviene se compilo senza glibc). – fuz

+2

Il VDSO è magicamente collegato anche senza Glibc. Potresti capire come stanno gli altri Libc. Trovo il codice sorgente di http://musl-libc.org/ molto leggibile (più di Glibc che usa molti trucchi del preprocessore). –

+0

@Basile Compilare un file oggetto con -nostdlib e quindi eseguire ldd a.out per eseguire il dump delle librerie collegate; linux-vdso.so.1 non è elencato. (È se usi glibc). – fuz

4

ho trovato questi file nel kernel di Linux utili:

L'oggetto vDSO è un oggetto condiviso dinamico virtuale che viene sempre mappato nello spazio di indirizzi di un processo amd64 sotto Linux. Può essere utilizzato per implementare chiamate di sistema rapide. Per accedere alle funzioni all'interno dell'oggetto vDSO, è necessario

  • individuare l'oggetto
  • estratto un indirizzo dalla tabella dei simboli

Entrambe le cose possono essere fatte con l'attuazione CC0 di riferimento licenza parse_vdso.c.