Blog literacki, portal erotyczny - seks i humor nie z tej ziemi
Autor: Piotr Sokolowski(24 lipca 1998r)
---------------------------------------
Programowanie w trybie chronionym
=================================
Umozliwia wlasciwie tylko jeden kompilator borlanda - mianowicie
Borland Pascal 7.0 .Otoz posiada on specjalna opcje w menu
TARGET pozwalajaca przelanczac sie miedzy trybem REAL MODE(tryb
rzeczywisty), PROTECTED MODE(tryb chroniony) noi WINDOWS czyli
aplikacja windowsa. W trybie chronionym nie ma ograniczen co do
wielkosci segmentu ktory moze przyjmowac maksymalnie rozmiar
FFFF FFFFh - tak jest wszedzie oprocz w BP bowiem tu mamy dostep
do calej pamieci jednak jest nadal ograniczenie wielkosci
segmentu do 64kb(spowodowane jest to tym iz BP udostepnia
maksymalnie instrukcje 286 noi przy adresowaniu maksymalny
offset ma wartosc rowna wielkosci segmentu z trybu
rzeczywistego). Otoz w trybie chronionym adresowanie odbywa sie
teorytycznie przy pomocy pary rejestrow np: ds:ebx wtedy rejestr
ds zawiera tzw. selektor (wskazuje on na tzw. dyskryptor - jest
to 8 bajtowa struktura ktora zawiera takie informacje jak
wielkosc wskazywanego przez siebie segmentu,jego adres liniowy
itp). Natomiast np. rejestr ebx(ktory w BP jest zwyklym bx) jest
najnormalniejszym offsetem.
Rozkazy operujace na pamieci w trybie PMODE pochodza z
biblioteki winapi(najwazniejsze to):
- globalalloc(typ alokowanej pamieci,wielkosc) -> alokuje blok
pamieci o wielkosci "wielkosc"(w bajtach) i typie
"typ"(mem_moveable - pamiec tzw. przesuwalna). Funkcja ta zwraca
selektor(zmienna dwubajtowa typu thandle) do tego bloku pamieci.
Jesli jest on wiekszy od 65536 to zwraca ona selektor do
pierwszego segmentu. Dostep do nastepnego realizowany jest
poprzez zmienna systemowa:
- selectorinc -> jest to wartosc jaka trzeba dodac do wartosci
selektora aby uzyskac dostep do jego nastepnego segmentu
- globallfree(selektor) ->zwalnia blok pamieci wskazywany przez
selektor utworzony funkcja globalalloc.
- globalsize(selektor) -> funkcja zwracajaca wielkosc bloku
pamieci wskazywanego przez selektor utworzony funkcja
globalalloc
- globalcompact(0) -> funkcja zwracajaca wielkosc maksymalnego
bloku do zaalokowania funkcja globalalloc
Np.
uses winapi,crt;
var
al_:byte;
offset_:word;
a:thandle;
begin
clrscr;
writeln(globalcompact(0));{Wypisanie maksymalnej dostepnej
pamieci}
a:=globalalloc(gmem_moveable,65535*2);
offset_:=0;
writeln('Zapis do pamieci 128kb pamieci!');
repeat
asm
mov ax,a
mov es,ax
mov es:[offset_],2
end;
inc(offset_);
until offset_ = 65535;
inc(a,selectorinc);
offset_:=0;
repeat
asm
mov ax,a
mov es,ax
mov es:[offset_],3
end;
inc(offset_);
until offset_ = 65535;
writeln('Teraz nastapi odczyt z pamieci 128kb danych! - nacisnij
klawisz enter');
readln;
offset_:=0;
repeat
asm
mov ax,a
mov es,ax
mov al,byte ptr es:[offset_]
mov al_,al
end;
write(al_);
inc(offset_);
until offset_ = 65535;
writeln(globalsize(a));
dec(a,selectorinc);
offset_:=0;
repeat
asm
mov ax,a
mov es,ax
mov al,byte ptr es:[offset_]
mov al_,al
end;
write(al_);
inc(offset_);
until offset_ = 65535;
offset_:=0;
writeln(globalsize(a));
globalfree(a);
end.
{kompiluj z TARGET: Protected mode}
Program ten dokonuje alokacji 128 kB pamieci poczym zapisuje w
nich dane (cyfry 2 i 3) poczym dokonuje ich odczytu i wypisania
na ekranie. Na koniec zwalnia blok pamieci.
Inny problem pojawia sie w przypadku gdy w trybie chronionym
chcemy wywolac przerwanie zwracajace dane w pewne miejsce
pamieci,np rozkaz vesy(int 10h) ax=4F01h zwraca pod es:[di] 256
bajtow danych, wtedy stosuje sie rozkaz ax = 300h przerwania 31h
- symulacja przerwania trybu rzeczywistego. Oto jego opis:
ax = 300h
bx = numer symulowanego przerwania
cx = ilosc bajtow jak ma zostac skopiowana ze stosu trybu
chronionego na stos symulowanego trybu
rzeczywistego(najczesciej to 0)
es:[di] = adres bufora zawierajacego wartosci rejestrow dla
symulowanego przerwania. Oto jego budowa:
Offset Dlugosc Znaczenie
00h 4 EDI
04h 4 ESI
08h 4 EBP
0ch 4 zarezerwowane, ignorowane
10h 4 EBX
14h 4 EDX
18h 4 ECX
1ch 4 EAX
20h 2 CPU (znaczniki stanu)
22h 2 ES
24h 2 DS
26h 2 FS
28h 2 GS
2ah 2 IP (zarezerwowane, ignorowane)
2ch 2 CS (zarezerwowane, ignorowane)
2eh 2 SP
30h 2 SS
W ponizszym programie bufor ten nazwany jest "blok".
Np.
uses crt,winapi;
var
blok:array[0..24] of word;
bufor:longint;
modeinfo : record
attr:word;
wina,winb:Byte;
bsize,wsize,sega,segb:word;
funp:pointer;
lsize:word;
xresolution:word;
yresolution:word;
reserved:array[1..233] of byte;
end;
begin
fillchar(blok,sizeof(blok),0);{wyzerowanie tablicy na rejestry z
trybu real}
bufor:=globaldosalloc(300);{zalokowanie 300 bajtow na bufor w
pierwszym MB
pamieci by moc uzyskac segment tego bufora dla funkcji $4F00h
Vesy oraz jego
selektor}
blok[14]:=$4F01;
blok[12]:=$101;
blok[17]:=hiword(bufor);{segment tablicy bufor - bowiem 4F00h to
rozkaz trybu
real}
blok[0]:=0;{offset bufora "bufor"}
asm
mov ax,300h {Rozkaz 300h - symulacja przerwania real mode}
mov bx,10h {jakie symulowac przerwanie}
mov cx,0 {nie kopiowac stosu}
push ds
pop es
mov di,offset blok {es:di - adres bufora z rejestrami dla trybu
real}
int 31h
end;
move(ptr(loword(bufor),0)^,modeinfo,sizeof(modeinfo));{przeniesi
enie danych z
zaalokowanego bufora do bufora w segmencie danych ,loword(bufor)
- selektor(z boku 0 to offset = 0)}
globaldosfree(loword(bufor));{zwolnienie zaalokowanego bufora}
writeln(modeinfo.xresolution);
end.
Program ten zwraca liczbe w postaci poziomej rozdzielczosci
odczytanej rozkazem 4F01h Vesy.
Jeszcze innym problemem jest klopot z bezposrednim dostepem do
pamieci w trybie chronionym. Np. chcemy zapalic piksela czyli
chcemy zapisac bajt w segmencie A000h. Jednak w trybie
chronionym pod tym adresem nie musi rzeczywiscie sie znajdowac
pamiec karty graficznej totez proba zapisu pod ten segment
zakonczy sie bledem:
Runtime Error 216 at xxxx:xxxx
czyli proba nieupowaznionego dostepu
Wtedy stosujemy zmienne "SEG" zawierajace odpowiednie adresy
zarowno dla trybu chronionego i rzeczywistego. Sa to:
SEGA000 - czyli A000h
SEGB000 - czyli B000h
SEGB800 - czyli B800h
SEG0040 - czyli 40h
Np.
uses crt;
begin
asm
mov ax,13h
int 10h
mov ax,segA000
mov es,ax
mov bx,5
mov al,2
mov es:[bx],al
end;
repeat
until keypressed;
asm
mov ax,03h
int 10h
end;
end.
Program ten spowoduje zapisanie zielonego piksela na ekranie(w
gornym, lewym rogu).
Oto ciekawsze znaczniki trybu chronionego(biblioteki winapi):
wf_PMode = $00000001; { Uruchomione w protected mode }
wf_CPU286 = $00000002; { CPU jest conajmniej 80286 }
wf_CPU386 = $00000004; { CPU jest conajmniej 80386 }
wf_CPU486 = $00000008; { CPU jest conajmniej 80486 }
wf_Standard = $00000010; { Uruchomione w zwyklym trybie }
wf_CPU086 = $00000040; { CPU jest conajmniej 8086 }
wf_CPU186 = $00000080; { CPU jest conajmniej 80186 }
wf_DPMI = $80000000; { Uruchomione w dosowym protected
mode}
Mozemy je traktowac jak zwykle stale tzn. sprawdzac ich
wartosci,np.
uses winapi;
begin
if wf_PMode = 1 then writeln('Uruchomiony tryb chroniony!');
end.