Завантажувач. Принципи загрузки програм на виконання в системі MS DOS, структура виконуваних файлів (COM, EXE) (Звіт з лабораторної роботи № 5)

Страницы работы

Фрагмент текста работы

Пользовательская программа может в ходе своего выполнения запустить другую программу из COM- или EXE-файла. Эта возможность обеспечивается функцией DOS 4BH.

Подфункция 0 этой функции выполняет загрузку и запуск другой программы. Для загружаемой (порожденной) программы DOS выделяет память из своего ресурса, следовательно, программа-родитель должна обеспечить наличие свободной памяти в системе (в первую  очередь это относится к COM-родителям,  так как при их загрузке весь ресурс памяти DOS отдается им). Для запуска программа-родитель должна сформировать строку вызова, содержащую имя файла вызываемой программы (с полным маршрутом, если файл находится не в текущем каталоге) и построить EPB (Exec Parameters Block - Блок Параметров Выполнения) - EPB содержит сегментный адрес окружения, которое копируется в сегмент окружения создаваемый для порожденной программы (если этот адрес 0,то в него копируется окружение родителя) и адреса строки параметров и двух блоков FCB, помещаемых в PSP порожденной программы. При обращении к функции 0x4B в регистр AL записывается  код подфункции,  в регистры DS:DX - адрес строки вызова, а в ES:BX - адрес EPB. Родитель запрашивает у оператора строку вызова, формирует EPB и обращается к функции 0x4B. Это обращение вызывает загрузку порождаемой программы и передачу ей управления. Порожденная программа получает свой PID и сообщает оператору его и PID родителя, из PSP находит свой сегмент окружения и выводит на экран окружение и строку вызова, а также строку параметров из PSP. Перед завершением порожденная программа запрашивает у оператора код завершения и завершается по функции DOS 4CH, передавая ей полученный код завершения. Программа-родитель, когда к ней возвращается управление, получает этот код завершения при помощи функции 4DH.

Текст програми завантажувача COMфайлів:

#pragma inline

#include <dos.h>

#include <io.h>

#include <fcntl.h>

#include <stdio.h>

#include <alloc.h>

int main(int argc, char *argv[]){

  int handle;      //файл

  unsigned bytes;  //колич байт для чтения с файла

  void far *beginPSP;     //начало PSP

  void far *farptr;        //начало кучи

  void far *beginfile;     //начало кода

  int  far *ret;             //установл int 20h

  long flength, memory;     //длина файла, колич памяти

  if (argc<1) return 0;     //если нет аргум

  if (_dos_open(argv[1],O_RDONLY | O_BINARY,&handle)!=0){ //открытие ф

      puts("\nError !\n");   return 0;

  }

  flength=filelength(handle);

  memory=flength+16-flength%16;    //выравнивание к параграфу

  memory+=0x0100;           //добавить PSP

farptr=(void far*)farmalloc(memory);  //выдел памяти

  if(farptr==NULL) { puts("\nNot enouth memory !\n"); return 0; }

  beginPSP=(int far*)farptr;       //вычисление начала PSP

  asm mov ax,word ptr beginPSP+2

  asm add ax,1       //выравнивание PSP к para

  asm mov word ptr beginPSP,0

  asm mov word ptr beginPSP+2,ax

  ret=(int far*)beginPSP;     //помещение int 20h

  *ret=0xCD20;

  beginfile=beginPSP; //вычисление начала кода

  asm {

     mov ax,beginfile+2        //пропускаем PSP

     add ax,16

     mov word ptr beginfile,0

     mov word ptr beginfile+2,ax

  }

  printf("\nRun:%s ",argv[1]);

  if (_dos_read(handle, beginfile, flength, &bytes) != 0) { //чтение ф

      puts("\nReading failed\n");    return 0;

  }

  else

    printf("\nRead: %d bytes read\n", bytes);  //чтение n байт

 close(handle);              //закрытие

  asm jmp goprogram

  asm start dd 0            //адрес кода

goprogram:

  asm {

     mov ax,offset cs:end

     mov cx,seg cs:end

     push ds

     mov bx,0

     mov ds,bx

     mov bx,128

     mov ds:[bx],ax

     mov ds:[bx+2],cx

     pop ds

     }

 asm {

     mov ax,0x100             смещение кода

     mov bx,word ptr beginPSP+2

     mov word ptr cs:start,ax   //загружаем начало

     mov word ptr cs:start+2,bx

     mov ax,memory

     xor dx,dx

     xor cx,cx             //обнуляем регистры

     push di

     xor di,di

     push si

     xor si,si

     push bp

     xor bp,bp

     push ds

     mov ds,bx            //устанавл сегм регистры

     push es

     mov es,bx

xor ax,ax

     xor bx,bx

     call cs:start            //jmp far

    }

 asm end label byte

 asm {

    pop es

    pop ds

    pop bp

    pop si

    pop di

}

  puts("End");

  farfree(farptr);

  return 1;

}

Текст програми завантажувача EXEфайлів:

#include <io.h>

#include <dos.h>

#include <stdio.h>

#include <conio.h>

#include <fcntl.h>

#include <stdlib.h>

#include <string.h>

struct head_exe

{

          unsigned int MZ;         // 5A4Dh - признак файла .EXE ('MZ')

          unsigned int PartPag;    // длина последнего блока файла (обычно игнорируется)

          unsigned int PageCnt;    // длина файла в 512-байтных блоках

          unsigned int NumTable;   // число элементов в таблице настройки адресов

          unsigned int HdrSize;    // длина заголовка в 16-байтных параграфах

          unsigned int MinMem;     // минимальный объем памяти

          unsigned int MaxMem;     // максимальный объем памяти

          unsigned int ReloSS;     // сегментное смещение сегмента стека (для установки SS)

          unsigned int ExeSP;      // значение SP, устанавливаемое при входе

          unsigned int ContrSum;   // контрольная сумма - ноль минус сумма без переноса всех слов файла

          unsigned int ExeIP;      // значение IP, устанавливаемое при входе (стартовый адрес)

          unsigned int ReloCS;     // сегментное смещение сегмента кода

Похожие материалы

Информация о работе