Shared libraries without a MMU
Posted: Wed Sep 04, 2024 12:16 pm
I am presently designing a small operating system for small computers. Since small computers don't have a lot of RAM, the system has to optimize for memory usage. One of the ways it does so is by sharing code common to different processes by means of shared libraries.
As I understand it, the immutable parts of a library, the .text segments seem mostly straightforward to share: it is only a question of adjusting addresses depending on the location where the library is loaded. The sharing of the mutable parts is complicated by the fact that each process has to have its own copy of it. If not, the processes that import the same library could read and write the same global variable and locks would have to be implemented to prevent race conditions, something I would rather not like to do. But if the mutable segments are at different places depending on the current process, a mechanism needs to be implemented that permits each library to know where are its mutable segments for the current process. With CPUs that have a Memory Management Unit (MMU), this is not a big problem: particular mapping schemes can give the illusion to the code present in each library that its global variables are always in the same place no matter the process in activity. But since the computers I target don't all have a MMU, I cannot rely on it to implement shared libraries.
So my question is: How to implement a shared library so that it can find the instances of its global variables that are pertinent to the current process in computers that don't have a MMU?
For example: Without the help of a MMU, how can the global variable errno have different value for each process that use libc if libc is a shared library.
A maybe important note: I plan to use a dialect of the Forth programming language that uses indirect threading, this means that the code is essentially a list of addresses of subroutines, the majority of which will pertain to shared libraries. For this reason, ideally, library calls would not suffer a too high penalty. Also, shared libraries will use other shared libraries recursively.
As I understand it, the immutable parts of a library, the .text segments seem mostly straightforward to share: it is only a question of adjusting addresses depending on the location where the library is loaded. The sharing of the mutable parts is complicated by the fact that each process has to have its own copy of it. If not, the processes that import the same library could read and write the same global variable and locks would have to be implemented to prevent race conditions, something I would rather not like to do. But if the mutable segments are at different places depending on the current process, a mechanism needs to be implemented that permits each library to know where are its mutable segments for the current process. With CPUs that have a Memory Management Unit (MMU), this is not a big problem: particular mapping schemes can give the illusion to the code present in each library that its global variables are always in the same place no matter the process in activity. But since the computers I target don't all have a MMU, I cannot rely on it to implement shared libraries.
So my question is: How to implement a shared library so that it can find the instances of its global variables that are pertinent to the current process in computers that don't have a MMU?
For example: Without the help of a MMU, how can the global variable errno have different value for each process that use libc if libc is a shared library.
A maybe important note: I plan to use a dialect of the Forth programming language that uses indirect threading, this means that the code is essentially a list of addresses of subroutines, the majority of which will pertain to shared libraries. For this reason, ideally, library calls would not suffer a too high penalty. Also, shared libraries will use other shared libraries recursively.