Dynamic linking subsystem (call gates, etc)
Posted: Sun Feb 27, 2005 12:00 am
I've been reading a lot about os development over the last few years and took a quick stab at writing a simple realmode os a while ago. I think I'm about ready to get back to coding and have a few little ideas in mind for system design and so forth. Specifically I've been thinking a lot about conventions for dynamic linking and system calls lately and wanted to run an idea across y'all. I'm wondering is anyone out there has similar ideas and if its ever been done before...
The rest of this article outlines the said dynamic linking convention and is somewhat technical...
First, Shared Libraries and eXecutables would share a common proprietary format (call it the SLX format) which would allow it to:
1. Export functions to other processes (ie: be a shared lib)
2. Define and export a "main" function (ie: be an executable)
3. Call to previously loaded libraries (or trigger other libraries to be loaded on the fly) via an embedded link-table and patch table
The link table would be a list of module names and procedure names. For example:
0> cli.slx, writeln
1> kernel.slx, exit
The patch table would contain offsets into the binary image where FAR CALL instructions are located which need to be resolved by the loader. The FAR CALL itself would identify the desired module/procedure in the link table. For example:
.data
msg db 'hello world',0
.code
push offset msg
push seg msg
call far 0:0
call far 0:1
Obviously this is a messy example but you get the idea. The loader looks at the link table, ensures that the nessisary modules are loaded, creates a trap gate descriptor on the app's LDT for the call, looks at the patch table and fixes each FAR CALL with the appropiate trap gate selector.
In this system no dispatcher is needed in the OS or in the libraries. Functions are called directly, through a trap gate. This convention would also be used for system calls as well (except the created call gate would contain a privilage level change). The trap gate will be built with information stored in the CALLEE (not the caller). The number of parameters copied would be specified by the export table in the callee for each specific exported function. For shared libraries calling each-other in ring 3 I think calls could all occur without a context switch right? This would limit context switches to only occur only when a call is made from ring 3 to ring 0 (IE: a system call).
This should significantly increase call speeds between libraries and the system compaired to systems that use dispatch routines and jump tables at runtime right?
In this system, each app with get it's own LDTs which will be filled with trap gates for each external procedure needed. I can't imagine any case where an app would need access to more then 8000 some-odd external procedures but apps would be limited to the number of descripters an LDT can store. Would this be an issue?
Is there something I'm not seeing here?
-Robert
The rest of this article outlines the said dynamic linking convention and is somewhat technical...
First, Shared Libraries and eXecutables would share a common proprietary format (call it the SLX format) which would allow it to:
1. Export functions to other processes (ie: be a shared lib)
2. Define and export a "main" function (ie: be an executable)
3. Call to previously loaded libraries (or trigger other libraries to be loaded on the fly) via an embedded link-table and patch table
The link table would be a list of module names and procedure names. For example:
0> cli.slx, writeln
1> kernel.slx, exit
The patch table would contain offsets into the binary image where FAR CALL instructions are located which need to be resolved by the loader. The FAR CALL itself would identify the desired module/procedure in the link table. For example:
.data
msg db 'hello world',0
.code
push offset msg
push seg msg
call far 0:0
call far 0:1
Obviously this is a messy example but you get the idea. The loader looks at the link table, ensures that the nessisary modules are loaded, creates a trap gate descriptor on the app's LDT for the call, looks at the patch table and fixes each FAR CALL with the appropiate trap gate selector.
In this system no dispatcher is needed in the OS or in the libraries. Functions are called directly, through a trap gate. This convention would also be used for system calls as well (except the created call gate would contain a privilage level change). The trap gate will be built with information stored in the CALLEE (not the caller). The number of parameters copied would be specified by the export table in the callee for each specific exported function. For shared libraries calling each-other in ring 3 I think calls could all occur without a context switch right? This would limit context switches to only occur only when a call is made from ring 3 to ring 0 (IE: a system call).
This should significantly increase call speeds between libraries and the system compaired to systems that use dispatch routines and jump tables at runtime right?
In this system, each app with get it's own LDTs which will be filled with trap gates for each external procedure needed. I can't imagine any case where an app would need access to more then 8000 some-odd external procedures but apps would be limited to the number of descripters an LDT can store. Would this be an issue?
Is there something I'm not seeing here?
-Robert