Page 1 of 1

dynamic symbol table in kernel

Posted: Tue May 14, 2013 2:09 pm
by dschatz
I'm attempting to build my kernel with the dynamic symbol table and hash table so that I can load modules efficiently into the kernel's address space. This is briefly explained at the bottom of this wiki page: http://wiki.osdev.org/LD

The idea is to build the kernel as a shared library, and resolve all symbols within the kernel. This will still leave the dynamic symbol table around. I've run into a problem for which I've created a minimal test case which fails:

tmp.c:

Code: Select all

int foo(const char* s)
{
  return 0;
}

int main()
{
  return foo("bar");
}
I build this using gcc -c (I've tried with both my cross compiler and the native toolchain). The relocatable object file has the following (from objdump -dr):

Code: Select all

000000000000000f <main>:
   f:	55                   	push   %rbp
  10:	48 89 e5             	mov    %rsp,%rbp
  13:	bf 00 00 00 00       	mov    $0x0,%edi
			14: R_X86_64_32	.rodata
  18:	e8 00 00 00 00       	callq  1d <main+0xe>
			19: R_X86_64_PC32	foo-0x4
  1d:	5d                   	pop    %rbp
  1e:	c3                   	retq   
I try to link it :

Code: Select all

CC -Wl,-Bsymbolic -Wl,-z,defs -Wl,-shared test.o
And the linker complains:

Code: Select all

relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
Why can't it relocate against the rodata section which should be in the resulting binary? Thanks

Re: dynamic symbol table in kernel

Posted: Tue May 14, 2013 2:19 pm
by jnc100
An ELF shared library is designed to be loaded at any address. Therefore static relocations (including R_X86_64_32) are not allowed at link time as the static linker (ld) does not know where the .rodata section will be loaded at run-time. If you want to build a dynamic object you have to do what it says, namely add the -fPIC option to the gcc compile line, which will generate relocations against the GOT instead. If you do this, your bootloader will need to patch up the relocations at load time.

There is, unfortunately, no way to ask ld to keep the hash table in a static binary (as I questioned on the binutils mailing list recently). You could do as the embedded linux guys do and perform post-hoc processing on the binary file e.g. here to add the hash table back again.

Regards,
John.

Re: dynamic symbol table in kernel

Posted: Tue May 14, 2013 11:14 pm
by xenos
Which memory model are you using? (Medium? Kernel?) Indeed the issue seems to be with the R_X86_64_32 type relocation. I also compile my kernel as a shared library, but without the -fPIC option and using the large memory model instead. The compiler then generates R_X86_64_64 type relocations instead, and these seem to work fine. (Of course the large memory model will cause some overhead, and the overhead using -fPIC instead may be smaller, since it can take advantage of RIP relative addressing on x86_64.)

Re: dynamic symbol table in kernel

Posted: Wed May 15, 2013 7:46 am
by dschatz
Thank you both for the helpful responses.

I'm using the default memory model, small. I tried building with mcmodel=large which solves the majority of the relocation problems but I run into a problem with my boot code, written in assembly. This makes several R_X86_64_32 relocations which fail. Many of these references are made before long mode and so they do in fact need to be 32 bit addresses.

Trying my small test with mcmodel=large shows that the linker is indeed able to resolve the address of the string "bar" into the code. Why do I need to set mcmodel for this? The gcc options say about mcmodel=small : "the program and its symbols must be linked in the lower 2 GB of the address space". Why then can't it resolve a 32 bit absolute address? The problem isn't that it doesn't know where the data sections will be loaded at run-time because if so then mcmodel=large should also fail. What is the real cause?