Лабораторная работа № 23-24. «Изучение и распределение памяти в MS DOS». Краткие теоретические и учебно-методические материалы
⇐ ПредыдущаяСтр 12 из 12 Лабораторная работа № 23-24 «Изучение и распределение памяти в MS DOS»
Цель работы: изучение распределения памяти в операционной системе MS-DOS и получение практических навыков работы с блоками управления памятью.
Образовательные результаты, заявленные во ФГОС третьего поколения: Студент должен уметь: - осуществлять разработку кода программного модуля на современных языках программирования; - создавать программу по разработанному алгоритму как отдельный модуль; - выполнять отладку и тестирование программы на уровне модуля знать: - основные этапы разработки программного обеспечения; - основные принципы технологии структурного и объектно-ориентированного программирования; - основные принципы отладки итестирования программных продуктов. Краткие теоретические и учебно-методические материалы по теме лабораторной работы После загpузки опеpационной системы оставшаяся часть памяти свободна и pаспpеделяется DOS пpикладным пpогpаммам. Память pаспpеделяется блоками. Размеp блока может быть пpоизвольным, но обязательно кpатен pазмеpу паpагpафа (16 байт). Вообще пpи pаспpеделении памяти объем памяти измеpяется в паpагpафах, и все блоки памяти выpавниваются по гpанице паpагpафа. Блоки создаются и уничтожаются динамически, по меpе поступления запpосов на их выделение / освобождение. Каждый блок памяти пpедваpяется Упpавляющим Блоком Памяти (MCB - Memory Control Block). MCB имеет фиксиpованный pазмеp 1 паpагpаф и фоpмат. Для каждого MCB выводится на экран: · сегментный адрес MCB; · программный иденитфикатор " владельца" блока памяти; · размер блока памяти в параграфах; · класс блока;
· символьный идентификатор владельца (только DOS 4. 0 и дальше); · строка вызова владельца (DOS 3. 0 и выше). Сегментный адрес, PID владельца и размер блока получаются из MCB очевидным образом. Класс блока определяется по следующим правилам. Если PID владельца блока нулевой, блок является свободным (класс Free). Для занятых блоков класс уточняется. Если PID (сегментный адрес PSP) владельца содержит адрес, лежащий до вершины распределяемой памяти memtop (обычно это число 8), то блок получает класс Dos. Для блоков, не принадлежащих DOS, прежде всего проверяется сегментный адрес владельца. Если этот адрес является адресом сегмента, следующего за текущим MCB, это означает, что блок памяти содержит программный сегмент и получает класс Pgm. В противном случае программа " заглядывает" в PSP владельца. Со смещением 0x2C в PSP содержится адрес сегмента окружения; если этот адрес является адресом сегмента, следующего за текущим MCB, то блок получает класс Env. Если класс блока не удается определить ни одним из вышеописанных способов, считаем, что блок содержит данные и помечаем его классом Data. При обычной работе MS DOS сама занимается распределением памяти и предоставляет пользователю три функции выделения/освобождения памяти: · функция 0x48 - выделение блока памяти (на входе: BX - требуемый размер блока в параграфах, на выходе: AX - сегментный адрес выделенного блока; если памяти для удовлетворения запроса не хватает, BX содержит размер наибольшего свободного блока); · функция 0x49 - освобождение блока (на входе ES - сегментный адрес освобождаемого блока); · функция 0x4A - изменение размера ранее выделенного блока (на входе ES - сегментный адрес, BX - требуемый размер).
Пример: Вывести на экран карту распределяемой памяти на своем рабочем месте. Структура программы Программа состоит из основной программы и двух функций. void get_DOS_ver_h(void) - функция, возвращающая в глобальной переменной dos старшее число номера версии DOS.
void print_head(void) - функция, которая выводит заголовок лабораторной работы. Переменные, глобальные для всей программы: cmcb - адрес текущего управляющего блока памяти (MCB); emcb - адрес управляющего блока памяти в котором содержится сегмент окружения программы; memtop - сегментный адрес начала цепочки управляющих блоков; csem - сегментный адрес текущего управляющего блока; othersegm - сегментный адрес блока окружения хозяина текущего блока памяти; fathersegm - сегментный адрес родителя для программы - хозяина текущего блока; 0envstr - адрес строки окружения для программы-хозяина текущего блока памяти (используется для определения имени программы из строки вызова); envlen - длина очередной строки окружения; dos - старшее число номера версии DOS; rr и sr - переменные, которые используются для задания значений регистров общего назначения и сегментных регистров, соответственно, при вызове прерывания; i - вспомагательная переменная, используемая для получения имени хозяина блока (для версии DOS 4. 0 и старше); n - число выведенных на экран строк информации о блоках (после вывода информации о каждых 20-ти блоках программа приостанавливает свою работу и ожидает нажатия на любую клавишу); s - указатель на имя хозяина блока (если используется версия DOS не ниже 4. 0). В начале выполнения программы определим номер версии DOS, установленной на данной ПЭВМ. Затем с помощью функции 52h DOS (прерывание 21h) определим адрес системных управляющих блоков: Вход: AH = 52h Выход: ES: BX - адрес 1-го блока параметров диска. Вычтя из этого адреса 2, получим адрес того слова памяти в котором DOS хранит сегментный адрес первого управляющего блока памяти. Каждый блок памяти пpедваpяется Упpавляющим Блоком Памяти (MCB - Memory Control Block). MCB имеет фиксиpованный pазмеp 1 паpагpаф и фоpмат, описываемый следующей стpуктуpой: struct MCB { byte type; /* тип */ word owner; /* владелец */ word size; /* размер */ byte reserved[3]; /* не используется */ char pgmname[8]; /* имя (только DOS 4. 0 и выше) */ }; Поле type содеpжит код, показывающий, является ли этот MCB последним (код буквы Z - 5Ah. ) или непоследним (код буквы M - 4Dh). Поле owner содеpжит PID (сегментный адpес пpефикса пpогpаммного сегмента) пpогpаммы, котоpой данный блок памяти пpинадлежит. Если значение этого поля нулевое, то блок свободен. Поле size содеpжит pазмеp блока памяти в паpагpафах (в это число не включен 1 паpагpаф, занимаемый самим MCB). Следующие 3 байта (поле reserved) заpезеpвиpованы во всех веpсиях. Поле pgmname заpезеpвиpовано (не используется) в веpсиях DOS ниже 4. 0. Начиная с веpсии 4. 0, в MCB, пpедваpяющем пpогpаммный сегмент, здесь записано имя (без pасшиpения) пpогpаммы, находящейся в этом сегменте (если длина имени меньше 8 символов, оно заканчивается нулевым байтом).
Все MCB увязаны в цепочку. Получив при помощи функции DOS 52h сегментный адрес начала цепочки MCB csegm, движемся по цепочке. Переход к следующему блоку производится прибавлением к адресу текущего MCB его поля size и еще 1. Перебор заканчивается при достижении MCB со значением 'Z' в поле type. Для каждого MCB выводится на экран: сегментный адрес MCB; программный иденитфикатор " владельца" блока памяти; размер блока памяти в параграфах; класс блока (см. ниже); символьный идентификатор владельца (только DOS 4. 0 и старше); строка вызова владельца (DOS 3. 0 и выше). Сегментный адрес, PID владельца и размер блока получаются из MCB. Класс блока определяется по следующим правилам. Если PID владельца блока нулевой, блок является свободным (класс Free). Для занятых блоков класс уточняется. Если PID (сегментный адрес PSP) владельца содержит адрес, лежащий до вершины распределяемой памяти memtop (обычно это число 8), то блок получает класс Dos. Для блоков, не принадлежащих DOS, прежде всего проверяется сегментный адрес владельца. Если этот адрес является адресом сегмента, следующего за текущим MCB, это означает, что блок памяти содержит программный сегмент и получает класс Pgm. В противном случае программа " заглядывает" в PSP владельца. Со смещением 2Ch в PSP содержится адрес сегмента окружения; если этот адрес является адресом сегмента, следующего за текущим MCB, то блок получает класс Env. Если класс блока не удается определить ни одним из вышеописанных способов, считаем, что блок содержит данные и помечаем его классом Data.
Для DOS 4. 0 и выше определяем символьный идентификатор владельца, для этого " заглядываем" в MCB того блока, на который указывает поле owner текущего блока, и выводим его поле pgmname. Только DOS 4. 0 позволяют получить идентификатор командного процессора DOS вышеописанным образом. Однако, в ранних версиях DOS можно опознать блок памяти, принадлежащий командному процессору вот каким способом. В PSP владельца со смещением 16h находится сегментный адрес " родителя" - программы, запустившей данную программу. Для программ, запущенных из командной строки DOS, родителем является COMMAND. COM. Родителем же COMMAND. COM является он сам. По этому признаку (сам себе родитель) он и может быть опознан. Если же программа не является программой DOS, командным процессором или резидентной, загруженной по INSTALL, для нее должна сохраняться строка вызова. Строка вызова находится в сегменте окружения. Программа получает адрес начала блока окружения, пропускает в нем все строки до пустой, после пустой строки пропускает еще 2 байта и получает адрес строки вызова. Из строки вызова мы и определяем имя программы, которой принадлежит текущий блок. Функция get_DOS_ver_h() определяет старшее число номера версии DOS, используя для этого функцию 30h DOS (прерывание 21h), которая возвращает в регистре AL старшее число номера версии, а в регистре AH - младшее число. Нас интересует только значение регистра AL. Функция print_head() выводит заголовок лабораторной работы (номер лабораторной работы, тема и т. д. ). /* Типы данных */ #define byte unsigned char #define word unsigned int
/* Подключение стандартных заголовков */ #include < dos. h> #include < string. h>
void get_DOS_ver_h(void); /* получить номер версии DOS */ void print_head(void); /* вывод заголовка лаб. работы */
struct MCB { /* блок упpавления памятью */ char type; /* тип */ word owner, /* владелец */ size; /* размер */ byte reserved[3]; /* зарезервировано */ char pgmname[8]; /* имя программы, находящейся в данном блоке ( для DOS 4. 0 и выше ) */ };
struct MCB *cmcb; /* адpес текущего MCB */ struct MCB *emcb; /* адpес MCB сpеды */ word memtop; /* сегм. адрес начала памяти */ word csegm; /* сегментный адpес текущего MCB */ word othersegm; /* сегм. адрес другого MCB */ word fathersegm; /* сегм. адрес родителя */ byte *envstr; /* адpес стpоки окружения */ int envlen; /* длина очередной строки окружения */ int envsize; /* размер блока окружения */ byte dos; /* номер версии DOS */ union REGS rr; struct SREGS sr; int i, n; char *s;
void main() { print_head(); n=0; /* Число выведенных на экран блоков */ get_DOS_ver_h(); /* получить адрес системных блоков */ rr. h. ah=0x52; intdosx(& rr, & rr, & sr); /* получить адрес начала цепочки */ memtop=csegm=peek(sr. es, rr. x. bx-2); do {
cmcb=(struct MCB *)MK_FP(csegm, 0); textattr(14); cprintf(" Addr=%04X: 0000 ", csegm); textattr(13); cprintf(" PID=%04X ", cmcb-> owner); textattr(11); cprintf(" Size=%-6u ", cmcb-> size*16); n++; /* Счетчик выведенных блоков увеличить на 1 */ if (cmcb-> owner==0) { textattr(15); cprintf(" Free" ); /* блок свободен */ } else { /* блок занят */ /* блок принадлежит DOS? */ if (cmcb-> owner< memtop) { textattr(13); cprintf(" Dos " ); } else { /* блок не принадлежит DOS */ /* если PID хозяина указывает на текущий блок, то это программный сегмент */ if (csegm==cmcb-> owner-1) { textattr(10); cprintf(" Pgm " ); } else { /* адpес блока сpеды для хозяина этого блока памя- ти находится в PSP хозяина со смещением 0x2C */ othersegm=peek(cmcb-> owner, 0x2c); /* адpес родителя для программы-хозяина этого бло- ка находится в PSP хозяина со смещением 0x16 */ fathersegm=peek(cmcb-> owner, 0x16); /* если на текущий блок указывает адрес окружения хозяина, то это блок окружения */ if (csegm==othersegm-1) { textattr(11); cprintf(" Env " ); } /* иначе - это блок данных */ else { textattr(14); cprintf(" Data " ); } } /* если хозяин сам себе родитель, то это COMMAND */ if (cmcb-> owner==fathersegm) { textattr(13); cprintf(" COMMAND. COM" ); } else { /* для другой программы узнаем ее имя */ textattr(15); if (dos> 3) { emcb=(struct MCB *)MK_FP(cmcb-> owner-1, 0); for (i=0, s=emcb-> pgmname; i< 8; i++) { if (*s> 0) printf(" %c", *(s++)); else printf(" " ); } printf(" " ); } if (dos> 2) { /* для DOS 3. 0 и выше имя - из строки вызова */ emcb=(struct MCB *)MK_FP(othersegm-1, 0); envsize=emcb-> size*16; /*размер окружения */ envstr=(char *)MK_FP(othersegm, 0); do { /* пропуск строк окружения до пустой строки */ envlen=strlen(envstr)+1; envstr+=envlen; envsize-=envlen; } while ((envlen> 1)& & (envsize> 0)); envstr+=2; envsize-=2; /* 2 байта - кол. строк */ /* envstr - указатель на строку вызова */ if (envsize> 0) { textattr(11); cprintf(" %s", envstr); }}}}} printf(" \n" ); csegm+=(cmcb-> size+1); /* переход к следующему блоку */ if(n==20) { /* Весь экран занят информацией о блоках */ textattr(0x0a); gotoxy(30, 24); cprintf(" Нажмите любую клавишу" ); getch(); n=0; print_head(); }} while (cmcb-> type! ='Z'); /* выход по последн. блоку */ textattr(0x0a); gotoxy(20, 24); cprintf(" Нажмите любую клавишу для возврата в DOS. " ); textattr(0x07); getch(); clrscr(); } /* получить номер версии DOS */ void get_DOS_ver_h(void) { rr. h. ah=0x30; intdos(& rr, & rr); dos=rr. h. al; } /* вывод заголовка лаб. работы */ void print_head(void) { textbackground(0); clrscr(); textattr(0x0a); cprintf(" ---------------" ); cprintf(" Лабораторная работа N23-24 " ); cprintf(" ---------------" ); cprintf(" ---------------" ); cprintf(" Управление памятью " ); cprintf(" ---------------" ); gotoxy(28, 3); textattr(13); cprintf(" Карта распределяемой памяти. \n\r" ); } В процессе работы программы на экран быдет выведена следующая информация о распределении памяти: --------------- Управление памятью --------------- Карта распределяемой памяти. Addr=025B: 0000 PID=0008 Size=9130 Dos Addr=0496: 0000 PID=0008 Size=64 Dos Addr=049B: 0000 PID=04A0 Size=48 Data COMMAND. COM Addr=049F: 0000 PID=04A0 Size=2640 Pgm COMMAND. COM Addr=0545: 0000 PID=04A0 Size=64 Data COMMAND. COM Addr=054A: 0000 PID=04A0 Size=513 Env COMMAND. COM Addr=056B: 0000 PID=0008 Size=32 Dos Addr=056E: 0000 PID=06CB Size=160 Env NC C: \NC\NC. EXE Addr=0579: 0000 PID=057A Size=5376 Pgm KEYRUS C: \NC\NC. EXE Addr=06CA: 0000 PID=06CB Size=13152 Pgm NC C: \NC\NC. EXE Addr=0A01: 0000 PID=0AFA Size=160 Data COMMAND. COM Addr=0A0C: 0000 PID=0AFA Size=256 Env COMMAND. COM Addr=0A1D: 0000 PID=0BA0 Size=160 Env TC_LAB12 D: \TC\TC_LAB12. EXE Addr=0A28: 0000 PID=0000 Size=2464 Free Addr=0AC3: 0000 PID=0ACF Size=160 Env COPY_ECR D: \TC\COPY_ECR. COM Addr=0ACE: 0000 PID=0ACF Size=672 Pgm COPY_ECR D: \TC\COPY_ECR. COM Addr=0AF9: 0000 PID=0AFA Size=2640 Pgm COMMAND D: \TC\COPY_ECR. COM Addr=0B9F: 0000 PID=0BA0 Size=17408 Pgm TC_LAB12 D: \TC\COPY_ECR. COM Addr=0FE0: 0000 PID=0000 Size=65008 Free Задания для лабораторной работы: Вывести на экран карту распределяемой памяти на своем рабочем месте.
Контрольные вопросы: 1. Что такое параграф? 2. Каково назначение MCB? 3. По каким правилам определяется класс блока? 4. Что такое сегмент окружения? 5. Каков размер блока?
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|