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 - 2016 */
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, zmachine_backpatch_table;
27 int32 zcode_backpatch_size, zmachine_backpatch_size;
29 /* ------------------------------------------------------------------------- */
30 /* The mending operation */
31 /* ------------------------------------------------------------------------- */
33 int backpatch_marker, backpatch_size, backpatch_error_flag;
35 static int32 backpatch_value_z(int32 value)
36 { /* Corrects the quantity "value" according to backpatch_marker */
40 if (asm_trace_level >= 4)
41 printf("BP %s applied to %04x giving ",
42 describe_mv(backpatch_marker), value);
44 switch(backpatch_marker)
46 value += strings_offset/scale_factor; break;
48 value += variables_offset; break;
50 if (OMIT_UNUSED_ROUTINES)
51 value = df_stripped_address_for_address(value);
52 value += code_offset/scale_factor;
55 if ((value<0) || (value>=VENEER_ROUTINES))
56 { if (no_link_errors > 0) break;
58 ("Backpatch veneer routine number out of range"))
59 { printf("Illegal BP veneer routine number: %d\n", value);
60 backpatch_error_flag = TRUE;
65 value = veneer_routine_address[value];
66 if (OMIT_UNUSED_ROUTINES)
67 value = df_stripped_address_for_address(value);
68 value += code_offset/scale_factor;
71 value = no_objects; break;
73 if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
74 { if (no_link_errors > 0) break;
76 ("Backpatch system constant number out of range"))
77 { printf("Illegal BP system constant number: %d\n", value);
78 backpatch_error_flag = TRUE;
83 value = value_of_system_constant(value); break;
85 value = dictionary_offset + 7 +
86 final_dict_order[value]*((version_number==3)?7:9);
91 value = 256*zmachine_paged_memory[value + prop_values_offset]
92 + zmachine_paged_memory[value + prop_values_offset + 1];
94 case INHERIT_INDIV_MV:
95 value = 256*zmachine_paged_memory[value
97 + zmachine_paged_memory[value
98 + individuals_offset + 1];
101 value += individuals_offset;
104 value = symbol_index("Main", -1);
105 if (stypes[value] != ROUTINE_T)
106 error("No 'Main' routine has been defined");
107 sflags[value] |= USED_SFLAG;
108 value = svals[value];
109 if (OMIT_UNUSED_ROUTINES)
110 value = df_stripped_address_for_address(value);
111 value += code_offset/scale_factor;
114 if ((value<0) || (value>=no_symbols))
115 { if (no_link_errors > 0) break;
116 if (compiler_error("Backpatch symbol number out of range"))
117 { printf("Illegal BP symbol number: %d\n", value);
118 backpatch_error_flag = TRUE;
123 if (sflags[value] & UNKNOWN_SFLAG)
124 { if (!(sflags[value] & UERROR_SFLAG))
125 { sflags[value] |= UERROR_SFLAG;
126 error_named_at("No such constant as",
127 (char *) symbs[value], slines[value]);
131 if (sflags[value] & CHANGE_SFLAG)
132 { sflags[value] &= (~(CHANGE_SFLAG));
133 backpatch_marker = (svals[value]/0x10000);
134 if ((backpatch_marker < 0)
135 || (backpatch_marker > LARGEST_BPATCH_MV))
137 if (no_link_errors == 0)
138 { compiler_error_named(
139 "Illegal backpatch marker attached to symbol",
140 (char *) symbs[value]);
141 backpatch_error_flag = TRUE;
145 svals[value] = backpatch_value_z((svals[value]) % 0x10000);
148 sflags[value] |= USED_SFLAG;
149 { int t = stypes[value];
150 value = svals[value];
153 if (OMIT_UNUSED_ROUTINES)
154 value = df_stripped_address_for_address(value);
155 value += code_offset/scale_factor;
157 case ARRAY_T: value += variables_offset; break;
162 if (no_link_errors > 0) break;
163 if (compiler_error("Illegal backpatch marker"))
164 { printf("Illegal backpatch marker %d value %04x\n",
165 backpatch_marker, value);
166 backpatch_error_flag = TRUE;
171 if (asm_trace_level >= 4) printf(" %04x\n", value);
176 static int32 backpatch_value_g(int32 value)
177 { /* Corrects the quantity "value" according to backpatch_marker */
182 if (asm_trace_level >= 4)
183 printf("BP %s applied to %04x giving ",
184 describe_mv(backpatch_marker), value);
186 switch(backpatch_marker)
189 if (value <= 0 || value > no_strings)
190 compiler_error("Illegal string marker.");
191 value = strings_offset + compressed_offsets[value-1]; break;
193 if (OMIT_UNUSED_ROUTINES)
194 value = df_stripped_address_for_address(value);
195 value += code_offset;
198 value += arrays_offset; break;
200 value = variables_offset + (4*value); break;
202 value = object_tree_offset + (OBJECT_BYTE_LENGTH*(value-1));
205 if ((value<0) || (value>=VENEER_ROUTINES))
206 { if (no_link_errors > 0) break;
208 ("Backpatch veneer routine number out of range"))
209 { printf("Illegal BP veneer routine number: %d\n", value);
210 backpatch_error_flag = TRUE;
215 value = veneer_routine_address[value];
216 if (OMIT_UNUSED_ROUTINES)
217 value = df_stripped_address_for_address(value);
218 value += code_offset;
221 value = no_objects; break;
223 if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
224 { if (no_link_errors > 0) break;
226 ("Backpatch system constant number out of range"))
227 { printf("Illegal BP system constant number: %d\n", value);
228 backpatch_error_flag = TRUE;
233 value = value_of_system_constant(value); break;
235 value = dictionary_offset + 4
236 + final_dict_order[value]*DICT_ENTRY_BYTE_LENGTH;
241 valaddr = (prop_values_offset - Write_RAM_At) + value;
242 value = ReadInt32(zmachine_paged_memory + valaddr);
244 case INHERIT_INDIV_MV:
245 error("*** No individual property storage in Glulx ***");
248 value += individuals_offset;
251 value = symbol_index("Main", -1);
252 if (stypes[value] != ROUTINE_T)
253 error("No 'Main' routine has been defined");
254 sflags[value] |= USED_SFLAG;
255 value = svals[value];
256 if (OMIT_UNUSED_ROUTINES)
257 value = df_stripped_address_for_address(value);
258 value += code_offset;
261 if ((value<0) || (value>=no_symbols))
262 { if (no_link_errors > 0) break;
263 if (compiler_error("Backpatch symbol number out of range"))
264 { printf("Illegal BP symbol number: %d\n", value);
265 backpatch_error_flag = TRUE;
270 if (sflags[value] & UNKNOWN_SFLAG)
271 { if (!(sflags[value] & UERROR_SFLAG))
272 { sflags[value] |= UERROR_SFLAG;
273 error_named_at("No such constant as",
274 (char *) symbs[value], slines[value]);
278 if (sflags[value] & CHANGE_SFLAG)
279 { sflags[value] &= (~(CHANGE_SFLAG));
280 backpatch_marker = smarks[value];
281 if ((backpatch_marker < 0)
282 || (backpatch_marker > LARGEST_BPATCH_MV))
284 if (no_link_errors == 0)
285 { compiler_error_named(
286 "Illegal backpatch marker attached to symbol",
287 (char *) symbs[value]);
288 backpatch_error_flag = TRUE;
292 svals[value] = backpatch_value_g(svals[value]);
295 sflags[value] |= USED_SFLAG;
296 { int t = stypes[value];
297 value = svals[value];
301 if (OMIT_UNUSED_ROUTINES)
302 value = df_stripped_address_for_address(value);
303 value += code_offset;
305 case ARRAY_T: value += arrays_offset; break;
308 value = object_tree_offset +
309 (OBJECT_BYTE_LENGTH*(value-1));
312 /* value is unchanged */
315 case INDIVIDUAL_PROPERTY_T:
316 /* value is unchanged */
319 error("*** Illegal backpatch marker in forward-declared \
326 if (no_link_errors > 0) break;
327 if (compiler_error("Illegal backpatch marker"))
328 { printf("Illegal backpatch marker %d value %04x\n",
329 backpatch_marker, value);
330 backpatch_error_flag = TRUE;
335 if (asm_trace_level >= 4) printf(" %04x\n", value);
340 extern int32 backpatch_value(int32 value)
343 return backpatch_value_z(value);
345 return backpatch_value_g(value);
348 static void backpatch_zmachine_z(int mv, int zmachine_area, int32 offset)
350 { if (zmachine_area == PROP_DEFAULTS_ZA) return;
353 { if (mv == OBJECT_MV) return;
354 if (mv == IDENT_MV) return;
355 if (mv == ACTION_MV) return;
358 /* printf("MV %d ZA %d Off %04x\n", mv, zmachine_area, offset); */
360 write_byte_to_memory_block(&zmachine_backpatch_table,
361 zmachine_backpatch_size++, mv);
362 write_byte_to_memory_block(&zmachine_backpatch_table,
363 zmachine_backpatch_size++, zmachine_area);
364 write_byte_to_memory_block(&zmachine_backpatch_table,
365 zmachine_backpatch_size++, offset/256);
366 write_byte_to_memory_block(&zmachine_backpatch_table,
367 zmachine_backpatch_size++, offset%256);
370 static void backpatch_zmachine_g(int mv, int zmachine_area, int32 offset)
372 { if (zmachine_area == PROP_DEFAULTS_ZA) return;
375 { if (mv == IDENT_MV) return;
376 if (mv == ACTION_MV) return;
379 /* The backpatch table format for Glulx:
380 First, the marker byte.
381 Then, the zmachine area being patched.
382 Then the four-byte address.
385 /* printf("+MV %d ZA %d Off %06x\n", mv, zmachine_area, offset); */
387 write_byte_to_memory_block(&zmachine_backpatch_table,
388 zmachine_backpatch_size++, mv);
389 write_byte_to_memory_block(&zmachine_backpatch_table,
390 zmachine_backpatch_size++, zmachine_area);
391 write_byte_to_memory_block(&zmachine_backpatch_table,
392 zmachine_backpatch_size++, (offset >> 24) & 0xFF);
393 write_byte_to_memory_block(&zmachine_backpatch_table,
394 zmachine_backpatch_size++, (offset >> 16) & 0xFF);
395 write_byte_to_memory_block(&zmachine_backpatch_table,
396 zmachine_backpatch_size++, (offset >> 8) & 0xFF);
397 write_byte_to_memory_block(&zmachine_backpatch_table,
398 zmachine_backpatch_size++, (offset) & 0xFF);
401 extern void backpatch_zmachine(int mv, int zmachine_area, int32 offset)
404 backpatch_zmachine_z(mv, zmachine_area, offset);
406 backpatch_zmachine_g(mv, zmachine_area, offset);
409 extern void backpatch_zmachine_image_z(void)
410 { int bm = 0, zmachine_area; int32 offset, value, addr = 0;
412 backpatch_error_flag = FALSE;
413 while (bm < zmachine_backpatch_size)
415 = read_byte_from_memory_block(&zmachine_backpatch_table, bm);
417 = read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
419 = 256*read_byte_from_memory_block(&zmachine_backpatch_table,bm+2)
420 + read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
423 switch(zmachine_area)
424 { case PROP_DEFAULTS_ZA: addr = prop_defaults_offset; break;
425 case PROP_ZA: addr = prop_values_offset; break;
426 case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
427 case DYNAMIC_ARRAY_ZA: addr = variables_offset; break;
429 if (no_link_errors == 0)
430 if (compiler_error("Illegal area to backpatch"))
431 backpatch_error_flag = TRUE;
435 value = 256*zmachine_paged_memory[addr]
436 + zmachine_paged_memory[addr+1];
437 value = backpatch_value_z(value);
438 zmachine_paged_memory[addr] = value/256;
439 zmachine_paged_memory[addr+1] = value%256;
441 if (backpatch_error_flag)
442 { backpatch_error_flag = FALSE;
443 if (no_link_errors == 0)
444 printf("*** MV %d ZA %d Off %04x ***\n",
445 backpatch_marker, zmachine_area, offset);
450 extern void backpatch_zmachine_image_g(void)
451 { int bm = 0, zmachine_area; int32 offset, value, addr = 0;
453 backpatch_error_flag = FALSE;
454 while (bm < zmachine_backpatch_size)
456 = read_byte_from_memory_block(&zmachine_backpatch_table, bm);
458 = read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
459 offset = read_byte_from_memory_block(&zmachine_backpatch_table, bm+2);
460 offset = (offset << 8) |
461 read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
462 offset = (offset << 8) |
463 read_byte_from_memory_block(&zmachine_backpatch_table, bm+4);
464 offset = (offset << 8) |
465 read_byte_from_memory_block(&zmachine_backpatch_table, bm+5);
468 /* printf("-MV %d ZA %d Off %06x\n", backpatch_marker, zmachine_area, offset); */
470 switch(zmachine_area) {
471 case PROP_DEFAULTS_ZA: addr = prop_defaults_offset+4; break;
472 case PROP_ZA: addr = prop_values_offset; break;
473 case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
474 case ARRAY_ZA: addr = arrays_offset; break;
475 case GLOBALVAR_ZA: addr = variables_offset; break;
477 if (no_link_errors == 0)
478 if (compiler_error("Illegal area to backpatch"))
479 backpatch_error_flag = TRUE;
481 addr = addr + offset - Write_RAM_At;
483 value = (zmachine_paged_memory[addr] << 24)
484 | (zmachine_paged_memory[addr+1] << 16)
485 | (zmachine_paged_memory[addr+2] << 8)
486 | (zmachine_paged_memory[addr+3]);
487 value = backpatch_value_g(value);
488 zmachine_paged_memory[addr] = (value >> 24) & 0xFF;
489 zmachine_paged_memory[addr+1] = (value >> 16) & 0xFF;
490 zmachine_paged_memory[addr+2] = (value >> 8) & 0xFF;
491 zmachine_paged_memory[addr+3] = (value) & 0xFF;
493 if (backpatch_error_flag)
494 { backpatch_error_flag = FALSE;
495 if (no_link_errors == 0)
496 printf("*** MV %d ZA %d Off %04x ***\n",
497 backpatch_marker, zmachine_area, offset);
502 /* ========================================================================= */
503 /* Data structure management routines */
504 /* ------------------------------------------------------------------------- */
506 extern void init_bpatch_vars(void)
507 { initialise_memory_block(&zcode_backpatch_table);
508 initialise_memory_block(&zmachine_backpatch_table);
511 extern void bpatch_begin_pass(void)
512 { zcode_backpatch_size = 0;
513 zmachine_backpatch_size = 0;
516 extern void bpatch_allocate_arrays(void)
520 extern void bpatch_free_arrays(void)
521 { deallocate_memory_block(&zcode_backpatch_table);
522 deallocate_memory_block(&zmachine_backpatch_table);
525 /* ========================================================================= */