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