frontend.cpp 12 KB

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