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


Anmelden zum Antworten