Recent Linux kernels (at least on amd64) provide a magic object file called linux-vdso.so.1
that abstracts away the syscall interface to the kernel, allowing the kernel to choose the optimal calling convention. If you write code in C, the glibc automatically uses this object.
Now, if I want to write a program without using the glibc, how can I use this object? Is the interface it provides documented somewhere? What about the calling convention?
I found these files in the Linux kernel tree helpful:
Documentation/ABI/stable/vdso
(what is the vDSO object?)Documentation/vDSO/parse_vdso.c
(Reference parser for the vDSO object)The vDSO object is a virtual dynamic shared object that is always mapped into the address space of an amd64 process under linux. It can be used to implement quick system calls. To access the functions inside the vDSO object, you need to
Both things can be done with the CC0 licensed reference implementation parse_vdso.c.
It depends if your implementation is using C interface for low level utilities or not.
If your language implement gives direct access to syscalls without going thru the C wrapper you don't need to use VDSO (you could for instance generate the appropriate SYSENTER
machine instruction to do the syscall), but you could decide to use VDSO and then take advantage of it. In that case, your language don't even need to follow the all the ABI conventions, just the conventions of the kernel. (for instance, you don't need the ABI provided caller-safe calle-safe distinguo on registers, and you could even avoid using any stacks).
An example of language implementation not even using libc.so
is Bones Scheme. You could find a few others.
My understanding of the VDSO is that it is an abstraction, provided by the kernel, to abstract away the various small differences (related to user-land -> kernel transitions) in implementing syscalls, between various families of x86 processors. If you have chosen a particular processor target, you don't need VDSO, and you can always avoid it.
AFAIU, the VDSO is an ELF shared object, sitting (on my Debian/AMD64 with a recently compiled 3.8.3 kernel) in the segment ffffffffff600000-ffffffffff601000
; check exactly with cat /proc/self/maps
where it is). So you just need to understand the organization of ELF shared objects and retrieve the symbols from it. See this & that links. The VDSO uses the C conventions for calling documented in the x86-64 ABI specification.
That is, if you extract from your process space the VDSO and write it on a disk file, the result is a well formed ELF shared object
ELF is a well documented format. And so is the x86-64 ABI conventions
(which defines precisely the C calling conventions, and how exactly a process' image starts. See also execve(2)) man page, and of course the kernel documentation, so I don't understand what is your issue. I agree that understanding ELF takes time (I did that 10 years ago, but my memory is rusty). Read also the <elf.h>
header file on your machine.
For instance; running (under zsh
on 64 bits 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]
See also this answer.
You probably want inside your runtime a minimal version of a dynamic linker able to simply parse the VDSO. You certainly want to understand the exact state in which a process is started, and in particular the role of auxv
, the auxiliary vector (I really forget these details, but I remember that they are important). See e.g. this article
Actually, starting reliably your runtime is probably harder than the VDSO issue.
You may also want to read the linux assembly howto which also explains some things (but more about x86 than x86-64)
BTW,the code of http://musl-libc.org/ (which is an alternative libc) is much easier to read and understand (and you'll learn easily how they do dynamic linking, pthreads, etc..)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With