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.31 */
6
/* copyright (c) Graham Nelson 1993 - 2006 */
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
value += code_offset/scale_factor; break;
38
if ((value<0) || (value>=VENEER_ROUTINES))
39
{ if (no_link_errors > 0) break;
41
("Backpatch veneer routine number out of range"))
42
{ printf("Illegal BP veneer routine number: %d\n", value);
43
backpatch_error_flag = TRUE;
48
value = veneer_routine_address[value] + code_offset/scale_factor;
51
value = no_objects; break;
53
if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
54
{ if (no_link_errors > 0) break;
56
("Backpatch system constant number out of range"))
57
{ printf("Illegal BP system constant number: %d\n", value);
58
backpatch_error_flag = TRUE;
63
value = value_of_system_constant(value); break;
65
value = dictionary_offset + 7 +
66
final_dict_order[value]*((version_number==3)?7:9);
71
value = 256*zmachine_paged_memory[value + prop_values_offset]
72
+ zmachine_paged_memory[value + prop_values_offset + 1];
74
case INHERIT_INDIV_MV:
75
value = 256*zmachine_paged_memory[value
77
+ zmachine_paged_memory[value
78
+ individuals_offset + 1];
81
value += individuals_offset;
84
value = symbol_index("Main", -1);
85
if (stypes[value] != ROUTINE_T)
86
error("No 'Main' routine has been defined");
87
sflags[value] |= USED_SFLAG;
88
value = svals[value] + code_offset/scale_factor;
91
if ((value<0) || (value>=no_symbols))
92
{ if (no_link_errors > 0) break;
93
if (compiler_error("Backpatch symbol number out of range"))
94
{ printf("Illegal BP symbol number: %d\n", value);
95
backpatch_error_flag = TRUE;
100
if (sflags[value] & UNKNOWN_SFLAG)
101
{ if (!(sflags[value] & UERROR_SFLAG))
102
{ sflags[value] |= UERROR_SFLAG;
103
error_named_at("No such constant as",
104
(char *) symbs[value], slines[value]);
108
if (sflags[value] & CHANGE_SFLAG)
109
{ sflags[value] &= (~(CHANGE_SFLAG));
110
backpatch_marker = (svals[value]/0x10000);
111
if ((backpatch_marker < 0)
112
|| (backpatch_marker > LARGEST_BPATCH_MV))
114
if (no_link_errors == 0)
115
{ compiler_error_named(
116
"Illegal backpatch marker attached to symbol",
117
(char *) symbs[value]);
118
backpatch_error_flag = TRUE;
122
svals[value] = backpatch_value_z((svals[value]) % 0x10000);
125
sflags[value] |= USED_SFLAG;
126
{ int t = stypes[value];
127
value = svals[value];
129
{ case ROUTINE_T: value += code_offset/scale_factor; break;
130
case ARRAY_T: value += variables_offset; break;
135
if (no_link_errors > 0) break;
136
if (compiler_error("Illegal backpatch marker"))
137
{ printf("Illegal backpatch marker %d value %04x\n",
138
backpatch_marker, value);
139
backpatch_error_flag = TRUE;
144
if (asm_trace_level >= 4) printf(" %04x\n", value);
149
static int32 backpatch_value_g(int32 value)
150
{ /* Corrects the quantity "value" according to backpatch_marker */
155
if (asm_trace_level >= 4)
156
printf("BP %s applied to %04x giving ",
157
describe_mv(backpatch_marker), value);
159
switch(backpatch_marker)
162
if (value <= 0 || value > no_strings)
163
compiler_error("Illegal string marker.");
164
value = strings_offset + compressed_offsets[value-1]; break;
166
value += code_offset; break;
168
value += arrays_offset; break;
170
value = variables_offset + (4*value); break;
172
value = object_tree_offset + (OBJECT_BYTE_LENGTH*(value-1));
175
if ((value<0) || (value>=VENEER_ROUTINES))
176
{ if (no_link_errors > 0) break;
178
("Backpatch veneer routine number out of range"))
179
{ printf("Illegal BP veneer routine number: %d\n", value);
180
backpatch_error_flag = TRUE;
185
value = veneer_routine_address[value] + code_offset;
188
value = no_objects; break;
190
if ((value<0) || (value>=NO_SYSTEM_CONSTANTS))
191
{ if (no_link_errors > 0) break;
193
("Backpatch system constant number out of range"))
194
{ printf("Illegal BP system constant number: %d\n", value);
195
backpatch_error_flag = TRUE;
200
value = value_of_system_constant(value); break;
202
value = dictionary_offset + 4
203
+ final_dict_order[value]*(7+DICT_WORD_SIZE);
208
valaddr = (prop_values_offset - Write_RAM_At) + value;
209
value = ReadInt32(zmachine_paged_memory + valaddr);
211
case INHERIT_INDIV_MV:
212
error("*** No individual property storage in Glulx ***");
215
value += individuals_offset;
218
value = symbol_index("Main", -1);
219
if (stypes[value] != ROUTINE_T)
220
error("No 'Main' routine has been defined");
221
sflags[value] |= USED_SFLAG;
222
value = svals[value] + code_offset;
225
if ((value<0) || (value>=no_symbols))
226
{ if (no_link_errors > 0) break;
227
if (compiler_error("Backpatch symbol number out of range"))
228
{ printf("Illegal BP symbol number: %d\n", value);
229
backpatch_error_flag = TRUE;
234
if (sflags[value] & UNKNOWN_SFLAG)
235
{ if (!(sflags[value] & UERROR_SFLAG))
236
{ sflags[value] |= UERROR_SFLAG;
237
error_named_at("No such constant as",
238
(char *) symbs[value], slines[value]);
242
if (sflags[value] & CHANGE_SFLAG)
243
{ sflags[value] &= (~(CHANGE_SFLAG));
244
backpatch_marker = smarks[value];
245
if ((backpatch_marker < 0)
246
|| (backpatch_marker > LARGEST_BPATCH_MV))
248
if (no_link_errors == 0)
249
{ compiler_error_named(
250
"Illegal backpatch marker attached to symbol",
251
(char *) symbs[value]);
252
backpatch_error_flag = TRUE;
256
svals[value] = backpatch_value_g(svals[value]);
259
sflags[value] |= USED_SFLAG;
260
{ int t = stypes[value];
261
value = svals[value];
264
case ROUTINE_T: value += code_offset; break;
265
case ARRAY_T: value += arrays_offset; break;
268
value = object_tree_offset +
269
(OBJECT_BYTE_LENGTH*(value-1));
272
/* value is unchanged */
275
case INDIVIDUAL_PROPERTY_T:
276
/* value is unchanged */
279
error("*** Illegal backpatch marker in forward-declared \
286
if (no_link_errors > 0) break;
287
if (compiler_error("Illegal backpatch marker"))
288
{ printf("Illegal backpatch marker %d value %04x\n",
289
backpatch_marker, value);
290
backpatch_error_flag = TRUE;
295
if (asm_trace_level >= 4) printf(" %04x\n", value);
300
extern int32 backpatch_value(int32 value)
303
return backpatch_value_z(value);
305
return backpatch_value_g(value);
308
static void backpatch_zmachine_z(int mv, int zmachine_area, int32 offset)
310
{ if (zmachine_area == PROP_DEFAULTS_ZA) return;
313
{ if (mv == OBJECT_MV) return;
314
if (mv == IDENT_MV) return;
315
if (mv == ACTION_MV) return;
318
/* printf("MV %d ZA %d Off %04x\n", mv, zmachine_area, offset); */
320
write_byte_to_memory_block(&zmachine_backpatch_table,
321
zmachine_backpatch_size++, mv);
322
write_byte_to_memory_block(&zmachine_backpatch_table,
323
zmachine_backpatch_size++, zmachine_area);
324
write_byte_to_memory_block(&zmachine_backpatch_table,
325
zmachine_backpatch_size++, offset/256);
326
write_byte_to_memory_block(&zmachine_backpatch_table,
327
zmachine_backpatch_size++, offset%256);
330
static void backpatch_zmachine_g(int mv, int zmachine_area, int32 offset)
332
{ if (zmachine_area == PROP_DEFAULTS_ZA) return;
335
{ if (mv == IDENT_MV) return;
336
if (mv == ACTION_MV) return;
339
/* The backpatch table format for Glulx:
340
First, the marker byte.
341
Then, the zmachine area being patched.
342
Then the four-byte address.
345
/* printf("+MV %d ZA %d Off %06x\n", mv, zmachine_area, offset); */
347
write_byte_to_memory_block(&zmachine_backpatch_table,
348
zmachine_backpatch_size++, mv);
349
write_byte_to_memory_block(&zmachine_backpatch_table,
350
zmachine_backpatch_size++, zmachine_area);
351
write_byte_to_memory_block(&zmachine_backpatch_table,
352
zmachine_backpatch_size++, (offset >> 24) & 0xFF);
353
write_byte_to_memory_block(&zmachine_backpatch_table,
354
zmachine_backpatch_size++, (offset >> 16) & 0xFF);
355
write_byte_to_memory_block(&zmachine_backpatch_table,
356
zmachine_backpatch_size++, (offset >> 8) & 0xFF);
357
write_byte_to_memory_block(&zmachine_backpatch_table,
358
zmachine_backpatch_size++, (offset) & 0xFF);
361
extern void backpatch_zmachine(int mv, int zmachine_area, int32 offset)
364
backpatch_zmachine_z(mv, zmachine_area, offset);
366
backpatch_zmachine_g(mv, zmachine_area, offset);
369
extern void backpatch_zmachine_image_z(void)
370
{ int bm = 0, zmachine_area; int32 offset, value, addr;
372
backpatch_error_flag = FALSE;
373
while (bm < zmachine_backpatch_size)
375
= read_byte_from_memory_block(&zmachine_backpatch_table, bm);
377
= read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
379
= 256*read_byte_from_memory_block(&zmachine_backpatch_table,bm+2)
380
+ read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
383
switch(zmachine_area)
384
{ case PROP_DEFAULTS_ZA: addr = prop_defaults_offset; break;
385
case PROP_ZA: addr = prop_values_offset; break;
386
case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
387
case DYNAMIC_ARRAY_ZA: addr = variables_offset; break;
389
if (no_link_errors == 0)
390
if (compiler_error("Illegal area to backpatch"))
391
backpatch_error_flag = TRUE;
395
value = 256*zmachine_paged_memory[addr]
396
+ zmachine_paged_memory[addr+1];
397
value = backpatch_value_z(value);
398
zmachine_paged_memory[addr] = value/256;
399
zmachine_paged_memory[addr+1] = value%256;
401
if (backpatch_error_flag)
402
{ backpatch_error_flag = FALSE;
403
if (no_link_errors == 0)
404
printf("*** MV %d ZA %d Off %04x ***\n",
405
backpatch_marker, zmachine_area, offset);
410
extern void backpatch_zmachine_image_g(void)
411
{ int bm = 0, zmachine_area; int32 offset, value, addr;
413
backpatch_error_flag = FALSE;
414
while (bm < zmachine_backpatch_size)
416
= read_byte_from_memory_block(&zmachine_backpatch_table, bm);
418
= read_byte_from_memory_block(&zmachine_backpatch_table, bm+1);
419
offset = read_byte_from_memory_block(&zmachine_backpatch_table, bm+2);
420
offset = (offset << 8) |
421
read_byte_from_memory_block(&zmachine_backpatch_table, bm+3);
422
offset = (offset << 8) |
423
read_byte_from_memory_block(&zmachine_backpatch_table, bm+4);
424
offset = (offset << 8) |
425
read_byte_from_memory_block(&zmachine_backpatch_table, bm+5);
428
/* printf("-MV %d ZA %d Off %06x\n", backpatch_marker, zmachine_area, offset); */
430
switch(zmachine_area) {
431
case PROP_DEFAULTS_ZA: addr = prop_defaults_offset+4; break;
432
case PROP_ZA: addr = prop_values_offset; break;
433
case INDIVIDUAL_PROP_ZA: addr = individuals_offset; break;
434
case ARRAY_ZA: addr = arrays_offset; break;
435
case GLOBALVAR_ZA: addr = variables_offset; break;
437
if (no_link_errors == 0)
438
if (compiler_error("Illegal area to backpatch"))
439
backpatch_error_flag = TRUE;
441
addr = addr + offset - Write_RAM_At;
443
value = (zmachine_paged_memory[addr] << 24)
444
| (zmachine_paged_memory[addr+1] << 16)
445
| (zmachine_paged_memory[addr+2] << 8)
446
| (zmachine_paged_memory[addr+3]);
447
value = backpatch_value(value);
448
zmachine_paged_memory[addr] = (value >> 24) & 0xFF;
449
zmachine_paged_memory[addr+1] = (value >> 16) & 0xFF;
450
zmachine_paged_memory[addr+2] = (value >> 8) & 0xFF;
451
zmachine_paged_memory[addr+3] = (value) & 0xFF;
453
if (backpatch_error_flag)
454
{ backpatch_error_flag = FALSE;
455
if (no_link_errors == 0)
456
printf("*** MV %d ZA %d Off %04x ***\n",
457
backpatch_marker, zmachine_area, offset);
462
/* ========================================================================= */
463
/* Data structure management routines */
464
/* ------------------------------------------------------------------------- */
466
extern void init_bpatch_vars(void)
467
{ initialise_memory_block(&zcode_backpatch_table);
468
initialise_memory_block(&zmachine_backpatch_table);
471
extern void bpatch_begin_pass(void)
472
{ zcode_backpatch_size = 0;
473
zmachine_backpatch_size = 0;
476
extern void bpatch_allocate_arrays(void)
480
extern void bpatch_free_arrays(void)
481
{ deallocate_memory_block(&zcode_backpatch_table);
482
deallocate_memory_block(&zmachine_backpatch_table);
485
/* ========================================================================= */