Page 1 of 1

Modules

Posted: Fri Jun 14, 2002 7:16 am
by FlashBurn
I would like to know how do I make modules and how do I use modules . I would be very good if you can give me some example code . I know that there are functions in a module , but how can I figure out which functions are in a module and how can I call these functions .

Re:Modules

Posted: Fri Jun 14, 2002 10:43 am
by Tim
By 'modules', do you mean executable files or libraries that you can load and execute? You need to get a copy of the relevant file format spec, e.g. ELF or PE. See http://www.nondot.org/sabre/os/articles ... leFormats/.

Re:Modules

Posted: Fri Jun 14, 2002 2:41 pm
by FlashBurn
With modules I mean files like the drivers . And I have no idea how I could write a file that can say me what functions it has and as I said , I can not imagine how I could call these functions .

Re:Modules

Posted: Fri Jun 14, 2002 6:19 pm
by Tim
OK... loading modular drivers into your kernel can be the same thing as loading DLLs into your user apps, just at a different address. I'll describe PE because I know that format better, although the principles will be almost the same for ELF.

The file on disk (executable, DLL or driver) is more-or-less the same as the memory image. It consists of a set of headers and some sections; sections are just chunks of code, data, etc.. One section (called .text) contains code, another (.data) contains initialised global data, and another (.bss) contains uninitialsied global data.

For example

Code: Select all

int this_goes_in_bss;
int this_goes_in_data;
int this_goes_in_text()
{
    return 42;
}
There are two general ways of loading a module: explictly and demand paging. With explicit loading, the loader will read the headers and each section from disk into memory and start running the code. With demand loading, the loader will set up a structure in memory so that it knows that this module is loaded, and it starts running the code; nothing is actually loaded yet. Inevitably, the code will page fault, because there is nothing there; at this point, the loader checks its list of modules, realises that there should be something mapped to that page, loads that page from disk, and continues.

The code in this case is the machine opcodes that the compiler emits; the data is the various global variables the program uses, appended to each other into one block (local variables are stored on the stack).

ELF and PE both support dynamic linking; that is, you can load a module and ask it for a specific function. PE supports this with an export table, which consists of a list of names and addresses. When asked for a particular function, the loader just walks the list of names and returns the appropriate address. I'm sure ELF does it similarly, but I'll have to leave it to someone else to fill in the details here, since I've never written an ELF loader.

Re:Modules

Posted: Mon Jun 17, 2002 12:33 pm
by Pype.Clicker
In order to have modules, your kernel must implement a (more or less complicated) symbolic-name-to-function-address mapper. It can be very simple (v2os simply uses a byte as symbolic name :) or very complicated (my OS has a hierarchical name resolver and has symbols like "ksyms.print" registered).

Each module will come with a list of requirements (the symbols it expects to find), which it can either lookup in the table everytime it needs it like :
function[KERNEL_PRINT]("hello world")
or rely on the module loader to perform relocation on each call, so that you simply write kprint("hello world") and expect the module maker/loader tools to find out it's a reference to the KPRINT function exported by the kernel, look it up and replace call 0x000000 by call @kprint in your machine code at load time.

So basically, your module is simply an executable file with enough symbolic information to let it be linked into the running system. A trivial module format could be to have an mod_init(void **fptr) function starting at offset 0 of your file and that will receive a pointer to the symbol table that it can read/write to link against the system.

ex (Very Simple Module Format):
#include <symbols.h>
void (*kprint)(char*);
int mod_init(void **fptr)
{
if ((kprint=fptr[KERNEL_PRINT]) &&
(!fptr[HELLO_WORLD]) {
fptr[HELLO_WORLD]=hello;
return SUCCESS;
} else return FAIL;
}

hello() {
kprint("hello world\n");
}

Note that this means every symbol must be assigned an unique ID (KERNEL_PRINT, HELLO_WORLD, ...).