bpatch.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. /* ------------------------------------------------------------------------- */
  2. /* "bpatch" : Keeps track of, and finally acts on, backpatch markers, */
  3. /* correcting symbol values not known at compilation time */
  4. /* */
  5. /* Part of Inform 6.33 */
  6. /* copyright (c) Graham Nelson 1993 - 2014 */
  7. /* */
  8. /* ------------------------------------------------------------------------- */
  9. #include "header.h"
  10. memory_block zcode_backpatch_table, zmachine_backpatch_table;
  11. int32 zcode_backpatch_size, zmachine_backpatch_size;
  12. /* ------------------------------------------------------------------------- */
  13. /* The mending operation */
  14. /* ------------------------------------------------------------------------- */
  15. int backpatch_marker, backpatch_size, backpatch_error_flag;
  16. static int32 backpatch_value_z(int32 value)
  17. { /* Corrects the quantity "value" according to backpatch_marker */
  18. ASSERT_ZCODE();
  19. if (asm_trace_level >= 4)
  20. printf("BP %s applied to %04x giving ",
  21. describe_mv(backpatch_marker), value);
  22. switch(backpatch_marker)
  23. { case STRING_MV:
  24. value += strings_offset/scale_factor; break;
  25. case ARRAY_MV:
  26. value += variables_offset; break;
  27. case IROUTINE_MV:
  28. if (OMIT_UNUSED_ROUTINES)
  29. value = df_stripped_address_for_address(value);
  30. value += code_offset/scale_factor;
  31. break;
  32. case VROUTINE_MV:
  33. if ((value<0) || (value>=VENEER_ROUTINES))
  34. { if (no_link_errors > 0) break;
  35. if (compiler_error
  36. ("Backpatch veneer routine number out of range"))
  37. { printf("Illegal BP veneer routine number: %d\n", value);
  38. backpatch_error_flag = TRUE;
  39. }
  40. value = 0;
  41. break;
  42. }
  43. value = veneer_routine_address[value];
  44. if (OMIT_UNUSED_ROUTINES)
  45. value = df_stripped_address_for_address(value);
  46. value += code_offset/scale_factor;
  47. break;
  48. case NO_OBJS_MV:
  49. value = no_objects; break;
  50. case INCON_MV:
  51. if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
  52. { if (no_link_errors > 0) break;
  53. if (compiler_error
  54. ("Backpatch system constant number out of range"))
  55. { printf("Illegal BP system constant number: %d\n", value);
  56. backpatch_error_flag = TRUE;
  57. }
  58. value = 0;
  59. break;
  60. }
  61. value = value_of_system_constant(value); break;
  62. case DWORD_MV:
  63. value = dictionary_offset + 7 +
  64. final_dict_order[value]*((version_number==3)?7:9);
  65. break;
  66. case ACTION_MV:
  67. break;
  68. case INHERIT_MV:
  69. value = 256*zmachine_paged_memory[value + prop_values_offset]
  70. + zmachine_paged_memory[value + prop_values_offset + 1];
  71. break;
  72. case INHERIT_INDIV_MV:
  73. value = 256*zmachine_paged_memory[value
  74. + individuals_offset]
  75. + zmachine_paged_memory[value
  76. + individuals_offset + 1];
  77. break;
  78. case INDIVPT_MV:
  79. value += individuals_offset;
  80. break;
  81. case MAIN_MV:
  82. value = symbol_index("Main", -1);
  83. if (stypes[value] != ROUTINE_T)
  84. error("No 'Main' routine has been defined");
  85. sflags[value] |= USED_SFLAG;
  86. value = svals[value];
  87. if (OMIT_UNUSED_ROUTINES)
  88. value = df_stripped_address_for_address(value);
  89. value += code_offset/scale_factor;
  90. break;
  91. case SYMBOL_MV:
  92. if ((value<0) || (value>=no_symbols))
  93. { if (no_link_errors > 0) break;
  94. if (compiler_error("Backpatch symbol number out of range"))
  95. { printf("Illegal BP symbol number: %d\n", value);
  96. backpatch_error_flag = TRUE;
  97. }
  98. value = 0;
  99. break;
  100. }
  101. if (sflags[value] & UNKNOWN_SFLAG)
  102. { if (!(sflags[value] & UERROR_SFLAG))
  103. { sflags[value] |= UERROR_SFLAG;
  104. error_named_at("No such constant as",
  105. (char *) symbs[value], slines[value]);
  106. }
  107. }
  108. else
  109. if (sflags[value] & CHANGE_SFLAG)
  110. { sflags[value] &= (~(CHANGE_SFLAG));
  111. backpatch_marker = (svals[value]/0x10000);
  112. if ((backpatch_marker < 0)
  113. || (backpatch_marker > LARGEST_BPATCH_MV))
  114. {
  115. if (no_link_errors == 0)
  116. { compiler_error_named(
  117. "Illegal backpatch marker attached to symbol",
  118. (char *) symbs[value]);
  119. backpatch_error_flag = TRUE;
  120. }
  121. }
  122. else
  123. svals[value] = backpatch_value_z((svals[value]) % 0x10000);
  124. }
  125. sflags[value] |= USED_SFLAG;
  126. { int t = stypes[value];
  127. value = svals[value];
  128. switch(t)
  129. { case ROUTINE_T:
  130. if (OMIT_UNUSED_ROUTINES)
  131. value = df_stripped_address_for_address(value);
  132. value += code_offset/scale_factor;
  133. break;
  134. case ARRAY_T: value += variables_offset; break;
  135. }
  136. }
  137. break;
  138. default:
  139. if (no_link_errors > 0) break;
  140. if (compiler_error("Illegal backpatch marker"))
  141. { printf("Illegal backpatch marker %d value %04x\n",
  142. backpatch_marker, value);
  143. backpatch_error_flag = TRUE;
  144. }
  145. break;
  146. }
  147. if (asm_trace_level >= 4) printf(" %04x\n", value);
  148. return(value);
  149. }
  150. static int32 backpatch_value_g(int32 value)
  151. { /* Corrects the quantity "value" according to backpatch_marker */
  152. int32 valaddr;
  153. ASSERT_GLULX();
  154. if (asm_trace_level >= 4)
  155. printf("BP %s applied to %04x giving ",
  156. describe_mv(backpatch_marker), value);
  157. switch(backpatch_marker)
  158. {
  159. case STRING_MV:
  160. if (value <= 0 || value > no_strings)
  161. compiler_error("Illegal string marker.");
  162. value = strings_offset + compressed_offsets[value-1]; break;
  163. case IROUTINE_MV:
  164. if (OMIT_UNUSED_ROUTINES)
  165. value = df_stripped_address_for_address(value);
  166. value += code_offset;
  167. break;
  168. case ARRAY_MV:
  169. value += arrays_offset; break;
  170. case VARIABLE_MV:
  171. value = variables_offset + (4*value); break;
  172. case OBJECT_MV:
  173. value = object_tree_offset + (OBJECT_BYTE_LENGTH*(value-1));
  174. break;
  175. case VROUTINE_MV:
  176. if ((value<0) || (value>=VENEER_ROUTINES))
  177. { if (no_link_errors > 0) break;
  178. if (compiler_error
  179. ("Backpatch veneer routine number out of range"))
  180. { printf("Illegal BP veneer routine number: %d\n", value);
  181. backpatch_error_flag = TRUE;
  182. }
  183. value = 0;
  184. break;
  185. }
  186. value = veneer_routine_address[value];
  187. if (OMIT_UNUSED_ROUTINES)
  188. value = df_stripped_address_for_address(value);
  189. value += code_offset;
  190. break;
  191. case NO_OBJS_MV:
  192. value = no_objects; break;
  193. case INCON_MV:
  194. if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
  195. { if (no_link_errors > 0) break;
  196. if (compiler_error
  197. ("Backpatch system constant number out of range"))
  198. { printf("Illegal BP system constant number: %d\n", value);
  199. backpatch_error_flag = TRUE;
  200. }
  201. value = 0;
  202. break;
  203. }
  204. value = value_of_system_constant(value); break;
  205. case DWORD_MV:
  206. value = dictionary_offset + 4
  207. + final_dict_order[value]*DICT_ENTRY_BYTE_LENGTH;
  208. break;
  209. case ACTION_MV:
  210. break;
  211. case INHERIT_MV:
  212. valaddr = (prop_values_offset - Write_RAM_At) + value;
  213. value = ReadInt32(zmachine_paged_memory + valaddr);
  214. break;
  215. case INHERIT_INDIV_MV:
  216. error("*** No individual property storage in Glulx ***");
  217. break;
  218. case INDIVPT_MV:
  219. value += individuals_offset;
  220. break;
  221. case MAIN_MV:
  222. value = symbol_index("Main", -1);
  223. if (stypes[value] != ROUTINE_T)
  224. error("No 'Main' routine has been defined");
  225. sflags[value] |= USED_SFLAG;
  226. value = svals[value];
  227. if (OMIT_UNUSED_ROUTINES)
  228. value = df_stripped_address_for_address(value);
  229. value += code_offset;
  230. break;
  231. case SYMBOL_MV:
  232. if ((value<0) || (value>=no_symbols))
  233. { if (no_link_errors > 0) break;
  234. if (compiler_error("Backpatch symbol number out of range"))
  235. { printf("Illegal BP symbol number: %d\n", value);
  236. backpatch_error_flag = TRUE;
  237. }
  238. value = 0;
  239. break;
  240. }
  241. if (sflags[value] & UNKNOWN_SFLAG)
  242. { if (!(sflags[value] & UERROR_SFLAG))
  243. { sflags[value] |= UERROR_SFLAG;
  244. error_named_at("No such constant as",
  245. (char *) symbs[value], slines[value]);
  246. }
  247. }
  248. else
  249. if (sflags[value] & CHANGE_SFLAG)
  250. { sflags[value] &= (~(CHANGE_SFLAG));
  251. backpatch_marker = smarks[value];
  252. if ((backpatch_marker < 0)
  253. || (backpatch_marker > LARGEST_BPATCH_MV))
  254. {
  255. if (no_link_errors == 0)
  256. { compiler_error_named(
  257. "Illegal backpatch marker attached to symbol",
  258. (char *) symbs[value]);
  259. backpatch_error_flag = TRUE;
  260. }
  261. }
  262. else
  263. svals[value] = backpatch_value_g(svals[value]);
  264. }
  265. sflags[value] |= USED_SFLAG;
  266. { int t = stypes[value];
  267. value = svals[value];
  268. switch(t)
  269. {
  270. case ROUTINE_T:
  271. if (OMIT_UNUSED_ROUTINES)
  272. value = df_stripped_address_for_address(value);
  273. value += code_offset;
  274. break;
  275. case ARRAY_T: value += arrays_offset; break;
  276. case OBJECT_T:
  277. case CLASS_T:
  278. value = object_tree_offset +
  279. (OBJECT_BYTE_LENGTH*(value-1));
  280. break;
  281. case ATTRIBUTE_T:
  282. /* value is unchanged */
  283. break;
  284. case CONSTANT_T:
  285. case INDIVIDUAL_PROPERTY_T:
  286. /* value is unchanged */
  287. break;
  288. default:
  289. error("*** Illegal backpatch marker in forward-declared \
  290. symbol");
  291. break;
  292. }
  293. }
  294. break;
  295. default:
  296. if (no_link_errors > 0) break;
  297. if (compiler_error("Illegal backpatch marker"))
  298. { printf("Illegal backpatch marker %d value %04x\n",
  299. backpatch_marker, value);
  300. backpatch_error_flag = TRUE;
  301. }
  302. break;
  303. }
  304. if (asm_trace_level >= 4) printf(" %04x\n", value);
  305. return(value);
  306. }
  307. extern int32 backpatch_value(int32 value)
  308. {
  309. if (!glulx_mode)
  310. return backpatch_value_z(value);
  311. else
  312. return backpatch_value_g(value);
  313. }
  314. static void backpatch_zmachine_z(int mv, int zmachine_area, int32 offset)
  315. { if (module_switch)
  316. { if (zmachine_area == PROP_DEFAULTS_ZA) return;
  317. }
  318. else
  319. { if (mv == OBJECT_MV) return;
  320. if (mv == IDENT_MV) return;
  321. if (mv == ACTION_MV) return;
  322. }
  323. /* printf("MV %d ZA %d Off %04x\n", mv, zmachine_area, offset); */
  324. write_byte_to_memory_block(&zmachine_backpatch_table,
  325. zmachine_backpatch_size++, mv);
  326. write_byte_to_memory_block(&zmachine_backpatch_table,
  327. zmachine_backpatch_size++, zmachine_area);
  328. write_byte_to_memory_block(&zmachine_backpatch_table,
  329. zmachine_backpatch_size++, offset/256);
  330. write_byte_to_memory_block(&zmachine_backpatch_table,
  331. zmachine_backpatch_size++, offset%256);
  332. }
  333. static void backpatch_zmachine_g(int mv, int zmachine_area, int32 offset)
  334. { if (module_switch)
  335. { if (zmachine_area == PROP_DEFAULTS_ZA) return;
  336. }
  337. else
  338. { if (mv == IDENT_MV) return;
  339. if (mv == ACTION_MV) return;
  340. }
  341. /* The backpatch table format for Glulx:
  342. First, the marker byte.
  343. Then, the zmachine area being patched.
  344. Then the four-byte address.
  345. */
  346. /* printf("+MV %d ZA %d Off %06x\n", mv, zmachine_area, offset); */
  347. write_byte_to_memory_block(&zmachine_backpatch_table,
  348. zmachine_backpatch_size++, mv);
  349. write_byte_to_memory_block(&zmachine_backpatch_table,
  350. zmachine_backpatch_size++, zmachine_area);
  351. write_byte_to_memory_block(&zmachine_backpatch_table,
  352. zmachine_backpatch_size++, (offset >> 24) & 0xFF);
  353. write_byte_to_memory_block(&zmachine_backpatch_table,
  354. zmachine_backpatch_size++, (offset >> 16) & 0xFF);
  355. write_byte_to_memory_block(&zmachine_backpatch_table,
  356. zmachine_backpatch_size++, (offset >> 8) & 0xFF);
  357. write_byte_to_memory_block(&zmachine_backpatch_table,
  358. zmachine_backpatch_size++, (offset) & 0xFF);
  359. }
  360. extern void backpatch_zmachine(int mv, int zmachine_area, int32 offset)
  361. {
  362. if (!glulx_mode)
  363. backpatch_zmachine_z(mv, zmachine_area, offset);
  364. else
  365. backpatch_zmachine_g(mv, zmachine_area, offset);
  366. }
  367. extern void backpatch_zmachine_image_z(void)
  368. { int bm = 0, zmachine_area; int32 offset, value, addr;
  369. ASSERT_ZCODE();
  370. backpatch_error_flag = FALSE;
  371. while (bm < zmachine_backpatch_size)
  372. { backpatch_marker
  373. = read_byte_from_memory_block(&zmachine_backpatch_table, bm);
  374. zmachine_area
  375. = read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
  376. offset
  377. = 256*read_byte_from_memory_block(&zmachine_backpatch_table,bm+2)
  378. + read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
  379. bm += 4;
  380. switch(zmachine_area)
  381. { case PROP_DEFAULTS_ZA: addr = prop_defaults_offset; break;
  382. case PROP_ZA: addr = prop_values_offset; break;
  383. case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
  384. case DYNAMIC_ARRAY_ZA: addr = variables_offset; break;
  385. default:
  386. if (no_link_errors == 0)
  387. if (compiler_error("Illegal area to backpatch"))
  388. backpatch_error_flag = TRUE;
  389. }
  390. addr += offset;
  391. value = 256*zmachine_paged_memory[addr]
  392. + zmachine_paged_memory[addr+1];
  393. value = backpatch_value_z(value);
  394. zmachine_paged_memory[addr] = value/256;
  395. zmachine_paged_memory[addr+1] = value%256;
  396. if (backpatch_error_flag)
  397. { backpatch_error_flag = FALSE;
  398. if (no_link_errors == 0)
  399. printf("*** MV %d ZA %d Off %04x ***\n",
  400. backpatch_marker, zmachine_area, offset);
  401. }
  402. }
  403. }
  404. extern void backpatch_zmachine_image_g(void)
  405. { int bm = 0, zmachine_area; int32 offset, value, addr;
  406. ASSERT_GLULX();
  407. backpatch_error_flag = FALSE;
  408. while (bm < zmachine_backpatch_size)
  409. { backpatch_marker
  410. = read_byte_from_memory_block(&zmachine_backpatch_table, bm);
  411. zmachine_area
  412. = read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
  413. offset = read_byte_from_memory_block(&zmachine_backpatch_table, bm+2);
  414. offset = (offset << 8) |
  415. read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
  416. offset = (offset << 8) |
  417. read_byte_from_memory_block(&zmachine_backpatch_table, bm+4);
  418. offset = (offset << 8) |
  419. read_byte_from_memory_block(&zmachine_backpatch_table, bm+5);
  420. bm += 6;
  421. /* printf("-MV %d ZA %d Off %06x\n", backpatch_marker, zmachine_area, offset); */
  422. switch(zmachine_area) {
  423. case PROP_DEFAULTS_ZA: addr = prop_defaults_offset+4; break;
  424. case PROP_ZA: addr = prop_values_offset; break;
  425. case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
  426. case ARRAY_ZA: addr = arrays_offset; break;
  427. case GLOBALVAR_ZA: addr = variables_offset; break;
  428. default:
  429. if (no_link_errors == 0)
  430. if (compiler_error("Illegal area to backpatch"))
  431. backpatch_error_flag = TRUE;
  432. }
  433. addr = addr + offset - Write_RAM_At;
  434. value = (zmachine_paged_memory[addr] << 24)
  435. | (zmachine_paged_memory[addr+1] << 16)
  436. | (zmachine_paged_memory[addr+2] << 8)
  437. | (zmachine_paged_memory[addr+3]);
  438. value = backpatch_value_g(value);
  439. zmachine_paged_memory[addr] = (value >> 24) & 0xFF;
  440. zmachine_paged_memory[addr+1] = (value >> 16) & 0xFF;
  441. zmachine_paged_memory[addr+2] = (value >> 8) & 0xFF;
  442. zmachine_paged_memory[addr+3] = (value) & 0xFF;
  443. if (backpatch_error_flag)
  444. { backpatch_error_flag = FALSE;
  445. if (no_link_errors == 0)
  446. printf("*** MV %d ZA %d Off %04x ***\n",
  447. backpatch_marker, zmachine_area, offset);
  448. }
  449. }
  450. }
  451. /* ========================================================================= */
  452. /* Data structure management routines */
  453. /* ------------------------------------------------------------------------- */
  454. extern void init_bpatch_vars(void)
  455. { initialise_memory_block(&zcode_backpatch_table);
  456. initialise_memory_block(&zmachine_backpatch_table);
  457. }
  458. extern void bpatch_begin_pass(void)
  459. { zcode_backpatch_size = 0;
  460. zmachine_backpatch_size = 0;
  461. }
  462. extern void bpatch_allocate_arrays(void)
  463. {
  464. }
  465. extern void bpatch_free_arrays(void)
  466. { deallocate_memory_block(&zcode_backpatch_table);
  467. deallocate_memory_block(&zmachine_backpatch_table);
  468. }
  469. /* ========================================================================= */