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.33 */
6 /* copyright (c) Graham Nelson 1993 - 2014 */
8 /* ------------------------------------------------------------------------- */
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 */
26 if (asm_trace_level
>= 4)
27 printf("BP %s applied to %04x giving ",
28 describe_mv(backpatch_marker
), value
);
30 switch(backpatch_marker
)
32 value
+= strings_offset
/scale_factor
; break;
34 value
+= variables_offset
; break;
36 if (OMIT_UNUSED_ROUTINES
)
37 value
= df_stripped_address_for_address(value
);
38 value
+= code_offset
/scale_factor
;
41 if ((value
<0) || (value
>=VENEER_ROUTINES
))
42 { if (no_link_errors
> 0) break;
44 ("Backpatch veneer routine number out of range"))
45 { printf("Illegal BP veneer routine number: %d\n", value
);
46 backpatch_error_flag
= TRUE
;
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
;
57 value
= no_objects
; break;
59 if ((value
<0) || (value
>=NO_SYSTEM_CONSTANTS
))
60 { if (no_link_errors
> 0) break;
62 ("Backpatch system constant number out of range"))
63 { printf("Illegal BP system constant number: %d\n", value
);
64 backpatch_error_flag
= TRUE
;
69 value
= value_of_system_constant(value
); break;
71 value
= dictionary_offset
+ 7 +
72 final_dict_order
[value
]*((version_number
==3)?7:9);
77 value
= 256*zmachine_paged_memory
[value
+ prop_values_offset
]
78 + zmachine_paged_memory
[value
+ prop_values_offset
+ 1];
80 case INHERIT_INDIV_MV
:
81 value
= 256*zmachine_paged_memory
[value
83 + zmachine_paged_memory
[value
84 + individuals_offset
+ 1];
87 value
+= individuals_offset
;
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
;
95 if (OMIT_UNUSED_ROUTINES
)
96 value
= df_stripped_address_for_address(value
);
97 value
+= code_offset
/scale_factor
;
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
;
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
]);
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
;
131 svals
[value
] = backpatch_value_z((svals
[value
]) % 0x10000);
134 sflags
[value
] |= USED_SFLAG
;
135 { int t
= stypes
[value
];
136 value
= svals
[value
];
139 if (OMIT_UNUSED_ROUTINES
)
140 value
= df_stripped_address_for_address(value
);
141 value
+= code_offset
/scale_factor
;
143 case ARRAY_T
: value
+= variables_offset
; break;
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
;
157 if (asm_trace_level
>= 4) printf(" %04x\n", value
);
162 static int32
backpatch_value_g(int32 value
)
163 { /* Corrects the quantity "value" according to backpatch_marker */
168 if (asm_trace_level
>= 4)
169 printf("BP %s applied to %04x giving ",
170 describe_mv(backpatch_marker
), value
);
172 switch(backpatch_marker
)
175 if (value
<= 0 || value
> no_strings
)
176 compiler_error("Illegal string marker.");
177 value
= strings_offset
+ compressed_offsets
[value
-1]; break;
179 if (OMIT_UNUSED_ROUTINES
)
180 value
= df_stripped_address_for_address(value
);
181 value
+= code_offset
;
184 value
+= arrays_offset
; break;
186 value
= variables_offset
+ (4*value
); break;
188 value
= object_tree_offset
+ (OBJECT_BYTE_LENGTH
*(value
-1));
191 if ((value
<0) || (value
>=VENEER_ROUTINES
))
192 { if (no_link_errors
> 0) break;
194 ("Backpatch veneer routine number out of range"))
195 { printf("Illegal BP veneer routine number: %d\n", value
);
196 backpatch_error_flag
= TRUE
;
201 value
= veneer_routine_address
[value
];
202 if (OMIT_UNUSED_ROUTINES
)
203 value
= df_stripped_address_for_address(value
);
204 value
+= code_offset
;
207 value
= no_objects
; break;
209 if ((value
<0) || (value
>=NO_SYSTEM_CONSTANTS
))
210 { if (no_link_errors
> 0) break;
212 ("Backpatch system constant number out of range"))
213 { printf("Illegal BP system constant number: %d\n", value
);
214 backpatch_error_flag
= TRUE
;
219 value
= value_of_system_constant(value
); break;
221 value
= dictionary_offset
+ 4
222 + final_dict_order
[value
]*DICT_ENTRY_BYTE_LENGTH
;
227 valaddr
= (prop_values_offset
- Write_RAM_At
) + value
;
228 value
= ReadInt32(zmachine_paged_memory
+ valaddr
);
230 case INHERIT_INDIV_MV
:
231 error("*** No individual property storage in Glulx ***");
234 value
+= individuals_offset
;
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
;
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
;
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
]);
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
;
278 svals
[value
] = backpatch_value_g(svals
[value
]);
281 sflags
[value
] |= USED_SFLAG
;
282 { int t
= stypes
[value
];
283 value
= svals
[value
];
287 if (OMIT_UNUSED_ROUTINES
)
288 value
= df_stripped_address_for_address(value
);
289 value
+= code_offset
;
291 case ARRAY_T
: value
+= arrays_offset
; break;
294 value
= object_tree_offset
+
295 (OBJECT_BYTE_LENGTH
*(value
-1));
298 /* value is unchanged */
301 case INDIVIDUAL_PROPERTY_T
:
302 /* value is unchanged */
305 error("*** Illegal backpatch marker in forward-declared \
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
;
321 if (asm_trace_level
>= 4) printf(" %04x\n", value
);
326 extern int32
backpatch_value(int32 value
)
329 return backpatch_value_z(value
);
331 return backpatch_value_g(value
);
334 static void backpatch_zmachine_z(int mv
, int zmachine_area
, int32 offset
)
336 { if (zmachine_area
== PROP_DEFAULTS_ZA
) return;
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
)
358 { if (zmachine_area
== PROP_DEFAULTS_ZA
) return;
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
)
390 backpatch_zmachine_z(mv
, zmachine_area
, offset
);
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
;
398 backpatch_error_flag
= FALSE
;
399 while (bm
< zmachine_backpatch_size
)
401 = read_byte_from_memory_block(&zmachine_backpatch_table
, bm
);
403 = read_byte_from_memory_block(&zmachine_backpatch_table
, bm
+1);
405 = 256*read_byte_from_memory_block(&zmachine_backpatch_table
,bm
+2)
406 + read_byte_from_memory_block(&zmachine_backpatch_table
, bm
+3);
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;
415 if (no_link_errors
== 0)
416 if (compiler_error("Illegal area to backpatch"))
417 backpatch_error_flag
= TRUE
;
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
;
439 backpatch_error_flag
= FALSE
;
440 while (bm
< zmachine_backpatch_size
)
442 = read_byte_from_memory_block(&zmachine_backpatch_table
, bm
);
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);
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;
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 /* ========================================================================= */