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.40 */
6 /* copyright (c) Graham Nelson 1993 - 2022 */
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 uchar *staticarray_backpatch_table; /* Allocated to staticarray_backpatch_size */
26 memory_list staticarray_backpatch_table_memlist;
27 uchar *zmachine_backpatch_table; /* Allocated to zmachine_backpatch_size */
28 memory_list zmachine_backpatch_table_memlist;
29 uchar *zcode_backpatch_table; /* Allocated to zcode_backpatch_size */
30 memory_list zcode_backpatch_table_memlist;
31 int32 zcode_backpatch_size, staticarray_backpatch_size,
32 zmachine_backpatch_size;
34 /* ------------------------------------------------------------------------- */
35 /* The mending operation */
36 /* ------------------------------------------------------------------------- */
38 int backpatch_marker, backpatch_size, backpatch_error_flag;
40 static int32 backpatch_value_z(int32 value)
41 { /* Corrects the quantity "value" according to backpatch_marker */
45 if (bpatch_trace_setting)
46 printf("BP %s applied to %04x giving ",
47 describe_mv(backpatch_marker), value);
49 switch(backpatch_marker)
51 value += strings_offset/scale_factor; break;
53 value += variables_offset; break;
55 value += static_arrays_offset; break;
57 if (OMIT_UNUSED_ROUTINES)
58 value = df_stripped_address_for_address(value);
59 value += code_offset/scale_factor;
62 if ((value<0) || (value>=VENEER_ROUTINES))
63 { if (no_link_errors > 0) break;
65 ("Backpatch veneer routine number out of range"))
66 { printf("Illegal BP veneer routine number: %d\n", value);
67 backpatch_error_flag = TRUE;
72 value = veneer_routine_address[value];
73 if (OMIT_UNUSED_ROUTINES)
74 value = df_stripped_address_for_address(value);
75 value += code_offset/scale_factor;
78 value = no_objects; break;
80 if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
81 { if (no_link_errors > 0) break;
83 ("Backpatch system constant number out of range"))
84 { printf("Illegal BP system constant number: %d\n", value);
85 backpatch_error_flag = TRUE;
90 value = value_of_system_constant(value); break;
92 value = dictionary_offset + 7 +
93 final_dict_order[value]*(DICT_ENTRY_BYTE_LENGTH);
98 value = 256*zmachine_paged_memory[value + prop_values_offset]
99 + zmachine_paged_memory[value + prop_values_offset + 1];
101 case INHERIT_INDIV_MV:
102 value = 256*zmachine_paged_memory[value
103 + individuals_offset]
104 + zmachine_paged_memory[value
105 + individuals_offset + 1];
108 value += individuals_offset;
111 value = symbol_index("Main", -1);
112 if (symbols[value].type != ROUTINE_T)
113 error("No 'Main' routine has been defined");
114 symbols[value].flags |= USED_SFLAG;
115 value = symbols[value].value;
116 if (OMIT_UNUSED_ROUTINES)
117 value = df_stripped_address_for_address(value);
118 value += code_offset/scale_factor;
121 if ((value<0) || (value>=no_symbols))
122 { if (no_link_errors > 0) break;
123 if (compiler_error("Backpatch symbol number out of range"))
124 { printf("Illegal BP symbol number: %d\n", value);
125 backpatch_error_flag = TRUE;
130 if (symbols[value].flags & UNKNOWN_SFLAG)
131 { if (!(symbols[value].flags & UERROR_SFLAG))
132 { symbols[value].flags |= UERROR_SFLAG;
133 error_named_at("No such constant as",
134 symbols[value].name, symbols[value].line);
138 if (symbols[value].flags & CHANGE_SFLAG)
139 { symbols[value].flags &= (~(CHANGE_SFLAG));
140 backpatch_marker = (symbols[value].marker);
141 if ((backpatch_marker < 0)
142 || (backpatch_marker > LARGEST_BPATCH_MV))
144 if (no_link_errors == 0)
145 { compiler_error_named(
146 "Illegal backpatch marker attached to symbol",
147 symbols[value].name);
148 backpatch_error_flag = TRUE;
152 symbols[value].value = backpatch_value_z((symbols[value].value) % 0x10000);
155 symbols[value].flags |= USED_SFLAG;
156 { int t = symbols[value].type;
157 value = symbols[value].value;
160 if (OMIT_UNUSED_ROUTINES)
161 value = df_stripped_address_for_address(value);
162 value += code_offset/scale_factor;
164 case ARRAY_T: value += variables_offset; break;
165 case STATIC_ARRAY_T: value += static_arrays_offset; break;
170 if (no_link_errors > 0) break;
171 if (compiler_error("Illegal backpatch marker"))
172 { printf("Illegal backpatch marker %d value %04x\n",
173 backpatch_marker, value);
174 backpatch_error_flag = TRUE;
179 if (bpatch_trace_setting) printf(" %04x\n", value);
184 static int32 backpatch_value_g(int32 value)
185 { /* Corrects the quantity "value" according to backpatch_marker */
190 if (bpatch_trace_setting)
191 printf("BP %s applied to %04x giving ",
192 describe_mv(backpatch_marker), value);
194 switch(backpatch_marker)
197 if (value <= 0 || value > no_strings)
198 compiler_error("Illegal string marker.");
199 value = strings_offset + compressed_offsets[value-1]; break;
201 if (OMIT_UNUSED_ROUTINES)
202 value = df_stripped_address_for_address(value);
203 value += code_offset;
206 value += arrays_offset; break;
207 case STATIC_ARRAY_MV:
208 value += static_arrays_offset; break;
210 value = variables_offset + (4*value); break;
212 value = object_tree_offset + (OBJECT_BYTE_LENGTH*(value-1));
215 if ((value<0) || (value>=VENEER_ROUTINES))
216 { if (no_link_errors > 0) break;
218 ("Backpatch veneer routine number out of range"))
219 { printf("Illegal BP veneer routine number: %d\n", value);
220 backpatch_error_flag = TRUE;
225 value = veneer_routine_address[value];
226 if (OMIT_UNUSED_ROUTINES)
227 value = df_stripped_address_for_address(value);
228 value += code_offset;
231 value = no_objects; break;
233 if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
234 { if (no_link_errors > 0) break;
236 ("Backpatch system constant number out of range"))
237 { printf("Illegal BP system constant number: %d\n", value);
238 backpatch_error_flag = TRUE;
243 value = value_of_system_constant(value); break;
245 value = dictionary_offset + 4
246 + final_dict_order[value]*DICT_ENTRY_BYTE_LENGTH;
251 valaddr = (prop_values_offset - Write_RAM_At) + value;
252 value = ReadInt32(zmachine_paged_memory + valaddr);
254 case INHERIT_INDIV_MV:
255 error("*** No individual property storage in Glulx ***");
258 value += individuals_offset;
261 value = symbol_index("Main", -1);
262 if (symbols[value].type != ROUTINE_T)
263 error("No 'Main' routine has been defined");
264 symbols[value].flags |= USED_SFLAG;
265 value = symbols[value].value;
266 if (OMIT_UNUSED_ROUTINES)
267 value = df_stripped_address_for_address(value);
268 value += code_offset;
271 if ((value<0) || (value>=no_symbols))
272 { if (no_link_errors > 0) break;
273 if (compiler_error("Backpatch symbol number out of range"))
274 { printf("Illegal BP symbol number: %d\n", value);
275 backpatch_error_flag = TRUE;
280 if (symbols[value].flags & UNKNOWN_SFLAG)
281 { if (!(symbols[value].flags & UERROR_SFLAG))
282 { symbols[value].flags |= UERROR_SFLAG;
283 error_named_at("No such constant as",
284 symbols[value].name, symbols[value].line);
288 if (symbols[value].flags & CHANGE_SFLAG)
289 { symbols[value].flags &= (~(CHANGE_SFLAG));
290 backpatch_marker = symbols[value].marker;
291 if ((backpatch_marker < 0)
292 || (backpatch_marker > LARGEST_BPATCH_MV))
294 if (no_link_errors == 0)
295 { compiler_error_named(
296 "Illegal backpatch marker attached to symbol",
297 symbols[value].name);
298 backpatch_error_flag = TRUE;
302 symbols[value].value = backpatch_value_g(symbols[value].value);
305 symbols[value].flags |= USED_SFLAG;
306 { int t = symbols[value].type;
307 value = symbols[value].value;
311 if (OMIT_UNUSED_ROUTINES)
312 value = df_stripped_address_for_address(value);
313 value += code_offset;
315 case ARRAY_T: value += arrays_offset; break;
316 case STATIC_ARRAY_T: value += static_arrays_offset; break;
319 value = object_tree_offset +
320 (OBJECT_BYTE_LENGTH*(value-1));
323 /* value is unchanged */
326 case INDIVIDUAL_PROPERTY_T:
328 /* value is unchanged */
331 error("*** Illegal backpatch marker in forward-declared \
338 if (no_link_errors > 0) break;
339 if (compiler_error("Illegal backpatch marker"))
340 { printf("Illegal backpatch marker %d value %04x\n",
341 backpatch_marker, value);
342 backpatch_error_flag = TRUE;
347 if (bpatch_trace_setting) printf(" %04x\n", value);
352 extern int32 backpatch_value(int32 value)
355 return backpatch_value_z(value);
357 return backpatch_value_g(value);
360 static void backpatch_zmachine_z(int mv, int zmachine_area, int32 offset)
362 { if (zmachine_area == PROP_DEFAULTS_ZA) return;
365 { if (mv == OBJECT_MV) return;
366 if (mv == IDENT_MV) return;
367 if (mv == ACTION_MV) return;
370 if (bpatch_trace_setting >= 2)
371 printf("BP added: MV %d ZA %d Off %04x\n", mv, zmachine_area, offset);
373 ensure_memory_list_available(&zmachine_backpatch_table_memlist, zmachine_backpatch_size+4);
374 zmachine_backpatch_table[zmachine_backpatch_size++] = mv;
375 zmachine_backpatch_table[zmachine_backpatch_size++] = zmachine_area;
376 zmachine_backpatch_table[zmachine_backpatch_size++] = offset/256;
377 zmachine_backpatch_table[zmachine_backpatch_size++] = offset%256;
380 static void backpatch_zmachine_g(int mv, int zmachine_area, int32 offset)
382 { if (zmachine_area == PROP_DEFAULTS_ZA) return;
385 { if (mv == IDENT_MV) return;
386 if (mv == ACTION_MV) return;
389 /* The backpatch table format for Glulx:
390 First, the marker byte.
391 Then, the zmachine area being patched.
392 Then the four-byte address.
395 if (bpatch_trace_setting >= 2)
396 printf("BP added: MV %d ZA %d Off %06x\n", mv, zmachine_area, offset);
398 ensure_memory_list_available(&zmachine_backpatch_table_memlist, zmachine_backpatch_size+6);
399 zmachine_backpatch_table[zmachine_backpatch_size++] = mv;
400 zmachine_backpatch_table[zmachine_backpatch_size++] = zmachine_area;
401 zmachine_backpatch_table[zmachine_backpatch_size++] = (offset >> 24) & 0xFF;
402 zmachine_backpatch_table[zmachine_backpatch_size++] = (offset >> 16) & 0xFF;
403 zmachine_backpatch_table[zmachine_backpatch_size++] = (offset >> 8) & 0xFF;
404 zmachine_backpatch_table[zmachine_backpatch_size++] = (offset) & 0xFF;
407 extern void backpatch_zmachine(int mv, int zmachine_area, int32 offset)
410 backpatch_zmachine_z(mv, zmachine_area, offset);
412 backpatch_zmachine_g(mv, zmachine_area, offset);
415 extern void backpatch_zmachine_image_z(void)
416 { int bm = 0, zmachine_area; int32 offset, value, addr = 0;
418 backpatch_error_flag = FALSE;
419 while (bm < zmachine_backpatch_size)
421 = zmachine_backpatch_table[bm];
423 = zmachine_backpatch_table[bm+1];
425 = 256*zmachine_backpatch_table[bm+2]
426 + zmachine_backpatch_table[bm+3];
429 switch(zmachine_area)
430 { case PROP_DEFAULTS_ZA: addr = prop_defaults_offset; break;
431 case PROP_ZA: addr = prop_values_offset; break;
432 case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
433 case DYNAMIC_ARRAY_ZA: addr = variables_offset; break;
434 case STATIC_ARRAY_ZA: addr = static_arrays_offset; break;
436 if (no_link_errors == 0)
437 if (compiler_error("Illegal area to backpatch"))
438 backpatch_error_flag = TRUE;
442 value = 256*zmachine_paged_memory[addr]
443 + zmachine_paged_memory[addr+1];
444 value = backpatch_value_z(value);
445 zmachine_paged_memory[addr] = value/256;
446 zmachine_paged_memory[addr+1] = value%256;
448 if (backpatch_error_flag)
449 { backpatch_error_flag = FALSE;
450 if (no_link_errors == 0)
451 printf("*** MV %d ZA %d Off %04x ***\n",
452 backpatch_marker, zmachine_area, offset);
457 extern void backpatch_zmachine_image_g(void)
458 { int bm = 0, zmachine_area; int32 offset, value, addr = 0;
460 backpatch_error_flag = FALSE;
461 while (bm < zmachine_backpatch_size)
463 = zmachine_backpatch_table[bm];
465 = zmachine_backpatch_table[bm+1];
466 offset = zmachine_backpatch_table[bm+2];
467 offset = (offset << 8) |
468 zmachine_backpatch_table[bm+3];
469 offset = (offset << 8) |
470 zmachine_backpatch_table[bm+4];
471 offset = (offset << 8) |
472 zmachine_backpatch_table[bm+5];
475 switch(zmachine_area) {
476 case PROP_DEFAULTS_ZA: addr = prop_defaults_offset+4; break;
477 case PROP_ZA: addr = prop_values_offset; break;
478 case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
479 case DYNAMIC_ARRAY_ZA: addr = arrays_offset; break;
480 case GLOBALVAR_ZA: addr = variables_offset; break;
481 /* STATIC_ARRAY_ZA is in ROM and therefore not handled here */
483 if (no_link_errors == 0)
484 if (compiler_error("Illegal area to backpatch"))
485 backpatch_error_flag = TRUE;
487 addr = addr + offset - Write_RAM_At;
489 value = (zmachine_paged_memory[addr] << 24)
490 | (zmachine_paged_memory[addr+1] << 16)
491 | (zmachine_paged_memory[addr+2] << 8)
492 | (zmachine_paged_memory[addr+3]);
493 value = backpatch_value_g(value);
494 zmachine_paged_memory[addr] = (value >> 24) & 0xFF;
495 zmachine_paged_memory[addr+1] = (value >> 16) & 0xFF;
496 zmachine_paged_memory[addr+2] = (value >> 8) & 0xFF;
497 zmachine_paged_memory[addr+3] = (value) & 0xFF;
499 if (backpatch_error_flag)
500 { backpatch_error_flag = FALSE;
501 if (no_link_errors == 0)
502 printf("*** MV %d ZA %d Off %04x ***\n",
503 backpatch_marker, zmachine_area, offset);
508 /* ========================================================================= */
509 /* Data structure management routines */
510 /* ------------------------------------------------------------------------- */
512 extern void init_bpatch_vars(void)
513 { zcode_backpatch_table = NULL;
514 staticarray_backpatch_table = NULL;
515 zmachine_backpatch_table = NULL;
518 extern void bpatch_begin_pass(void)
519 { zcode_backpatch_size = 0;
520 staticarray_backpatch_size = 0;
521 zmachine_backpatch_size = 0;
524 extern void bpatch_allocate_arrays(void)
526 initialise_memory_list(&zcode_backpatch_table_memlist,
527 sizeof(uchar), 128, (void**)&zcode_backpatch_table,
528 "code backpatch table");
529 initialise_memory_list(&staticarray_backpatch_table_memlist,
530 sizeof(uchar), 128, (void**)&staticarray_backpatch_table,
531 "static array backpatch table");
532 initialise_memory_list(&zmachine_backpatch_table_memlist,
533 sizeof(uchar), 128, (void**)&zmachine_backpatch_table,
534 "machine backpatch table");
537 extern void bpatch_free_arrays(void)
538 { deallocate_memory_list(&zcode_backpatch_table_memlist);
539 deallocate_memory_list(&staticarray_backpatch_table_memlist);
540 deallocate_memory_list(&zmachine_backpatch_table_memlist);
543 /* ========================================================================= */