position independant kernel
position independant kernel
Hi All,
I'm currently trying to get a clearer understanding of gcc compiler options and found the -pic (Position Independant Code) option. As my os i solely 64-bit longmode this might be a good option for my kernel to be compiled with. Is somebody of you also using this option ? and can somebody explains the cons and pros?
thanx in advance
I'm currently trying to get a clearer understanding of gcc compiler options and found the -pic (Position Independant Code) option. As my os i solely 64-bit longmode this might be a good option for my kernel to be compiled with. Is somebody of you also using this option ? and can somebody explains the cons and pros?
thanx in advance
Author of COBOS
I was under the impression all GCC code was already position independent (how else could it link anywhere into the final executable)
PIC, simply means you can run the code from anywhere in memory with the same results... Pros. you can stick the kernel where u like, cons, it is slightly slower because of the use of the base register solely for making hte code PIC. As i said though, i don't see how code could not always be PIC, or it wouldn't link...
PIC, simply means you can run the code from anywhere in memory with the same results... Pros. you can stick the kernel where u like, cons, it is slightly slower because of the use of the base register solely for making hte code PIC. As i said though, i don't see how code could not always be PIC, or it wouldn't link...
No, it's sort of like "position fixable" - it outputs a list of locations you have to add its own location to after placing it. Position independant code doesn't need fixing up.Tyler wrote:I was under the impression all GCC code was already position independent (how else could it link anywhere into the final executable)
Normally one compiles into objects which are relocatable, and then the linker "relocates" those at certain address, and gets rid of the relocation information. If we are compiling shared libraries, it however leaves this information into the library, so that it can be relocated at load time instead.
The downside is that if we load the same shared library in several processes, but at different addresses, we need two copies of the library in memory, because different relocations need to be done for each. Position independent code solves this by writing such code that we don't need to relocate it, there for allowing the same copy to be shared, saving memory.
The solution is to collect all the addresses that need relocation into a single table called GOT (global offset table) and write code that always gets the addresses from that table. That way you only need to relocate the table, and and rest of the pages can be shared. This ofcourse adds some overhead, and the GOT address is kept in a register (ebx or ebp, can't remember) so you also lose one of those. As it is, there are some issues with x86, having to do with the lack of EIP relative addressing.
That basicly means that you can't have PIC kernel, because you need some support code for PIC to work. You could theoretically make it work, but you'd need your bootloader to do the relevant relocations for you, and it's most definitely not worth the trouble.
The downside is that if we load the same shared library in several processes, but at different addresses, we need two copies of the library in memory, because different relocations need to be done for each. Position independent code solves this by writing such code that we don't need to relocate it, there for allowing the same copy to be shared, saving memory.
The solution is to collect all the addresses that need relocation into a single table called GOT (global offset table) and write code that always gets the addresses from that table. That way you only need to relocate the table, and and rest of the pages can be shared. This ofcourse adds some overhead, and the GOT address is kept in a register (ebx or ebp, can't remember) so you also lose one of those. As it is, there are some issues with x86, having to do with the lack of EIP relative addressing.
That basicly means that you can't have PIC kernel, because you need some support code for PIC to work. You could theoretically make it work, but you'd need your bootloader to do the relevant relocations for you, and it's most definitely not worth the trouble.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
And that is why i have a 64-bit AMD64/EM64T environment. It does support RIP relative addressing, thus the whole GOT/relocation scheme is not used. As a test i displaced all the code/data below 1MiB with an offset of 1MiB and made a jump with the folowing inline assembly.mystran wrote:The solution is to collect all the addresses that need relocation into a single table called GOT (global offset table) and write code that always gets the addresses from that table. That way you only need to relocate the table, and and rest of the pages can be shared. This ofcourse adds some overhead, and the GOT address is kept in a register (ebx or ebp, can't remember) so you also lose one of those. As it is, there are some issues with x86, having to do with the lack of EIP relative addressing.
That basicly means that you can't have PIC kernel, because you need some support code for PIC to work. You could theoretically make it work, but you'd need your bootloader to do the relevant relocations for you, and it's most definitely not worth the trouble.
Code: Select all
asm volatile("movq $lp, %rax; addq $0x100000, %rax; jmp *%rax; lp:");
![Wink ;-)](./images/smilies/icon_wink.gif)
Author of COBOS
Well you still need something like a GOT for a shared library to handle it's imported symbols, but IP relative addessing saves you a register..os64dev wrote: And that is why i have a 64-bit AMD64/EM64T environment. It does support RIP relative addressing, thus the whole GOT/relocation scheme is not used. As a test i displaced all the code/data below 1MiB with an offset of 1MiB and made a jump with the folowing inline assembly.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
AFAIK they just allow you to link the kernel to different addresses.Tyler wrote:Does anyone know how Linux, Windows/ReactOS allow different kernel loading positions... do they use relocations or PIC?
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
And the rest of the binaries?
Isn't ELF designed to be dynamically linked to any address by using relocation?
Yes, maybe that doesn't apply to the kernel itself, but whenever one uses an ELF and knows how to relocate its binary image, it can be done, but maybe that would require a complex boot loader (more than a bootstrap), one that contains a decent "dynamic program loader".
But at that point, I guess the relocated image would become "static" for that system run.
Isn't ELF designed to be dynamically linked to any address by using relocation?
Yes, maybe that doesn't apply to the kernel itself, but whenever one uses an ELF and knows how to relocate its binary image, it can be done, but maybe that would require a complex boot loader (more than a bootstrap), one that contains a decent "dynamic program loader".
But at that point, I guess the relocated image would become "static" for that system run.
No idea how Windows works. Maybe they relocate in loader, who knows. They could even do the link at load time if they wanted.Tyler wrote:So Windows comes with all versions of the kernel at 2Gb and 3Gb?mystran wrote:AFAIK they just allow you to link the kernel to different addresses.Tyler wrote:Does anyone know how Linux, Windows/ReactOS allow different kernel loading positions... do they use relocations or PIC?
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
Hi,
For e.g:
For a 64-bit system the address space is larger and the CPU practically forces you to have a hole in the middle of it. In this case it makes a lot of sense to have 131072 GB of user space and 131072 GB of kernel space, and there isn't much point allowing SOMEWHERE to be changed.
For 32-bit systems there's only one reason I can think of for considering using position independant code for the kernel - you might want to run kernel code before you setup paging. To be honest I've never liked this idea much (seems too much like rushing to write a kernel and skipping all the boot code and preperation). For 64-bit systems this isn't really an option - you can't run 64-bit code without paging.
Cheers,
Brendan
I've no idea how Windows does it, but I'd assume it'd be easier to statically link the kernel and always load it at a high address (like 0xF8000000). If the start of kernel space can be relocated, then the space between the start of kernel space and the kernel's code can still be shifted.Tyler wrote:So Windows comes with all versions of the kernel at 2Gb and 3Gb?
For e.g:
- 0x00000000 to SOMEWHERE User-space
SOMEWHERE to 0xF0000000 Space for dynamicaly allocated kernel data
0xF8000000 to 0xFFFFFFFF Space for kernel code and statically allocated kernel data
For a 64-bit system the address space is larger and the CPU practically forces you to have a hole in the middle of it. In this case it makes a lot of sense to have 131072 GB of user space and 131072 GB of kernel space, and there isn't much point allowing SOMEWHERE to be changed.
For 32-bit systems there's only one reason I can think of for considering using position independant code for the kernel - you might want to run kernel code before you setup paging. To be honest I've never liked this idea much (seems too much like rushing to write a kernel and skipping all the boot code and preperation). For 64-bit systems this isn't really an option - you can't run 64-bit code without paging.
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.