Ich habe das bei meinem bootloader so gelöst, dass die Interrupts 0xF0-0xFF je eine Funktion entsprechen - das erlaubt zwar max 15 Funktionen, aber bisher komme ich gut damit aus.
Kommt natürlich drauf an, wie ausgiebig die API sein soll.
Der Vorteil ist, dass man ein Register weniger "verbraucht" und man sich somit die calls besser in Code integrieren lassen.
So kann man diverse log-ausgaben erledigen, ohne auch nur einmal ein Register zu überschreiben (mal abgesehen von
si)
Die Funktionen befinden sich alle in der Binärdatei des Bootloaders werden dort wie folgt in die IVT eigetragen:
mov WORD [es:0xF0*4], int_0xF0
mov WORD [es:0xF0*4+2], cs
mov WORD [es:0xF1*4], int_0xF1
mov WORD [es:0xF1*4+2], cs
die Funktion
int_0xF0 kann dann z.B. so aussehen:
int_0xF0:
call writestring ; si = string-offset; ds = segment des strings
iret
Du musst in allen Funktionen die
writestring aufruft natürlich beachten das
ds und
es idr auf "fremde" Segmente zeigen.
Der Bootloader kann nun andere Binärdateien laden, (in ein anderes Segment) und diese Programme können dann ganz einfach per
int 0xF0 die writestring-Funktion des Bootloaders aufrufen
zu deinem 1. PS:
nahezu unendlich viele
du könntest ax:bx:cx:dx für eine fortlaufende Nummer benutzen, und die Argumente auf den Stack pushen
zu PS2:
Du musst die Datei im Speicher belassen, die die Funktionen beinhaltet. Wenn sich diese Funktionen so wie bei mir teil des Bootloaders sind ist das ohnehin nicht zu verhindern
Eine zusätzliche Datei (quasi ein shared object file) ist dann natürlich nicht mehr nötig.