Lowlevel
Lowlevel => OS-Design => Thema gestartet von: ehenkes am 07. June 2009, 13:28
-
Gibt es eine Uebersichtstabelle oder einen Uebesichtsartikel, was die Paarungen call/ret, int/iret oder jmp usw. alles ausloesen jeweils mit oder ohne privilege-Wechsel (user/supervisor mode) und aus Sicht CPU/Compiler/Programm, oder muss man sich das alles zusammen suchen (Intel Manual, Inet)?
Immerhin spielen drei Player munter zusammen jeweils nach ihren eigenen Regeln:
- CPU
- Compiler
- Programmierer ( C/C++ u. asm)
-
Inwiefern der Compiler bzw. der Programmierer damit was zu tun hat ist mir ehrlich gesagt schleierhaft und was genau du für eine Tabelle erwartest auch, aber die Intel Manuals sind im Allgemeinen die Quelle für die Befehle. Für call/ret und jmp ist wohl die Befehlsreferenz das richtige zum nachschauen für int/iret wohl eher der System Programming Teil.
Ich würde mal sagen, dass das wirklich zu umfangreich ist, das für das von dir geforderte aufzulisten, zB muss man bei int zwischen Task-, Interrupt- und Trapgatedeskriptoren (jetzt allein im Pmode) unterscheiden. Außerdem muss man für alle Modi (16bit, 32bit und 64bit) unterscheiden...
Ich würde wie gesagt da eher auf die Manuals verweisen, wenn man das in allen Details wissen will...
-
Inwiefern der Compiler bzw. der Programmierer damit was zu tun hat ist mir ehrlich gesagt schleierhaft
Der Compiler setzt den Aufruf bzw. die Durchfuehrung einer C-Funktion in asm um. Der Programmierer baut selbst asm-Routinen auf, z.B. fuer interrupts, syscalls, ... Zusaetzlich werden von der CPU auf dem Stack, im TSS, ... Aktionen durchgefuehrt. Drei Player (mindestens). :-)
-
Und was genau erwartest du dir für Erklärungen bzgl. Compiler/Programmier? Ich mein es ist genau definiert was ein Befehl macht (in den Intel-Manuals). Daran ändert der Compiler/Programmierer ja nichts. Er benutzt halt die Befehle und wie er das tut liegt komplett im Ermessen desjenigen.
-
gcc als wesentlicher Compiler setzt C-Funktionen nach gewissen Regeln in Assembler um. Diese muss man als OS-Dever kennen.
-
Das einzige, was du als Programmierer kennen musst, ist die Aufrufkonvention, also die Paarung call/ret. Dazu siehe auch Aufrufkonventionen im Wiki (http://lowlevel.brainsware.org/wiki/index.php/Aufrufkonventionen#cdecl). Was in dem Artikel noch fehlt, ist eine Beschreibung, welche Register vom Aufrufer und welche von der aufgerufenen Funktion gesichert werden müssen.
Der Compiler benutzt offensichtlich nie int/iret und jmp benutzt er innerhalb von Funktionen, aber nie darüber hinweg - insofern kann man das auch ignorieren.
-
http://www.hs-augsburg.de/~pascal/MNP/pcasm-book-german.pdf, das ist noch eine pdf-datei in der zum schluss steht, wie man c-strukturen, funktionen etc. in assembler bentzen kann! Vieleicht hilft es, da ich nicht genau weiß, was du wissen oder haben willst! :-D
-
http://www.hs-augsburg.de/~pascal/MNP/pcasm-book-german.pdf, das ist noch eine pdf-datei in der zum schluss steht, wie man c-strukturen, funktionen etc. in assembler bentzen kann! Vieleicht hilft es, da ich nicht genau weiß, was du wissen oder haben willst! :-D
Kap. 4.5 ist nicht uninteressant. Ich wusste garnicht, dass das Register EBP (ergaenzend zu ESP) erst spaeter (Artikel: 80386) eingefuehrt wurde. Fuer die exakte Navigation zu Parametern u.a. ist dies ja sehr wichtig.
-
Fuer die exakte Navigation zu Parametern u.a. ist dies ja sehr wichtig.
Was meinst du damit genau? Wird mir nicht ganz schlüssig :mrgreen:
-
Man kopiert normalweise zu Begin einer Funktion den Stackpointer esp in ebp und greift anschließend mit ebp auf die Funktionsparameter auf dem Stack zu. Der Stackpointer esp wird dann weiterverwendet zum zwischenspeichern von neuen Werten oder Parametern für von dieser Funktion aufgerufene Funktionen.
Würdest du immer esp nehmen, wäre dein Funktionsparameter nicht die ganze Zeit an [esp+X] für ein konstantes X, sondern X würde sich ständig verändern (wenn was neues gepusht/gepopt wird), was extrem unübersichtlich wäre.
-
Genau bei [ebp+8] etc. findet man die der aufgerufenen Funktion uebergebenen Argumente.
Beispiel aus Sicht des callee:
retValue = sum(arg1,arg2)
_sum
; prolog des callee
push ebp ; ebp des callers sichern
mov ebp, esp ; ebp des callee erstellen
; body des callee
mov eax, [ebp+ 8] ; argument 1
mov ecx, [ebp+12] ; argument 2
add eax, ecx
; epilog des callee
pop ebp ; ebp des callers wiederherstellen
ret
Man hat hier eine saubere "Navigation" mittels ebp des callee (das ebp des callers wird im Prolog gesichert und im Epilog zurueck geholt):
[ebp+0]: EBP der caller-Funktion
[ebp+4]: Return address der caller-Funktion
[ebp+8]: arg 1
[ebp+12]: arg 2
[ebp+16]: hier koennten noch gespeicherte Register (EAX, ECX, EDX) - oder weitere Argumente - zu finden sein.
Ich habe mal begonnen, das Thema an einem konkreten Beispiel zu verarbeiten mit steigendem Komplexitätsgrad, beginnend mit einer Funktion ohne Parameter und ohne wirksamen Body:
http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId342494