frontend.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. /*****************************************************************************
  2. * dcc project Front End module
  3. * Loads a program into simulated main memory and builds the procedure list.
  4. * (C) Cristina Cifuentes
  5. ****************************************************************************/
  6. #include "dcc.h"
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #ifdef __BORLAND__
  11. #include <alloc.h>
  12. #else
  13. #include <malloc.h> /* For malloc, free, realloc */
  14. #endif
  15. typedef struct { /* PSP structure */
  16. word int20h; /* interrupt 20h */
  17. word eof; /* segment, end of allocation block */
  18. byte res1; /* reserved */
  19. byte dosDisp[5]; /* far call to DOS function dispatcher */
  20. byte int22h[4]; /* vector for terminate routine */
  21. byte int23h[4]; /* vector for ctrl+break routine */
  22. byte int24h[4]; /* vector for error routine */
  23. byte res2[22]; /* reserved */
  24. word segEnv; /* segment address of environment block */
  25. byte res3[34]; /* reserved */
  26. byte int21h[6]; /* opcode for int21h and far return */
  27. byte res4[6]; /* reserved */
  28. byte fcb1[16]; /* default file control block 1 */
  29. byte fcb2[16]; /* default file control block 2 */
  30. byte res5[4]; /* reserved */
  31. byte cmdTail[0x80]; /* command tail and disk transfer area */
  32. } PSP;
  33. static struct { /* EXE file header */
  34. byte sigLo; /* .EXE signature: 0x4D 0x5A */
  35. byte sigHi;
  36. word lastPageSize; /* Size of the last page */
  37. word numPages; /* Number of pages in the file */
  38. word numReloc; /* Number of relocation items */
  39. word numParaHeader; /* # of paragraphs in the header */
  40. word minAlloc; /* Minimum number of paragraphs */
  41. word maxAlloc; /* Maximum number of paragraphs */
  42. word initSS; /* Segment displacement of stack */
  43. word initSP; /* Contents of SP at entry */
  44. word checkSum; /* Complemented checksum */
  45. word initIP; /* Contents of IP at entry */
  46. word initCS; /* Segment displacement of code */
  47. word relocTabOffset; /* Relocation table offset */
  48. word overlayNum; /* Overlay number */
  49. } header;
  50. #define EXE_RELOCATION 0x10 /* EXE images rellocated to above PSP */
  51. static void LoadImage(char *filename);
  52. static void displayLoadInfo(void);
  53. static void displayMemMap(void);
  54. /*****************************************************************************
  55. * FrontEnd - invokes the loader, parser, disassembler (if asm1), icode
  56. * rewritter, and displays any useful information.
  57. ****************************************************************************/
  58. void FrontEnd (char *filename, CALL_GRAPH * *pcallGraph)
  59. {
  60. /* Load program into memory */
  61. LoadImage(filename);
  62. if (option.verbose)
  63. displayLoadInfo();
  64. /* Do depth first flow analysis building call graph and procedure list,
  65. * and attaching the I-code to each procedure */
  66. parse (pcallGraph);
  67. if (option.asm1)
  68. {
  69. printf("dcc: writing assembler file %s\n", asm1_name);
  70. }
  71. /* Search through code looking for impure references and flag them */
  72. std::for_each(pProcList.begin(),pProcList.end(),
  73. [](Function &f)->void {
  74. f.markImpure();
  75. if (option.asm1)
  76. disassem(1, &f); });
  77. if (option.Interact)
  78. {
  79. interactDis(&pProcList.front(), 0); /* Interactive disassembler */
  80. }
  81. /* Converts jump target addresses to icode offsets */
  82. std::for_each(pProcList.begin(),pProcList.end(),
  83. [](Function &f)->void { f.bindIcodeOff(); });
  84. /* Print memory bitmap */
  85. if (option.Map)
  86. displayMemMap();
  87. }
  88. /****************************************************************************
  89. * displayLoadInfo - Displays low level loader type info.
  90. ***************************************************************************/
  91. static void displayLoadInfo(void)
  92. {
  93. Int i;
  94. printf("File type is %s\n", (prog.fCOM)?"COM":"EXE");
  95. if (! prog.fCOM) {
  96. printf("Signature = %02X%02X\n", header.sigLo, header.sigHi);
  97. printf("File size %% 512 = %04X\n", LH(&header.lastPageSize));
  98. printf("File size / 512 = %04X pages\n", LH(&header.numPages));
  99. printf("# relocation items = %04X\n", LH(&header.numReloc));
  100. printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader));
  101. printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc));
  102. printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc));
  103. }
  104. printf("Load image size = %04X\n", prog.cbImage - sizeof(PSP));
  105. printf("Initial SS:SP = %04X:%04X\n", prog.initSS, prog.initSP);
  106. printf("Initial CS:IP = %04X:%04X\n", prog.initCS, prog.initIP);
  107. if (option.VeryVerbose && prog.cReloc)
  108. {
  109. printf("\nRelocation Table\n");
  110. for (i = 0; i < prog.cReloc; i++)
  111. {
  112. printf("%06X -> [%04X]\n", prog.relocTable[i],LH(prog.Image + prog.relocTable[i]));
  113. }
  114. }
  115. printf("\n");
  116. }
  117. /*****************************************************************************
  118. * fill - Fills line for displayMemMap()
  119. ****************************************************************************/
  120. static void fill(Int ip, char *bf)
  121. {
  122. static byte type[4] = {'.', 'd', 'c', 'x'};
  123. byte i;
  124. for (i = 0; i < 16; i++, ip++)
  125. {
  126. *bf++ = ' ';
  127. *bf++ = (ip < prog.cbImage)?
  128. type[(prog.map[ip >> 2] >> ((ip & 3) * 2)) & 3]: ' ';
  129. }
  130. *bf = '\0';
  131. }
  132. /*****************************************************************************
  133. * displayMemMap - Displays the memory bitmap
  134. ****************************************************************************/
  135. static void displayMemMap(void)
  136. {
  137. char c, b1[33], b2[33], b3[33];
  138. byte i;
  139. Int ip = 0;
  140. printf("\nMemory Map\n");
  141. while (ip < prog.cbImage)
  142. {
  143. fill(ip, b1);
  144. printf("%06X %s\n", ip, b1);
  145. ip += 16;
  146. for (i = 3, c = b1[1]; i < 32 && c == b1[i]; i += 2)
  147. ; /* Check if all same */
  148. if (i > 32)
  149. {
  150. fill(ip, b2); /* Skip until next two are not same */
  151. fill(ip+16, b3);
  152. if (! (strcmp(b1, b2) || strcmp(b1, b3)))
  153. {
  154. printf(" :\n");
  155. do
  156. {
  157. ip += 16;
  158. fill(ip+16, b1);
  159. } while (! strcmp(b1, b2));
  160. }
  161. }
  162. }
  163. printf("\n");
  164. }
  165. /*****************************************************************************
  166. * LoadImage
  167. ****************************************************************************/
  168. static void LoadImage(char *filename)
  169. {
  170. FILE *fp;
  171. Int i, cb;
  172. byte buf[4];
  173. /* Open the input file */
  174. if ((fp = fopen(filename, "rb")) == NULL)
  175. {
  176. fatalError(CANNOT_OPEN, filename);
  177. }
  178. /* Read in first 2 bytes to check EXE signature */
  179. if (fread(&header, 1, 2, fp) != 2)
  180. {
  181. fatalError(CANNOT_READ, filename);
  182. }
  183. if (! (prog.fCOM = (boolT)(header.sigLo != 0x4D || header.sigHi != 0x5A))) {
  184. /* Read rest of header */
  185. fseek(fp, 0, SEEK_SET);
  186. if (fread(&header, sizeof(header), 1, fp) != 1)
  187. {
  188. fatalError(CANNOT_READ, filename);
  189. }
  190. /* This is a typical DOS kludge! */
  191. if (LH(&header.relocTabOffset) == 0x40)
  192. {
  193. fatalError(NEWEXE_FORMAT);
  194. }
  195. /* Calculate the load module size.
  196. * This is the number of pages in the file
  197. * less the length of the header and reloc table
  198. * less the number of bytes unused on last page
  199. */
  200. cb = (dword)LH(&header.numPages) * 512 - (dword)LH(&header.numParaHeader) * 16;
  201. if (header.lastPageSize)
  202. {
  203. cb -= 512 - LH(&header.lastPageSize);
  204. }
  205. /* We quietly ignore minAlloc and maxAlloc since for our
  206. * purposes it doesn't really matter where in real memory
  207. * the program would end up. EXE programs can't really rely on
  208. * their load location so setting the PSP segment to 0 is fine.
  209. * Certainly programs that prod around in DOS or BIOS are going
  210. * to have to load DS from a constant so it'll be pretty
  211. * obvious.
  212. */
  213. prog.initCS = (int16)LH(&header.initCS) + EXE_RELOCATION;
  214. prog.initIP = (int16)LH(&header.initIP);
  215. prog.initSS = (int16)LH(&header.initSS) + EXE_RELOCATION;
  216. prog.initSP = (int16)LH(&header.initSP);
  217. prog.cReloc = (int16)LH(&header.numReloc);
  218. /* Allocate the relocation table */
  219. if (prog.cReloc)
  220. {
  221. prog.relocTable = (dword*)allocMem(prog.cReloc * sizeof(Int));
  222. fseek(fp, LH(&header.relocTabOffset), SEEK_SET);
  223. /* Read in seg:offset pairs and convert to Image ptrs */
  224. for (i = 0; i < prog.cReloc; i++)
  225. {
  226. fread(buf, 1, 4, fp);
  227. prog.relocTable[i] = LH(buf) +
  228. (((Int)LH(buf+2) + EXE_RELOCATION)<<4);
  229. }
  230. }
  231. /* Seek to start of image */
  232. fseek(fp, (Int)LH(&header.numParaHeader) * 16, SEEK_SET);
  233. }
  234. else
  235. { /* COM file
  236. * In this case the load module size is just the file length
  237. */
  238. fseek(fp, 0, SEEK_END);
  239. cb = ftell(fp);
  240. /* COM programs start off with an ORG 100H (to leave room for a PSP)
  241. * This is also the implied start address so if we load the image
  242. * at offset 100H addresses should all line up properly again.
  243. */
  244. prog.initCS = 0;
  245. prog.initIP = 0x100;
  246. prog.initSS = 0;
  247. prog.initSP = 0xFFFE;
  248. prog.cReloc = 0;
  249. fseek(fp, 0, SEEK_SET);
  250. }
  251. /* Allocate a block of memory for the program. */
  252. prog.cbImage = cb + sizeof(PSP);
  253. prog.Image = (byte*)allocMem(prog.cbImage);
  254. prog.Image[0] = 0xCD; /* Fill in PSP Int 20h location */
  255. prog.Image[1] = 0x20; /* for termination checking */
  256. /* Read in the image past where a PSP would go */
  257. #ifdef __DOSWIN__
  258. if (cb > 0xFFFF)
  259. {
  260. printf("Image size of %ld bytes too large for fread!\n", cb);
  261. fatalError(CANNOT_READ, filename);
  262. }
  263. #endif
  264. if (cb != (Int)fread(prog.Image + sizeof(PSP), 1, (size_t)cb, fp))
  265. {
  266. fatalError(CANNOT_READ, filename);
  267. }
  268. /* Set up memory map */
  269. cb = (prog.cbImage + 3) / 4;
  270. prog.map = (byte *)memset(allocMem(cb), BM_UNKNOWN, (size_t)cb);
  271. /* Relocate segment constants */
  272. if (prog.cReloc)
  273. {
  274. for (i = 0; i < prog.cReloc; i++)
  275. {
  276. byte *p = &prog.Image[prog.relocTable[i]];
  277. word w = (word)LH(p) + EXE_RELOCATION;
  278. *p++ = (byte)(w & 0x00FF);
  279. *p = (byte)((w & 0xFF00) >> 8);
  280. }
  281. }
  282. fclose(fp);
  283. }
  284. /*****************************************************************************
  285. * allocMem - malloc with failure test
  286. ****************************************************************************/
  287. void *allocMem(Int cb)
  288. {
  289. byte *p;
  290. //printf("Attempt to allocMem %5ld bytes\n", cb);
  291. if (! (p = (byte*)malloc((size_t)cb)))
  292. /* if (! (p = (byte*)calloc((size_t)cb, 1))) */
  293. {
  294. fatalError(MALLOC_FAILED, cb);
  295. }
  296. /*printf("allocMem: %p\n", p);/**/
  297. return p;
  298. }
  299. /*****************************************************************************
  300. * reallocVar - reallocs extra variable space
  301. ****************************************************************************/
  302. void *reallocVar(void *p, Int newsize)
  303. {
  304. /*printf("Attempt to reallocVar %5d bytes\n", newsize);/**/
  305. if (! (p = realloc((byte *)p, (size_t)newsize)))
  306. {
  307. fatalError(MALLOC_FAILED, newsize);
  308. }
  309. /*printf("reallocVar: %p\n", p);/**/
  310. return p;
  311. }
  312. #if 0
  313. void free(void *p)
  314. {
  315. _ffree(p);
  316. switch (_heapset('Z'))
  317. {
  318. case _HEAPBADBEGIN: printf("f: Bad heap begin\n"); getchar(); break;
  319. case _HEAPBADNODE: printf("f: Bad heap node\n"); getchar(); break;
  320. case _HEAPEMPTY: printf("f: Heap empty\n"); getchar(); break;
  321. case _HEAPOK:putchar('!');break;
  322. }/**/
  323. }
  324. #endif