Page 1 of 1

Creating relocatable shared library

Posted: Sat Mar 28, 2009 5:46 am
by xenos
Hey guys,

I've spent some time thinking about this, but I still could not figure out how to solve it. I'd like to write shared libraries for my OS (using ELF), but as opposed to shared libraries on Linux systems, they should not be position independent, but relocatable. (I.e. they should neither have a GOT through which addresses are routed, nor a PLT.) The reason for this choice is that PIC always has some overhead routing everything through the GOT and wastes a register to store the GOT address. Relocatable code needs some more work relocating it at load time, but results in faster executables at run time.

So, what I need to create is some ELF file that does not contain GOT or PLT sections or any other sections related to them. However, I still need dynamic linking information, like a table of exported symbols. These should be stored in a .dynsym section, as it would be in any other shared library. I also need .dynstr and .dynamic sections, to store dynamic function names, module names and things like DT_INIT and DT_FINI functions. And of course I need relocation sections. (There are some libraries that will be mapped to a fixed location in every address space, like a library with kernel services, that encapsulates the kernel interface. These libraries can be linked at a fixed location and don't need to be relocated at load time, but they still need sections for dynamic linking of executables against them.)

My questions are:
  • How do I create such a library, that contains all these sections for dynamic linking, but without GOT, PLT and such?
  • How do I specify what has to be relocated at load time? Is the --emit-relocs option sufficient? It looks quite unspecific. Do I have to relocate everything that has been relocated at link time, or does linking the source files into a shared library already resolve some relocations, that don't have to be re-done when the library is loaded? Does --emit-relocs or --relocatable put any "unneeded" relocations into the library?
  • How do I tell my compiler / linker which functions / objects should be exported (i.e. placed in .dynsym), and which should not? (Without giving something like a visibility attribute to every function that should not be exported - there will be a lot more of them than exported functions, so not exporting the function is the default.)
  • How do I link an executable against such a library? Of course, I know how to do the dynamic linking at load time - I just check the DT_NEEDED entries in my executable, load the required libraries, look up any symbols and perform relocations. But how do I get all this dynamic linking stuff into my executable? How do I specify which libraries are needed?
I'm using GCC and Binutils (cross configured with target i686-pc-elf or x86_64-pc-elf) under CygWin.

Thanks in advance!

Re: Creating relocatable shared library

Posted: Sun Mar 29, 2009 4:33 pm
by JohnnyTheDon
Try the -r switch. It produces relocatable (not position independent) output. You can then link the program for a specific address at runtime. you can even use ld to do this for you :)

The problem you will quickly run into is that mapping the same file in multiple programs (one of the main advantages of shared objects) won't work. After you link for one program you will have to link again at a different address when another program tries to load the shared object.

There are other ways to implement shared objects without position independent code. You may want to take a look at how Windows DLLs do it.

If you're making a 64-bit OS, you should be aware x86_64 includes RIP relative addressing. Because everything can be addressed relative to the instruction pointer, there is very little overhead to position independent code.

Re: Creating relocatable shared library

Posted: Mon Mar 30, 2009 2:06 am
by xenos
Indeed, the -r switch was one of the first things I tried, and I get a relocatable object. OK, that's fine. But that way I don't get any sections for dynamic linking (.dynamic, .dynsym, .dynstr) into my output file... I tried -shared, which gives me the sections I need - and in addition a section named .got.plt. I'm not sure whether I can just safely strip that, but I'll give it a try. I also tried using both -r and -shared, but that doesn't work. However, if I use -q together with -shared, I get relocations + dynamic sections.

I also had a look at the Windows DLL approach and I think it's not that different from mine. The main difference is that my OS there is a reserved region for dynamic libraries, that is shared by all processes. So once a library is loaded, it resides at the same address in every adress space and needs to be relocated only once. The actual relocation is quite similar to the way Windows handles it - the library is simple relocated to some free chunk of virtual memory.

The only point where this approach might run into trouble is when I'm running out of virtual memory - but since one of the main guidelines of my OS is small, efficient code, that shouldn't happen too soon. I guess I should mention that my libraries are pure code, without any shared or per-process data, so they are read-only for any process that uses them.

Of course instruction pointer relative addressing makes PIC very simple and requires less overhead, but there don't seem to be many architectures that support it. Well, I could use it for x86_64, but since I'm also targetting other archtectures, my preferred solution is to circumvent PIC as far as possible.