Системное программное обеспечение персональных ЭВМ


Пример 4



Пример 4

/*== ПРИМЕР 11.4 ==*/ /*======== Обработка таблицы перемещений EXE-файла =====*/ #include <dos.h> #include <string.h> #include <stdlib.h> #define byte unsigned char #define word unsigned int #define dword unsigned long struct EXEH { /* заголовок EXE-файла */ word ExeFlag, LastPag, PageCnt, ReloCnt, HdrSize, MinMem, MaxMem,ReloSS, ExeSP, ChkSum, ExeIP, ReloCS, TabOff, Overlay; } exeh; /* Элемент таблицы перемещений */ struct ReloItem { word offs; /* смешение */ word segm; /* сегмент */ } ri; word psp, /* сегм.адрес PSP */ startseg, /* стартовый сегмент */ reloseg, /* сегмент модифицированного слова */ d; /* разность между памятью и файлом */ char fname[80],*fn; /* имя EXE-файла */ int exef; /* дескриптор EXE-файла */ dword fileoff, /* адрес в файле начала модуля */ itoff, /* адрес в файле модиф.слова */ seekoff; /* адрес в файле эл-та таблицы */ byte buff[10], /* буфер в ОП */ *s; int i, ni; union REGS rr; struct SREGS sr; main() { /* получение сегментного адреса PSP и открытие файла */ rr.h.ah=0x51; intdos(&rr,&rr); psp=rr.x.bx; for(fn=(char *)MK_FP(peek(psp,0x2C),0);*fn|*(fn+1);fn++); strcpy(fname,fn+4); if (strchr(fname,'.')==NULL) strcat(fname,".EXE"); rr.h.ah=0x3d; rr.h.al=0; sr.ds=FP_SEG(fname); rr.x.dx=FP_OFF(fname); intdosx(&rr,&rr,&sr); if (rr.x.cflag) { printf("Невозможно открыть файл %s\n",fname); exit(0); } else exef=rr.x.ax; /* чтение заголовка */ dread(&exeh,sizeof(struct EXEH)); startseg=psp+0x10; printf("\nСтартовый сегмент = %04Xh\n",startseg); printf("Число элементов = %d\n\n",exeh.ReloCnt); fileoff=exeh.HdrSize*16; /* перебор таблицы перемещений */ for (seekoff=exeh.TabOff,ni=0; ni<exeh.ReloCnt; ni++) { /* чтениe эл-та табл.перемещений */ dseek(seekoff); dread(&ri,sizeof(struct ReloItem)); printf("Элемент перемещения #%d : %04X:%04X\n", ni+1,ri.segm,ri.offs); /* выборка модифицированного адреса из программы в ОП */ reloseg=startseg+ri.segm; s=(byte *)MK_FP(reloseg,ri.offs)-4; printf(" Память : %Fp -> ",s); d=*((word *)(s+4)); prtmem(s); /* выборка немодифицированного адреса из EXE-файла */ itoff=fileoff+ri.segm*16+ri.offs-4; dseek(itoff);__ _.dread(buff,10); printf(" Файл : %9ld -> ",itoff); d-=*((word *)(buff+4)); prtmem(buff); printf(" Разность = %04X\n",d); seekoff+=sizeof(struct ReloItem); if (getch()==27) exit(0); } } /*==== Чтение из файла ====*/ dread(void *addr,int len) { rr.h.ah=0x3f; rr.x.bx=exef; rr.x.cx=len; sr.ds=FP_SEG(addr); rr.x.dx=FP_OFF(addr); intdosx(&rr,&rr,&sr); if (rr.x.cflag) { printf("Ошибка чтения %s\n"); exit(0); } } /*==== Позиционирование в файле ====*/ dseek(dword off) { rr.h.ah=0x42; rr.x.bx=exef; rr.h.al=0; rr.x.cx=off>>16; rr.x.dx=off&0xffff; intdos(&rr,&rr); if (rr.x.cflag) { printf("Ошибка позиционирования\n"); exit(0); } } /*==== Дамп участка памяти ====*/ prtmem(byte *a) { int i; for (i=0; i<10; i++) { if ((i==4)(i==6)) printf(" "); printf("%02X",*(a++)); } printf("\n"); }

Заголовок EXE-файла нужен только при загрузке программы в оперативную память - он не сохраняется после загрузки. Приведем итоговую схему загрузки EXE-программ:

  • форматированную часть заголовка DOS считывает в свой буфер;
  • определяется адрес в файле начала программного модуля: HdrSize * 16 и размер программного модуля: (PageCn - 1) * 512 + LastPage - HdrSize * 16;
  • выделяется память для программного сегмента и строится PSP;
  • вычисляется startseg - сегментный стартовый адрес; определяется начало в файле таблицы перемещений и элементы таблицы читаются в буфер DOS;
  • для каждого элемента выбирается слово по адресу (startseg + segm) : offs, к нему прибавляется startseg, результат записывается на то же место;
  • в регистры ES и DS записывается адрес PSP, в регистр SS - startseg + ReloSS, в SP - ExeSP, в CS - startseg + ReloCS, в IP - ExeIP, тем самым управление передается загруженной программе.




- Начало -  - Назад -  - Вперед -