1 /* ------------------------------------------------------------------------- */
2 /* "bpatch" : Keeps track of, and finally acts on, backpatch markers, */
3 /* correcting symbol values not known at compilation time */
5 /* Copyright (c) Graham Nelson 1993 - 2020 */
7 /* This file is part of Inform. */
9 /* Inform is free software: you can redistribute it and/or modify */
10 /* it under the terms of the GNU General Public License as published by */
11 /* the Free Software Foundation, either version 3 of the License, or */
12 /* (at your option) any later version. */
14 /* Inform is distributed in the hope that it will be useful, */
15 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
16 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
17 /* GNU General Public License for more details. */
19 /* You should have received a copy of the GNU General Public License */
20 /* along with Inform. If not, see https://gnu.org/licenses/ */
22 /* ------------------------------------------------------------------------- */
26 memory_block zcode_backpatch_table, staticarray_backpatch_table,
27 zmachine_backpatch_table;
28 int32 zcode_backpatch_size, staticarray_backpatch_size,
29 zmachine_backpatch_size;
31 /* ------------------------------------------------------------------------- */
32 /* The mending operation */
33 /* ------------------------------------------------------------------------- */
35 int backpatch_marker, backpatch_size, backpatch_error_flag;
37 static int32 backpatch_value_z(int32 value)
38 { /* Corrects the quantity "value" according to backpatch_marker */
42 if (asm_trace_level >= 4)
43 printf("BP %s applied to %04x giving ",
44 describe_mv(backpatch_marker), value);
46 switch(backpatch_marker)
48 value += strings_offset/scale_factor; break;
50 value += variables_offset; break;
52 value += static_arrays_offset; break;
54 if (OMIT_UNUSED_ROUTINES)
55 value = df_stripped_address_for_address(value);
56 value += code_offset/scale_factor;
59 if ((value<0) || (value>=VENEER_ROUTINES))
60 { if (no_link_errors > 0) break;
62 ("Backpatch veneer routine number out of range"))
63 { printf("Illegal BP veneer routine number: %d\n", value);
64 backpatch_error_flag = TRUE;
69 value = veneer_routine_address[value];
70 if (OMIT_UNUSED_ROUTINES)
71 value = df_stripped_address_for_address(value);
72 value += code_offset/scale_factor;
75 value = no_objects; break;
77 if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
78 { if (no_link_errors > 0) break;
80 ("Backpatch system constant number out of range"))
81 { printf("Illegal BP system constant number: %d\n", value);
82 backpatch_error_flag = TRUE;
87 value = value_of_system_constant(value); break;
89 value = dictionary_offset + 7 +
90 final_dict_order[value]*((version_number==3)?7:9);
95 value = 256*zmachine_paged_memory[value + prop_values_offset]
96 + zmachine_paged_memory[value + prop_values_offset + 1];
98 case INHERIT_INDIV_MV:
99 value = 256*zmachine_paged_memory[value
100 + individuals_offset]
101 + zmachine_paged_memory[value
102 + individuals_offset + 1];
105 value += individuals_offset;
108 value = symbol_index("Main", -1);
109 if (stypes[value] != ROUTINE_T)
110 error("No 'Main' routine has been defined");
111 sflags[value] |= USED_SFLAG;
112 value = svals[value];
113 if (OMIT_UNUSED_ROUTINES)
114 value = df_stripped_address_for_address(value);
115 value += code_offset/scale_factor;
118 if ((value<0) || (value>=no_symbols))
119 { if (no_link_errors > 0) break;
120 if (compiler_error("Backpatch symbol number out of range"))
121 { printf("Illegal BP symbol number: %d\n", value);
122 backpatch_error_flag = TRUE;
127 if (sflags[value] & UNKNOWN_SFLAG)
128 { if (!(sflags[value] & UERROR_SFLAG))
129 { sflags[value] |= UERROR_SFLAG;
130 error_named_at("No such constant as",
131 (char *) symbs[value], slines[value]);
135 if (sflags[value] & CHANGE_SFLAG)
136 { sflags[value] &= (~(CHANGE_SFLAG));
137 backpatch_marker = (svals[value]/0x10000);
138 if ((backpatch_marker < 0)
139 || (backpatch_marker > LARGEST_BPATCH_MV))
141 if (no_link_errors == 0)
142 { compiler_error_named(
143 "Illegal backpatch marker attached to symbol",
144 (char *) symbs[value]);
145 backpatch_error_flag = TRUE;
149 svals[value] = backpatch_value_z((svals[value]) % 0x10000);
152 sflags[value] |= USED_SFLAG;
153 { int t = stypes[value];
154 value = svals[value];
157 if (OMIT_UNUSED_ROUTINES)
158 value = df_stripped_address_for_address(value);
159 value += code_offset/scale_factor;
161 case ARRAY_T: value += variables_offset; break;
162 case STATIC_ARRAY_T: value += static_arrays_offset; break;
167 if (no_link_errors > 0) break;
168 if (compiler_error("Illegal backpatch marker"))
169 { printf("Illegal backpatch marker %d value %04x\n",
170 backpatch_marker, value);
171 backpatch_error_flag = TRUE;
176 if (asm_trace_level >= 4) printf(" %04x\n", value);
181 static int32 backpatch_value_g(int32 value)
182 { /* Corrects the quantity "value" according to backpatch_marker */
187 if (asm_trace_level >= 4)
188 printf("BP %s applied to %04x giving ",
189 describe_mv(backpatch_marker), value);
191 switch(backpatch_marker)
194 if (value <= 0 || value > no_strings)
195 compiler_error("Illegal string marker.");
196 value = strings_offset + compressed_offsets[value-1]; break;
198 if (OMIT_UNUSED_ROUTINES)
199 value = df_stripped_address_for_address(value);
200 value += code_offset;
203 value += arrays_offset; break;
204 case STATIC_ARRAY_MV:
205 value += static_arrays_offset; break;
207 value = variables_offset + (4*value); break;
209 value = object_tree_offset + (OBJECT_BYTE_LENGTH*(value-1));
212 if ((value<0) || (value>=VENEER_ROUTINES))
213 { if (no_link_errors > 0) break;
215 ("Backpatch veneer routine number out of range"))
216 { printf("Illegal BP veneer routine number: %d\n", value);
217 backpatch_error_flag = TRUE;
222 value = veneer_routine_address[value];
223 if (OMIT_UNUSED_ROUTINES)
224 value = df_stripped_address_for_address(value);
225 value += code_offset;
228 value = no_objects; break;
230 if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
231 { if (no_link_errors > 0) break;
233 ("Backpatch system constant number out of range"))
234 { printf("Illegal BP system constant number: %d\n", value);
235 backpatch_error_flag = TRUE;
240 value = value_of_system_constant(value); break;
242 value = dictionary_offset + 4
243 + final_dict_order[value]*DICT_ENTRY_BYTE_LENGTH;
248 valaddr = (prop_values_offset - Write_RAM_At) + value;
249 value = ReadInt32(zmachine_paged_memory + valaddr);
251 case INHERIT_INDIV_MV:
252 error("*** No individual property storage in Glulx ***");
255 value += individuals_offset;
258 value = symbol_index("Main", -1);
259 if (stypes[value] != ROUTINE_T)
260 error("No 'Main' routine has been defined");
261 sflags[value] |= USED_SFLAG;
262 value = svals[value];
263 if (OMIT_UNUSED_ROUTINES)
264 value = df_stripped_address_for_address(value);
265 value += code_offset;
268 if ((value<0) || (value>=no_symbols))
269 { if (no_link_errors > 0) break;
270 if (compiler_error("Backpatch symbol number out of range"))
271 { printf("Illegal BP symbol number: %d\n", value);
272 backpatch_error_flag = TRUE;
277 if (sflags[value] & UNKNOWN_SFLAG)
278 { if (!(sflags[value] & UERROR_SFLAG))
279 { sflags[value] |= UERROR_SFLAG;
280 error_named_at("No such constant as",
281 (char *) symbs[value], slines[value]);
285 if (sflags[value] & CHANGE_SFLAG)
286 { sflags[value] &= (~(CHANGE_SFLAG));
287 backpatch_marker = smarks[value];
288 if ((backpatch_marker < 0)
289 || (backpatch_marker > LARGEST_BPATCH_MV))
291 if (no_link_errors == 0)
292 { compiler_error_named(
293 "Illegal backpatch marker attached to symbol",
294 (char *) symbs[value]);
295 backpatch_error_flag = TRUE;
299 svals[value] = backpatch_value_g(svals[value]);
302 sflags[value] |= USED_SFLAG;
303 { int t = stypes[value];
304 value = svals[value];
308 if (OMIT_UNUSED_ROUTINES)
309 value = df_stripped_address_for_address(value);
310 value += code_offset;
312 case ARRAY_T: value += arrays_offset; break;
313 case STATIC_ARRAY_T: value += static_arrays_offset; break;
316 value = object_tree_offset +
317 (OBJECT_BYTE_LENGTH*(value-1));
320 /* value is unchanged */
323 case INDIVIDUAL_PROPERTY_T:
324 /* value is unchanged */
327 error("*** Illegal backpatch marker in forward-declared \
334 if (no_link_errors > 0) break;
335 if (compiler_error("Illegal backpatch marker"))
336 { printf("Illegal backpatch marker %d value %04x\n",
337 backpatch_marker, value);
338 backpatch_error_flag = TRUE;
343 if (asm_trace_level >= 4) printf(" %04x\n", value);
348 extern int32 backpatch_value(int32 value)
351 return backpatch_value_z(value);
353 return backpatch_value_g(value);
356 static void backpatch_zmachine_z(int mv, int zmachine_area, int32 offset)
358 { if (zmachine_area == PROP_DEFAULTS_ZA) return;
361 { if (mv == OBJECT_MV) return;
362 if (mv == IDENT_MV) return;
363 if (mv == ACTION_MV) return;
366 /* printf("MV %d ZA %d Off %04x\n", mv, zmachine_area, offset); */
368 write_byte_to_memory_block(&zmachine_backpatch_table,
369 zmachine_backpatch_size++, mv);
370 write_byte_to_memory_block(&zmachine_backpatch_table,
371 zmachine_backpatch_size++, zmachine_area);
372 write_byte_to_memory_block(&zmachine_backpatch_table,
373 zmachine_backpatch_size++, offset/256);
374 write_byte_to_memory_block(&zmachine_backpatch_table,
375 zmachine_backpatch_size++, offset%256);
378 static void backpatch_zmachine_g(int mv, int zmachine_area, int32 offset)
380 { if (zmachine_area == PROP_DEFAULTS_ZA) return;
383 { if (mv == IDENT_MV) return;
384 if (mv == ACTION_MV) return;
387 /* The backpatch table format for Glulx:
388 First, the marker byte.
389 Then, the zmachine area being patched.
390 Then the four-byte address.
393 /* printf("+MV %d ZA %d Off %06x\n", mv, zmachine_area, offset); */
395 write_byte_to_memory_block(&zmachine_backpatch_table,
396 zmachine_backpatch_size++, mv);
397 write_byte_to_memory_block(&zmachine_backpatch_table,
398 zmachine_backpatch_size++, zmachine_area);
399 write_byte_to_memory_block(&zmachine_backpatch_table,
400 zmachine_backpatch_size++, (offset >> 24) & 0xFF);
401 write_byte_to_memory_block(&zmachine_backpatch_table,
402 zmachine_backpatch_size++, (offset >> 16) & 0xFF);
403 write_byte_to_memory_block(&zmachine_backpatch_table,
404 zmachine_backpatch_size++, (offset >> 8) & 0xFF);
405 write_byte_to_memory_block(&zmachine_backpatch_table,
406 zmachine_backpatch_size++, (offset) & 0xFF);
409 extern void backpatch_zmachine(int mv, int zmachine_area, int32 offset)
412 backpatch_zmachine_z(mv, zmachine_area, offset);
414 backpatch_zmachine_g(mv, zmachine_area, offset);
417 extern void backpatch_zmachine_image_z(void)
418 { int bm = 0, zmachine_area; int32 offset, value, addr = 0;
420 backpatch_error_flag = FALSE;
421 while (bm < zmachine_backpatch_size)
423 = read_byte_from_memory_block(&zmachine_backpatch_table, bm);
425 = read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
427 = 256*read_byte_from_memory_block(&zmachine_backpatch_table,bm+2)
428 + read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
431 switch(zmachine_area)
432 { case PROP_DEFAULTS_ZA: addr = prop_defaults_offset; break;
433 case PROP_ZA: addr = prop_values_offset; break;
434 case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
435 case DYNAMIC_ARRAY_ZA: addr = variables_offset; break;
436 case STATIC_ARRAY_ZA: addr = static_arrays_offset; break;
438 if (no_link_errors == 0)
439 if (compiler_error("Illegal area to backpatch"))
440 backpatch_error_flag = TRUE;
444 value = 256*zmachine_paged_memory[addr]
445 + zmachine_paged_memory[addr+1];
446 value = backpatch_value_z(value);
447 zmachine_paged_memory[addr] = value/256;
448 zmachine_paged_memory[addr+1] = value%256;
450 if (backpatch_error_flag)
451 { backpatch_error_flag = FALSE;
452 if (no_link_errors == 0)
453 printf("*** MV %d ZA %d Off %04x ***\n",
454 backpatch_marker, zmachine_area, offset);
459 extern void backpatch_zmachine_image_g(void)
460 { int bm = 0, zmachine_area; int32 offset, value, addr = 0;
462 backpatch_error_flag = FALSE;
463 while (bm < zmachine_backpatch_size)
465 = read_byte_from_memory_block(&zmachine_backpatch_table, bm);
467 = read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
468 offset = read_byte_from_memory_block(&zmachine_backpatch_table, bm+2);
469 offset = (offset << 8) |
470 read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
471 offset = (offset << 8) |
472 read_byte_from_memory_block(&zmachine_backpatch_table, bm+4);
473 offset = (offset << 8) |
474 read_byte_from_memory_block(&zmachine_backpatch_table, bm+5);
477 /* printf("-MV %d ZA %d Off %06x\n", backpatch_marker, zmachine_area, offset); */
479 switch(zmachine_area) {
480 case PROP_DEFAULTS_ZA: addr = prop_defaults_offset+4; break;
481 case PROP_ZA: addr = prop_values_offset; break;
482 case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
483 case DYNAMIC_ARRAY_ZA: addr = arrays_offset; break;
484 case GLOBALVAR_ZA: addr = variables_offset; break;
485 /* STATIC_ARRAY_ZA is in ROM and therefore not handled here */
487 if (no_link_errors == 0)
488 if (compiler_error("Illegal area to backpatch"))
489 backpatch_error_flag = TRUE;
491 addr = addr + offset - Write_RAM_At;
493 value = (zmachine_paged_memory[addr] << 24)
494 | (zmachine_paged_memory[addr+1] << 16)
495 | (zmachine_paged_memory[addr+2] << 8)
496 | (zmachine_paged_memory[addr+3]);
497 value = backpatch_value_g(value);
498 zmachine_paged_memory[addr] = (value >> 24) & 0xFF;
499 zmachine_paged_memory[addr+1] = (value >> 16) & 0xFF;
500 zmachine_paged_memory[addr+2] = (value >> 8) & 0xFF;
501 zmachine_paged_memory[addr+3] = (value) & 0xFF;
503 if (backpatch_error_flag)
504 { backpatch_error_flag = FALSE;
505 if (no_link_errors == 0)
506 printf("*** MV %d ZA %d Off %04x ***\n",
507 backpatch_marker, zmachine_area, offset);
512 /* ========================================================================= */
513 /* Data structure management routines */
514 /* ------------------------------------------------------------------------- */
516 extern void init_bpatch_vars(void)
517 { initialise_memory_block(&zcode_backpatch_table);
518 initialise_memory_block(&staticarray_backpatch_table);
519 initialise_memory_block(&zmachine_backpatch_table);
522 extern void bpatch_begin_pass(void)
523 { zcode_backpatch_size = 0;
524 staticarray_backpatch_size = 0;
525 zmachine_backpatch_size = 0;
528 extern void bpatch_allocate_arrays(void)
532 extern void bpatch_free_arrays(void)
533 { deallocate_memory_block(&zcode_backpatch_table);
534 deallocate_memory_block(&staticarray_backpatch_table);
535 deallocate_memory_block(&zmachine_backpatch_table);
538 /* ========================================================================= */