Dockers DEV Site


Updates · Faq · Home 

Segmentbegrenzung im Realmode umgehen

Folgende Möglichkeiten bestehen im Realmode, Datenblöcke größer als 64 KB anzusprechen:

1.3.1 Benutzen von FAR-Zeigern / Speichermodell LARGE

Im Gegensatz zu NEAR-Zeigern wird bei FAR-Zeigern die Segmentadresse mitgeführt. Dadurch wird es möglich, durch zusätzliches Verändern der Segmentadresse den maximal adressierbaren Speicherbereich auf mehr als 64 KB zu vergrößern. Beachten Sie jedoch, daß Sie es weiterhin mit nur 64 KB großen Segmenten zu tun haben, daran ändert sich nichts!

Mehrere Segmente werden jetzt als ein Datenblock betrachtet und über einen FAR-Zeiger wird auf den Datenblock zugegriffen. Zum Anlegen bzw. Reservieren von größeren Speicherbereichen gibt es zwei Möglichkeiten. Erstens können sie statisch, d.h. direkt im Quelltext vereinbart werden oder der Speicher wird erst zur Laufzeit dynamisch allokiert.

Beide Möglichkeiten werden im folgenden kurz vorgestellt.

Statische Vereinbarung

Mehrere Segmente werden nacheinander im Speicher angeordnet. Das entspricht der Zerlegung eines einzelnen großen Speicherbereiches in mehrere kleinere 64 KB Blöcke.

Anlegen eines 100 KB Datenblocks unter der Voraussetzung, daß das aktuelle Speichermodell mehrere Datensegmente unterstützt. Das ist nur bei den Speichermodellen COMPACT, LARGE und HUGE möglich.

    DATEN1  segment PARA PUBLIC 'DATA'
            big_array1   db 65535 dup (?)
    DATEN1  ends
    DATEN2  segment PARA PUBLIC 'DATA'
            big_array2   db 34465 dup (?)
    DATEN2  ends

Anmerkung:

Diese Reservierung ist im Prinzip auch in C möglich:

        unsigned char far big_array1 [65535];
        unsigned char far big_array2 [34465];

Nur kann dann nicht garantiert werden, daß der C-Compiler beide Segmente wirklich nacheinander im Speicher anordnet. Viele C-Compiler unterstützen deshalb die sogenannten HUGE-Pointer, die auf dem hier besprochenen Prinzip aufbauen, jedoch direkt unterstützt werden.

Beispiel für statische Reservierung mit HUGE-Pointer:

        unsigned char huge big_array [100000];

Mehr über HUGE-Pointer (Prinzip und Realisierung) finden Sie unter 1.3.2 HUGE-Pointer.

Dynamische Reservierung

Die zweite Möglichkeit, große Speicherbereiche zu reservieren, ist die Nutzung des DOS-Heap. DOS stellt über die Funktionen 48h und 49h des Int 21h eine Möglichkeit bereit, Bereiche innerhalb des DOS-Speicherbereiches zu reservieren. Vergleichen Sie auch mit der entsprechenden Systemliteratur, z.B. Tischer: "PC-Intern" oder Monadjemi: "PC-Programmierung in Maschinensprache".

Funktion 48h:   Speicherplatz reservieren
   Aufruf mit   AH= 48h
                BX= Anzahl der zu reservierenden Paragraphen

                Da ein Paragraph 16 Byte groß ist und der übergebene
                Wert als Anzahl von Paragraphen interpretiert wird, ist der
                maximal zu reservierende Bereich 16*65536=1048576 (1 MB) groß!
                Dieser Bereich kann jedoch in der Regel nicht erreicht werden, da
                zum einen DOS selbst und auch das gerade ausgeführte Programm
                Speicherplatz belegen und zum anderen der verfügbare Raum durch
                UMB's, Treiber und die Routinen des ROM-Bios weiter eingeschränkt
                wird.

   Rückgabe     CF=0: Operation erfolgreich
                        AX= erstes Segment des reservierten Speicherbereichs
                CF=1: Fehler
                        AX= Fehlercode
                        BX= Größe des größten freien Speicherbereiches

Funktion 49h:   Speicherplatz freigeben
   Aufruf mit   AH= 49h
                ES= Segmentadresse des freizugebenden Bereiches

                Die Größe des Speicherbereichs wird dabei von DOS
                selbst aus den Speicherkontrollblocks ermittelt.

   Rückgabe     CF=0: Operation erfolgreich
                CF=1: Fehler
                        AX= Fehlercode

Zugriff auf den Speicher

Wurde über eine der obengenannten Möglichkeiten (statisch oder dynamisch) ein Speicherbereich reserviert, kann über einen FAR-Pointer darauf zugegriffen werden. Dabei wird zunächst die "normale" Offsetadresse benutzt, um Werte innerhalb des ersten reservierten Segmentes zu adressieren. Sollte es jedoch zu einem "Überlauf" der Offsetadresse kommen (Offset > 65535), so muß auch die Segmentadresse geändert werden. Die Segmentadresse wird in diesem Fall um 4096 (1000h) erhöht. Damit wird eine Erhöhung der physischen Adresse um 65536 Bytes erreicht. Die Offsetadresse wird dabei auf 0 zurückgesetzt bzw. entsprechend des Überlaufs korrigiert.

Konkret könnte der Zugriff auf größere Bereiche zum Beispiel so aussehen:

  ; far pointer (ES:BX) auf erstes Segment innerhalb
  ; des Datenblocks initialisieren
        mov ax,seg big_array1
        mov es,ax
        mov bx,offset big_array1
    
  ; mit dem Inhalt von al wird der Speicherbereich gefüllt
        mov al,12h

  ; füllen des Speicherbereichs (100000 Byte) mit al
  ; ersten Block bearbeiten
        mov cx,0

  inLoop1:
        mov es:[bx],al      ; Byte schreiben
        inc bx              ; Offsetadresse erhöhen
        dec cx
        jnz inLoop1         ; bis gesamter 64KB Block bearbeitet wurde

  ; Segmentregister auf neuen Block aktualisieren
        mov dx,es
        add dx,01000h       ; (4096d)
        mov es,dx

  ; zweiten Block bearbeiten
        mov cx,34465

  inLoop2:
        mov es:[bx],al
        inc bx
        dec cx
        jnz inLoop2
    

Der fett gedruckte Bereich, die Initialisierung des FAR-Pointers, würde sich bei dynamischer Reservierung wie folgt ändern:

        mov ax,adresse_des_Bereiches
        mov es,ax
        mov bx,0            ; der reservierte Bereich beginnt immer bei
                            ; der Offsetadresse 0
    


Das Assemblerbeispiel rm_01.asm soll als Zusammenfassung dienen. Es reserviert einen 100000 Byte großen Bereich auf dem DOS-Heap. Anschließend gibt es den aktuellen Inhalt dieses Bereiches unter Nutzung der Funktion showasci auf dem Bildschirm aus, füllt den Bereich mit einem konstanten Wert und zeigt den neuen Inhalt wieder am Bildschirm an.

Index
weiter >>
<< zurück ||

Last change 27/11/2022 by Docker Rocker.
This page uses no cookies, no tracking - just HTML.
Author: "Docker Rocker" ~ 2022 · [Public Git]