9

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?

fuz
  • 88,405
  • 25
  • 200
  • 352
  • Out of curiosity, what is your language that don't use the *C* interface for syscalls? Do you provide a free software implementation for it? – Basile Starynkevitch Mar 24 '13 at 19:54
  • @Basile I try to write a Forth to learn how Forth works. I want to program in assembly without any existing libraries, similar to [jonesforth](http://git.annexia.org/?p=jonesforth.git). The VDSO object is just a nice and efficient way to implement system calls. – fuz Mar 24 '13 at 20:06

2 Answers2

8

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..)

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • I try to implement a runtime library for a programming language, without using any parts of the glibc. I need to primitives for the system calls that wrap the bare instructions. I'd like to use VDSO for speed as it uses the fastest method available to execute a system call. – fuz Mar 24 '13 at 20:01
  • Then, design and implement it first, and optimize it later. VDSO is an optimization, and not really important in practice, especially in a new programming language (most programs are not syscall-bound but user-CPU or IO-bound), so VDSO don't matter much. AFAIK, statically linked binaries (even in C) are not using the VDSO, even if it stays in their address space. – Basile Starynkevitch Mar 24 '13 at 20:07
  • Your answer and your comment do not address any of my questions. It's terribly unhelpful if I ask "Howto A" and the answer is basically "Do A later". – fuz Mar 24 '13 at 20:11
  • The VDSO is a magic ELF shared library using the C ABI conventions. The only issue is to find names there, but these are probably standard ELF tables. I don"t understand what is your issues, but I do believe you could avoid using VDSO if you feels it is too complex. – Basile Starynkevitch Mar 24 '13 at 20:14
  • If I'd like to avoid the VDSO object, I probably hadn't asked this question. The VDSO object is there to provide the fastest kernel calling convention for the current processor (amd64, for instance, has multiple ways to call the kernel). I want to know what I need to pass to the linker to use it, what kind of calling convention it has, etc. – fuz Mar 24 '13 at 20:19
  • As I edited in my answer, you need to understand the details of the ELF format, and of the x86-64 ABI conventions (notably calling C functions). All of this is very well documented, but is tricky to grasp. – Basile Starynkevitch Mar 24 '13 at 20:27
  • Thank you for the additional info. I understand how ELF's work. Is that object guaranteed to sit at the range you told me? What do I have to do to get my symbols resolved against linux-VDSO.so? What are the names of the symbols in that object? What is the calling convention? – fuz Mar 24 '13 at 20:31
  • I edited my answer to reply. You'll need to read a lot of material (I did read them 10 years ago, but forgot the details). Are you sure it is worth the pain? – Basile Starynkevitch Mar 24 '13 at 20:51
  • 1
    One important point of this is that I really want to understand the fundamental details of how Linux works. Of course I am masochistic! Otherwise I'd never asked that question. – fuz Mar 24 '13 at 20:56
  • 1
    I haven t understood one thing. You said that the vsdo is locate at the address : 0xffffffffff600000, but /proc/self/maps shows that the elf file located at that address is called vsyscall. Whereas the vsdo is located at 0x7fff3f173000. What the difference between these two objects? – Giuseppe Pes Jun 17 '13 at 12:49
  • +1 for musl link. It's definitely a lot more obvious what they're doing. You have to `objdump` glibc to understand what it's doing at all. – S.S. Anne Mar 22 '19 at 01:02
6

I found these files in the Linux kernel tree helpful:

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

  • locate the object
  • extract an address from the symbol table

Both things can be done with the CC0 licensed reference implementation parse_vdso.c.

Community
  • 1
  • 1
fuz
  • 88,405
  • 25
  • 200
  • 352