1 /* ------------------------------------------------------------------------- */
2 /* "bpatch" : Keeps track of, and finally acts on, backpatch markers, */
3 /* correcting symbol values not known at compilation time */
5 /* Part of Inform 6.35 */
6 /* copyright (c) Graham Nelson 1993 - 2021 */
8 /* Inform is free software: you can redistribute it and/or modify */
9 /* it under the terms of the GNU General Public License as published by */
10 /* the Free Software Foundation, either version 3 of the License, or */
11 /* (at your option) any later version. */
13 /* Inform is distributed in the hope that it will be useful, */
14 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
15 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
16 /* GNU General Public License for more details. */
18 /* You should have received a copy of the GNU General Public License */
19 /* along with Inform. If not, see https://gnu.org/licenses/ */
21 /* ------------------------------------------------------------------------- */
25 memory_block zcode_backpatch_table, staticarray_backpatch_table,
26 zmachine_backpatch_table;
27 int32 zcode_backpatch_size, staticarray_backpatch_size,
28 zmachine_backpatch_size;
30 /* ------------------------------------------------------------------------- */
31 /* The mending operation */
32 /* ------------------------------------------------------------------------- */
34 int backpatch_marker, backpatch_size, backpatch_error_flag;
36 static int32 backpatch_value_z(int32 value)
37 { /* Corrects the quantity "value" according to backpatch_marker */
41 if (asm_trace_level >= 4)
42 printf("BP %s applied to %04x giving ",
43 describe_mv(backpatch_marker), value);
45 switch(backpatch_marker)
47 value += strings_offset/scale_factor; break;
49 value += variables_offset; break;
51 value += static_arrays_offset; break;
53 if (OMIT_UNUSED_ROUTINES)
54 value = df_stripped_address_for_address(value);
55 value += code_offset/scale_factor;
58 if ((value<0) || (value>=VENEER_ROUTINES))
59 { if (no_link_errors > 0) break;
61 ("Backpatch veneer routine number out of range"))
62 { printf("Illegal BP veneer routine number: %d\n", value);
63 backpatch_error_flag = TRUE;
68 value = veneer_routine_address[value];
69 if (OMIT_UNUSED_ROUTINES)
70 value = df_stripped_address_for_address(value);
71 value += code_offset/scale_factor;
74 value = no_objects; break;
76 if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
77 { if (no_link_errors > 0) break;
79 ("Backpatch system constant number out of range"))
80 { printf("Illegal BP system constant number: %d\n", value);
81 backpatch_error_flag = TRUE;
86 value = value_of_system_constant(value); break;
88 value = dictionary_offset + 7 +
89 final_dict_order[value]*((version_number==3)?7:9);
94 value = 256*zmachine_paged_memory[value + prop_values_offset]
95 + zmachine_paged_memory[value + prop_values_offset + 1];
97 case INHERIT_INDIV_MV:
98 value = 256*zmachine_paged_memory[value
100 + zmachine_paged_memory[value
101 + individuals_offset + 1];
104 value += individuals_offset;
107 value = symbol_index("Main", -1);
108 if (stypes[value] != ROUTINE_T)
109 error("No 'Main' routine has been defined");
110 sflags[value] |= USED_SFLAG;
111 value = svals[value];
112 if (OMIT_UNUSED_ROUTINES)
113 value = df_stripped_address_for_address(value);
114 value += code_offset/scale_factor;
117 if ((value<0) || (value>=no_symbols))
118 { if (no_link_errors > 0) break;
119 if (compiler_error("Backpatch symbol number out of range"))
120 { printf("Illegal BP symbol number: %d\n", value);
121 backpatch_error_flag = TRUE;
126 if (sflags[value] & UNKNOWN_SFLAG)
127 { if (!(sflags[value] & UERROR_SFLAG))
128 { sflags[value] |= UERROR_SFLAG;
129 error_named_at("No such constant as",
130 (char *) symbs[value], slines[value]);
134 if (sflags[value] & CHANGE_SFLAG)
135 { sflags[value] &= (~(CHANGE_SFLAG));
136 backpatch_marker = (svals[value]/0x10000);
137 if ((backpatch_marker < 0)
138 || (backpatch_marker > LARGEST_BPATCH_MV))
140 if (no_link_errors == 0)
141 { compiler_error_named(
142 "Illegal backpatch marker attached to symbol",
143 (char *) symbs[value]);
144 backpatch_error_flag = TRUE;
148 svals[value] = backpatch_value_z((svals[value]) % 0x10000);
151 sflags[value] |= USED_SFLAG;
152 { int t = stypes[value];
153 value = svals[value];
156 if (OMIT_UNUSED_ROUTINES)
157 value = df_stripped_address_for_address(value);
158 value += code_offset/scale_factor;
160 case ARRAY_T: value += variables_offset; break;
161 case STATIC_ARRAY_T: value += static_arrays_offset; break;
166 if (no_link_errors > 0) break;
167 if (compiler_error("Illegal backpatch marker"))
168 { printf("Illegal backpatch marker %d value %04x\n",
169 backpatch_marker, value);
170 backpatch_error_flag = TRUE;
175 if (asm_trace_level >= 4) printf(" %04x\n", value);
180 static int32 backpatch_value_g(int32 value)
181 { /* Corrects the quantity "value" according to backpatch_marker */
186 if (asm_trace_level >= 4)
187 printf("BP %s applied to %04x giving ",
188 describe_mv(backpatch_marker), value);
190 switch(backpatch_marker)
193 if (value <= 0 || value > no_strings)
194 compiler_error("Illegal string marker.");
195 value = strings_offset + compressed_offsets[value-1]; break;
197 if (OMIT_UNUSED_ROUTINES)
198 value = df_stripped_address_for_address(value);
199 value += code_offset;
202 value += arrays_offset; break;
203 case STATIC_ARRAY_MV:
204 value += static_arrays_offset; break;
206 value = variables_offset + (4*value); break;
208 value = object_tree_offset + (OBJECT_BYTE_LENGTH*(value-1));
211 if ((value<0) || (value>=VENEER_ROUTINES))
212 { if (no_link_errors > 0) break;
214 ("Backpatch veneer routine number out of range"))
215 { printf("Illegal BP veneer routine number: %d\n", value);
216 backpatch_error_flag = TRUE;
221 value = veneer_routine_address[value];
222 if (OMIT_UNUSED_ROUTINES)
223 value = df_stripped_address_for_address(value);
224 value += code_offset;
227 value = no_objects; break;
229 if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
230 { if (no_link_errors > 0) break;
232 ("Backpatch system constant number out of range"))
233 { printf("Illegal BP system constant number: %d\n", value);
234 backpatch_error_flag = TRUE;
239 value = value_of_system_constant(value); break;
241 value = dictionary_offset + 4
242 + final_dict_order[value]*DICT_ENTRY_BYTE_LENGTH;
247 valaddr = (prop_values_offset - Write_RAM_At) + value;
248 value = ReadInt32(zmachine_paged_memory + valaddr);
250 case INHERIT_INDIV_MV:
251 error("*** No individual property storage in Glulx ***");
254 value += individuals_offset;
257 value = symbol_index("Main", -1);
258 if (stypes[value] != ROUTINE_T)
259 error("No 'Main' routine has been defined");
260 sflags[value] |= USED_SFLAG;
261 value = svals[value];
262 if (OMIT_UNUSED_ROUTINES)
263 value = df_stripped_address_for_address(value);
264 value += code_offset;
267 if ((value<0) || (value>=no_symbols))
268 { if (no_link_errors > 0) break;
269 if (compiler_error("Backpatch symbol number out of range"))
270 { printf("Illegal BP symbol number: %d\n", value);
271 backpatch_error_flag = TRUE;
276 if (sflags[value] & UNKNOWN_SFLAG)
277 { if (!(sflags[value] & UERROR_SFLAG))
278 { sflags[value] |= UERROR_SFLAG;
279 error_named_at("No such constant as",
280 (char *) symbs[value], slines[value]);
284 if (sflags[value] & CHANGE_SFLAG)
285 { sflags[value] &= (~(CHANGE_SFLAG));
286 backpatch_marker = smarks[value];
287 if ((backpatch_marker < 0)
288 || (backpatch_marker > LARGEST_BPATCH_MV))
290 if (no_link_errors == 0)
291 { compiler_error_named(
292 "Illegal backpatch marker attached to symbol",
293 (char *) symbs[value]);
294 backpatch_error_flag = TRUE;
298 svals[value] = backpatch_value_g(svals[value]);
301 sflags[value] |= USED_SFLAG;
302 { int t = stypes[value];
303 value = svals[value];
307 if (OMIT_UNUSED_ROUTINES)
308 value = df_stripped_address_for_address(value);
309 value += code_offset;
311 case ARRAY_T: value += arrays_offset; break;
312 case STATIC_ARRAY_T: value += static_arrays_offset; break;
315 value = object_tree_offset +
316 (OBJECT_BYTE_LENGTH*(value-1));
319 /* value is unchanged */
322 case INDIVIDUAL_PROPERTY_T:
323 /* value is unchanged */
326 error("*** Illegal backpatch marker in forward-declared \
333 if (no_link_errors > 0) break;
334 if (compiler_error("Illegal backpatch marker"))
335 { printf("Illegal backpatch marker %d value %04x\n",
336 backpatch_marker, value);
337 backpatch_error_flag = TRUE;
342 if (asm_trace_level >= 4) printf(" %04x\n", value);
347 extern int32 backpatch_value(int32 value)
350 return backpatch_value_z(value);
352 return backpatch_value_g(value);
355 static void backpatch_zmachine_z(int mv, int zmachine_area, int32 offset)
357 { if (zmachine_area == PROP_DEFAULTS_ZA) return;
360 { if (mv == OBJECT_MV) return;
361 if (mv == IDENT_MV) return;
362 if (mv == ACTION_MV) return;
365 /* printf("MV %d ZA %d Off %04x\n", mv, zmachine_area, offset); */
367 write_byte_to_memory_block(&zmachine_backpatch_table,
368 zmachine_backpatch_size++, mv);
369 write_byte_to_memory_block(&zmachine_backpatch_table,
370 zmachine_backpatch_size++, zmachine_area);
371 write_byte_to_memory_block(&zmachine_backpatch_table,
372 zmachine_backpatch_size++, offset/256);
373 write_byte_to_memory_block(&zmachine_backpatch_table,
374 zmachine_backpatch_size++, offset%256);
377 static void backpatch_zmachine_g(int mv, int zmachine_area, int32 offset)
379 { if (zmachine_area == PROP_DEFAULTS_ZA) return;
382 { if (mv == IDENT_MV) return;
383 if (mv == ACTION_MV) return;
386 /* The backpatch table format for Glulx:
387 First, the marker byte.
388 Then, the zmachine area being patched.
389 Then the four-byte address.
392 /* printf("+MV %d ZA %d Off %06x\n", mv, zmachine_area, offset); */
394 write_byte_to_memory_block(&zmachine_backpatch_table,
395 zmachine_backpatch_size++, mv);
396 write_byte_to_memory_block(&zmachine_backpatch_table,
397 zmachine_backpatch_size++, zmachine_area);
398 write_byte_to_memory_block(&zmachine_backpatch_table,
399 zmachine_backpatch_size++, (offset >> 24) & 0xFF);
400 write_byte_to_memory_block(&zmachine_backpatch_table,
401 zmachine_backpatch_size++, (offset >> 16) & 0xFF);
402 write_byte_to_memory_block(&zmachine_backpatch_table,
403 zmachine_backpatch_size++, (offset >> 8) & 0xFF);
404 write_byte_to_memory_block(&zmachine_backpatch_table,
405 zmachine_backpatch_size++, (offset) & 0xFF);
408 extern void backpatch_zmachine(int mv, int zmachine_area, int32 offset)
411 backpatch_zmachine_z(mv, zmachine_area, offset);
413 backpatch_zmachine_g(mv, zmachine_area, offset);
416 extern void backpatch_zmachine_image_z(void)
417 { int bm = 0, zmachine_area; int32 offset, value, addr = 0;
419 backpatch_error_flag = FALSE;
420 while (bm < zmachine_backpatch_size)
422 = read_byte_from_memory_block(&zmachine_backpatch_table, bm);
424 = read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
426 = 256*read_byte_from_memory_block(&zmachine_backpatch_table,bm+2)
427 + read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
430 switch(zmachine_area)
431 { case PROP_DEFAULTS_ZA: addr = prop_defaults_offset; break;
432 case PROP_ZA: addr = prop_values_offset; break;
433 case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
434 case DYNAMIC_ARRAY_ZA: addr = variables_offset; break;
435 case STATIC_ARRAY_ZA: addr = static_arrays_offset; break;
437 if (no_link_errors == 0)
438 if (compiler_error("Illegal area to backpatch"))
439 backpatch_error_flag = TRUE;
443 value = 256*zmachine_paged_memory[addr]
444 + zmachine_paged_memory[addr+1];
445 value = backpatch_value_z(value);
446 zmachine_paged_memory[addr] = value/256;
447 zmachine_paged_memory[addr+1] = value%256;
449 if (backpatch_error_flag)
450 { backpatch_error_flag = FALSE;
451 if (no_link_errors == 0)
452 printf("*** MV %d ZA %d Off %04x ***\n",
453 backpatch_marker, zmachine_area, offset);
458 extern void backpatch_zmachine_image_g(void)
459 { int bm = 0, zmachine_area; int32 offset, value, addr = 0;
461 backpatch_error_flag = FALSE;
462 while (bm < zmachine_backpatch_size)
464 = read_byte_from_memory_block(&zmachine_backpatch_table, bm);
466 = read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
467 offset = read_byte_from_memory_block(&zmachine_backpatch_table, bm+2);
468 offset = (offset << 8) |
469 read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
470 offset = (offset << 8) |
471 read_byte_from_memory_block(&zmachine_backpatch_table, bm+4);
472 offset = (offset << 8) |
473 read_byte_from_memory_block(&zmachine_backpatch_table, bm+5);
476 /* printf("-MV %d ZA %d Off %06x\n", backpatch_marker, zmachine_area, offset); */
478 switch(zmachine_area) {
479 case PROP_DEFAULTS_ZA: addr = prop_defaults_offset+4; break;
480 case PROP_ZA: addr = prop_values_offset; break;
481 case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
482 case DYNAMIC_ARRAY_ZA: addr = arrays_offset; break;
483 case GLOBALVAR_ZA: addr = variables_offset; break;
484 /* STATIC_ARRAY_ZA is in ROM and therefore not handled here */
486 if (no_link_errors == 0)
487 if (compiler_error("Illegal area to backpatch"))
488 backpatch_error_flag = TRUE;
490 addr = addr + offset - Write_RAM_At;
492 value = (zmachine_paged_memory[addr] << 24)
493 | (zmachine_paged_memory[addr+1] << 16)
494 | (zmachine_paged_memory[addr+2] << 8)
495 | (zmachine_paged_memory[addr+3]);
496 value = backpatch_value_g(value);
497 zmachine_paged_memory[addr] = (value >> 24) & 0xFF;
498 zmachine_paged_memory[addr+1] = (value >> 16) & 0xFF;
499 zmachine_paged_memory[addr+2] = (value >> 8) & 0xFF;
500 zmachine_paged_memory[addr+3] = (value) & 0xFF;
502 if (backpatch_error_flag)
503 { backpatch_error_flag = FALSE;
504 if (no_link_errors == 0)
505 printf("*** MV %d ZA %d Off %04x ***\n",
506 backpatch_marker, zmachine_area, offset);
511 /* ========================================================================= */
512 /* Data structure management routines */
513 /* ------------------------------------------------------------------------- */
515 extern void init_bpatch_vars(void)
516 { initialise_memory_block(&zcode_backpatch_table);
517 initialise_memory_block(&staticarray_backpatch_table);
518 initialise_memory_block(&zmachine_backpatch_table);
521 extern void bpatch_begin_pass(void)
522 { zcode_backpatch_size = 0;
523 staticarray_backpatch_size = 0;
524 zmachine_backpatch_size = 0;
527 extern void bpatch_allocate_arrays(void)
531 extern void bpatch_free_arrays(void)
532 { deallocate_memory_block(&zcode_backpatch_table);
533 deallocate_memory_block(&staticarray_backpatch_table);
534 deallocate_memory_block(&zmachine_backpatch_table);
537 /* ========================================================================= */