Mit "Datei" meine ich die ASM-Datei, in der du den Quellcode hast. Dort sind alle Symboladressen (also Adressen von Funktionen, Variablen, ...) bekannt.
Wenn du FUNKTION.ASM hast und du definierst dort Funktionen, dann weiß die Datei KERNEL.ASM nicht, wo diese Funktionen innerhalb der FUNKTION.ASM liegen. Das unter der Annahme, dass du beide Binärdateien (FUNKTION.BIN und KERNEL.BIN) in verschiedene Segmente lädst. Um eine solche Funktion aufzurufen, brauchst du also zwingend die absolute, vollständige Adresse der Funktion. Und die ist deinem Kernel nicht bekannt.
Daher nutzt man ja auch den Weg über SYSCALLs (wie die implementiert sind, ist egal); dort übergibt man in der Regel eine Funktionsnummer, die vorher definiert ist. Die Adresse der Funktion wird dann entweder aus einer Tabelle nachgeschlagen oder, wie im folgenden Beispiel, direkt ausgewertet.
Mit Adressen meine ich die Einsprungadressen in Funktionen (bzw. die Speicheradressen, wo man mit CALL oder JMP hinkann).
In der IVT registrierst du jeden Interrupt mit einem Handler (= eine Funktion). Da drin kannst du z.B. je nach Registerzustand die gewünschte Funktion unterscheiden. Die Funktionsnummer wird also in AX übergeben, eine eventuelle Unterfunktionsnummer in BX. Wie du das genau machst, bleibt natürlich dir überlassen - in jedem Fall sieht so deine SYSCALL-Schnittstelle aus.
Die Funktionsnummern bleiben aus Kompatiblitätsgründen konstant; die FreeBSD-Linux-Emulation basiert darauf, dass die Funktionsnummern in Linux-Binaries dynamisch durch die (meist kompatiblen) FreeBSD-Funktionsnummern ersetzt werden. Darum ist das keine Simulation, sondern ein "natives" ausführen.
Als Beispiel etwa so (formuliert in C):
void int21_handler(int ax, int bx, int cx, int dx)
{
if( ax == 0 ) { ...putstr... };
if( ax == 1 ) { ...readstr... };
if( ax == 2 ) /* videofunktionen */
{
if( bx == 0 ) { ...setze videomodus... };
if( bx == 1 ) { ...zeichne pixel... };
}
}
Gruß,
Svenska