Speicher- Adressierung
-
Hi,
ich hab ein kleines Problem mit der Speicher Adresse beim Laden einen Sektors von Diskette. Der Speicher Ort kommt aus einem C++ Kernel, die Funktion die den Sektor an den Speicher lädt ist in Assembler.Hier die beiden Codes.
Kernel-Abschnitt
int disk_load_sector(int start, int anzahl, void *buffer); char sector_buffer[512]; if (disk_load_sector(1,1,§or_buffer)==true) { //OKAY } else { //Fehler }
disk_load_sector Funktion
GLOBAL disk_load_sector disk_load_sector: push bp mov bp,sp push dx push ax push cx push bx ;[bp+8] Start ;[bp+6] Anzahl ;[bp+4] Buffer mov ax, 1000h mov es, ax ; Ort, wo hingeladen wird mov al, [bp+6] ;mov al,1 mov cl, [bp+8] ;mov cl,1 ;mov bx, [bp+4] ; Offset, an dem begonnen werden soll zu laden mov bx,[bp+4] sdisk_load_sector@einlesen: mov ah, 0x02 ; Interrupt 13h Funktion zum Lesen von Sektoren mov ch, 0x00 ; Spur 0 mov dl, 0 ; Laufwerks Nummer (0 = Erstes Diskettenlaufwerk) mov dh, 0x00 ; Kopf Nummer int 0x13 ; Sektor einlesen jc disk_load_sector@fehler ; Wenn CFlag gesetzt ist ein Fehler aufgetreten, nochmal versuchen mov ax,TRUE jmp disk_load_sector@ende disk_load_sector@fehler: mov ax,FALSE disk_load_sector@ende pop bx pop cx pop ax pop dx pop bp ret
Der Aufruf aus C++ sieht so aus, is Turbo C++, der andere Asm Teil is NASM
mov ax,offset DGROUP:_sector_buffer push ax mov ax,1 push ax mov ax,1 push ax call near ptr @disk_load_sector$qiipv
Vor dem Laden mache ich natürlich noch einen Reset.
Mein Problem ich weiß nich wie ich die Adresse des Buffers beim laden angeben soll, ich hoffe das irgendwer aus meinem Code schlau wird :-).
-
Hey,
ein kurze Frage zwischen durch. Mit wlechen Programm schreibst du das und dann wo rein? und als was? Konsole oder Anwendung?
MfG Foxshunter
-
Ich spar mir mal deinen Code durch zu lesen. Hier was ich aus deiner Frage entnommen habe.
Es existiert irgendein Kernel, den du von Diskette laden willst. Generelle Lösung:
mov [drive], dl ; dl contains boot drive call ResetDrive ; self explaining jmp bx ; bx = kernel address ResetDrive: ; mov dl, [drive] ; select boot drive xor ax, ax ; reset disk drives int 0x13 ; low level disk services jc ResetDrive ; try again if loading failed LoadKernel: mov bx, [kernel_start] ; kernel start address (0x0000:0x????) ; prepare for reading sectors from drive mov dl, [drive] ; select boot drive ; mov al, 40 ; read first 40 sectors ; mov ch, 0 ; cylinder = 0 ; mov cl, 2 ; sector = 2 ; mov dh, 0 ; head = 0 ; mov ah, 2 ; function = read sectors from drive mov ax, 0x0228 mov cx, 0x0002 xor dh, dh int 0x13 jc LoadKernel ; try again if an error occurred ret
Mit "den Buffer" meinst du wohl die Speicherstelle, an die du den Kernel in den Speicher lesen willst? Falls ja, ist das bei mir "kernel_start". Adressiert wird das für int 13h über ES:BX.
Nach dem Aufruf kannst du noch in AL überprüfen, wie viele Sektoren geladen wurde. Generell ist bei Fehlern aber das Carry Flag gesetzt.
-
Zuerst mal ist es wenig sinnvoll, das Register fuer den Rueckgabewert der Funktion auf den Stack zu sichern. Noch weniger, wenn du beim Wiederherstellen den Rueckgabewert ueberschreibst.
Wie du am besten die Adresse deines Buffers uebergibst, haengt mit vom binaerformat ab, in das du linkst.
Ist das flach binaer (dh. alles im selben Segment), reicht es, ein Offset zu uebergeben und vor dem Aufruf des C-Codes dafuer zu sorgen, dass die Segmentregister korrekt gesetzt sind. Dann brauchst du in deiner Asm-Funktion die Segmentregister auch nicht mehr anfassen.
Geht dein Code aber ueber mehrere Segmente, ist es zweckmaessig, einen far pointer an deine Funktion zu uebergeben. Keine Ahnung, wie du das in deinem C-Code schreibst, hat schliesslich nichts mit Assembler zu tun.
-
@Nobuo T
Ich denke mal er meint den Puffer für den Interrupt 13h (ah = 2), was wie gesagt als Lösung ES:BX wäre. Oder was meinst du?
-
Ich meine ebenfalls diesen Puffer, sehe seine Frage aber so, dass er ein Problem damit hat, die Adresse dieses zum Einlesen in C-Code angelegten Puffers an die Assembler-Funktion zu uebergeben, statt innerhalb der Assembler-Funktion die Adresse an den int 13h, da das in seinem Code im Prinzip schon korrekt implementiert ist (er setzt es und bx auf eine Adresse).
-
Wenn das die Deklaration der Funktion in deinem C-Code ist:
int __cdecl disk_load_sector(int start, int anzahl, void *buffer);
dann ist das hier falsch:
;[bp+8] Start ;[bp+6] Anzahl ;[bp+4] Buffer mov ax, 1000h mov es, ax ; Ort, wo hingeladen wird mov al, [bp+6] ;mov al,1 mov cl, [bp+8] ;mov cl,1 ;mov bx, [bp+4] ; Offset, an dem begonnen werden soll zu laden mov bx,[bp+4]
cdecl Aufrufkonvention:
Die Parameter werden von rechts nach links auf den Stack gepushed. Hier mal ein Beispiel aus Pascal heraus:var val : Integer; function Summe(i1, i2, i3: Integer): Integer; cdecl; asm [asm] mov eax, [esp+8] // i1 mov edx, [esp+12] // i2 mov ecx, [esp+16] // i3 add eax, ecx add eax, edx[/asm] end; begin asm [asm] push 3 // Parameter 3 push 2 // Parameter 2 push 1 // Parameter 1 call Summe // Summe(1, 2, 3); add esp, 12 mov DWORD PTR [val], eax[/asm] end; writeln(val); readln; end.
Richtig wäre bei dir also:
PUBLIC _disk_load_sector _TEXT SEGMENT _Start$ = 4 _Anzahl$ = 6 _Buffer$ = 8 _disk_load_sector PROC push bx mov ax, _Start$[sp] mov cx, _Anzahl$[sp] mov bx, _Buffer$[sp] ; [...] pop bx _disk_load_sector ENDP _TEXT ENDS
Ganz nebenbei wundert mich, dass du aus C heraus überhaupt diese Funktion finden konntest, da C-Compiler externe Symbole mit einem Underscore "_" vornweg erwarten