frontend.cpp 11 KB

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