From what I've seen of Windows and Linux in my research for my OS, there seems to be two ways that an executable is loaded and relocated.
One is completely in the kernel, where the image is loaded and relocated in kernel level code (I think windows does it this way).
The other is where the kernel does the bare minimum required to load the image and passes the relocation to a userland library / program to do (E.g. ld-linux.so)
I was wondering what ways you guys do this and what you think is the best.
Personally I started by having the relocation done in the kernel but I've just completed a move to user-mode relocation to improve the stability of my kernel.
Edit: P.S. I put the "Theory Discussion: " in to differentiate this from a question of what I should do.
Theory Discussion: Where to put Executable Relocation
- thepowersgang
- Member
- Posts: 734
- Joined: Tue Dec 25, 2007 6:03 am
- Libera.chat IRC: thePowersGang
- Location: Perth, Western Australia
- Contact:
Theory Discussion: Where to put Executable Relocation
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Re: Theory Discussion: Where to put Executable Relocation
I would agree with that. My view is do as much as possible in userland, without compromising security.thepowersgang wrote:Personally I started by having the relocation done in the kernel but I've just completed a move to user-mode relocation to improve the stability of my kernel.
For example - you wouldn't do the task creation in userland, because that would mean allowing user code to manipulate PCB's and paging structures. Executable loading and relocation, however, can be done by standard system calls.
Cheers,
Adam
-
- Member
- Posts: 2566
- Joined: Sun Jan 14, 2007 9:15 pm
- Libera.chat IRC: miselin
- Location: Sydney, Australia (I come from a land down under!)
- Contact:
Re: Theory Discussion: Where to put Executable Relocation
You could take that to the next level and have an individual loader for each file format; it'd mean that you could easily support any number of file formats by just writing a new loader for it (which is even something that can be done by the community).Executable loading and relocation, however, can be done by standard system calls.
Re: Theory Discussion: Where to put Executable Relocation
meinOS does exactly that. Actually I have only ELF at the moment, but I designed the loader so that it is easy extensible. Also in meinOS almost everything is done in userspace. When you call any of the exec*() functions (I have the POSIX exec functions) it does a RPC call to the init process which then reloads the process image from the file and resets EIP. Of course working with other processes' memory and registers is only allowed by a init.
Re: Theory Discussion: Where to put Executable Relocation
So far, I have found that the mechanism of process/task/thread creation is too complex and subtle to just cram it into a userspace library conveniently.
Currently, my "loader" is a submodule of my scheduler. And depending on your definition, you could say that my scheduler is a piece of my kernel. The thing is, creating a new "task" must certainly be handled by the kernel/scheduler. But that mostly involves the concept of threads -- not processes. So the question becomes: in your OS, how are processes different from threads? One way, usually, is that processes get loaded as images off of disks -- whereas threads are forked from images that are already running in memory. But there are many other factors. CPU affinity, BSS allocation and clearing, task cleanup on exit(), etc. In my OS, I seem to be finding that I really want to have two slightly different types of loading done -- one creates a brand new independent process, and one that loads a semi-independent process into the address space of an already existing process.
So, in my OS, this seems to make "process loading" too annoying and inefficient to try to do in userspace, when it can be simply and easily done by the scheduler, in kernelspace.
Currently, my "loader" is a submodule of my scheduler. And depending on your definition, you could say that my scheduler is a piece of my kernel. The thing is, creating a new "task" must certainly be handled by the kernel/scheduler. But that mostly involves the concept of threads -- not processes. So the question becomes: in your OS, how are processes different from threads? One way, usually, is that processes get loaded as images off of disks -- whereas threads are forked from images that are already running in memory. But there are many other factors. CPU affinity, BSS allocation and clearing, task cleanup on exit(), etc. In my OS, I seem to be finding that I really want to have two slightly different types of loading done -- one creates a brand new independent process, and one that loads a semi-independent process into the address space of an already existing process.
So, in my OS, this seems to make "process loading" too annoying and inefficient to try to do in userspace, when it can be simply and easily done by the scheduler, in kernelspace.
- thepowersgang
- Member
- Posts: 734
- Joined: Tue Dec 25, 2007 6:03 am
- Libera.chat IRC: thePowersGang
- Location: Perth, Western Australia
- Contact:
Re: Theory Discussion: Where to put Executable Relocation
Just elaborating on what I do.
The kernel handles loading the binary from disk into memory (using the ELF program header for example) but then the complex relocation is done by a user mode library (ld-acess.so or ld-acess.dll depending on the format) called by the kernel.
This allows the kernel to cache executable images in global memory while still keeping the complex, and hence less stable, operations in used mode.
The kernel handles loading the binary from disk into memory (using the ELF program header for example) but then the complex relocation is done by a user mode library (ld-acess.so or ld-acess.dll depending on the format) called by the kernel.
This allows the kernel to cache executable images in global memory while still keeping the complex, and hence less stable, operations in used mode.
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Re: Theory Discussion: Where to put Executable Relocation
Just wondering does the kernel parse the ELF program header to figure out where to load the file and where to put the sections or does the user mode library do that. Because if all the parsing of the header is already done in the kernel why not go ahead and do the relocations in the kernel? It seems that you are moving one of the simpler parts out of the kernel.thepowersgang wrote:
The kernel handles loading the binary from disk into memory (using the ELF program header for example) but then the complex relocation is done by a user mode library (ld-acess.so or ld-acess.dll depending on the format) called by the kernel.
You would also need to alter the kernel to be able to load any formats other than ELF.
- thepowersgang
- Member
- Posts: 734
- Joined: Tue Dec 25, 2007 6:03 am
- Libera.chat IRC: thePowersGang
- Location: Perth, Western Australia
- Contact:
Re: Theory Discussion: Where to put Executable Relocation
The kernel parses the simpler program header and leaves the complex (and error prone) stuff to the user land.
I know that I would need to alter the kernel to have native support for other formats, but this means that the kernel can easily cache the data when it's loaded (say caching the shell/browser)
I know that I would need to alter the kernel to have native support for other formats, but this means that the kernel can easily cache the data when it's loaded (say caching the shell/browser)
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Re: Theory Discussion: Where to put Executable Relocation
Unless you plan on spawning multiple shells over and over again I don't see how caching the entire object in kernel space would be all that useful. It seems like more of a waste of memory to me. You could simple use Copy On Write pages for the shell, then starting a new shell would be as easy as making a link to the old one's code and creating a new data area. Why cache something that's already in memory?
The letting a user space library do the relocations could be a good idea provided a few requirements are met. You would need a way to verify that the library can be trusted. You would have to protect the library from viruses. If the library was infected it could make every application run virus code by providing faulty relocations.
If you are talking about a "server" (like in microkernels) doing the relocation then it sounds like a better idea than having a "library" do it. You could allow add-on modules for different file types without requiring a rewrite of any kernel code.
The letting a user space library do the relocations could be a good idea provided a few requirements are met. You would need a way to verify that the library can be trusted. You would have to protect the library from viruses. If the library was infected it could make every application run virus code by providing faulty relocations.
If you are talking about a "server" (like in microkernels) doing the relocation then it sounds like a better idea than having a "library" do it. You could allow add-on modules for different file types without requiring a rewrite of any kernel code.