1 /* ------------------------------------------------------------------------- */
2 /* "linker" : For compiling and linking modules */
4 /* Part of Inform 6.35 */
5 /* copyright (c) Graham Nelson 1993 - 2021 */
7 /* Inform is free software: you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation, either version 3 of the License, or */
10 /* (at your option) any later version. */
12 /* Inform is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
15 /* GNU General Public License for more details. */
17 /* You should have received a copy of the GNU General Public License */
18 /* along with Inform. If not, see https://gnu.org/licenses/ *
20 /* ------------------------------------------------------------------------- */
24 memory_block link_data_area;
25 uchar *link_data_holding_area, *link_data_top;
26 /* Start, current top, size of */
27 int32 link_data_size; /* link data table being written */
28 /* (holding import/export names) */
29 extern int32 *action_symbol;
31 /* ------------------------------------------------------------------------- */
33 /* ------------------------------------------------------------------------- */
35 extern char *describe_mv(int mval)
37 { case NULL_MV: return("null");
39 /* Marker values used in ordinary story file backpatching */
41 case DWORD_MV: return("dictionary word");
42 case STRING_MV: return("string literal");
43 case INCON_MV: return("system constant");
44 case IROUTINE_MV: return("routine");
45 case VROUTINE_MV: return("veneer routine");
46 case ARRAY_MV: return("internal array");
47 case NO_OBJS_MV: return("the number of objects");
48 case INHERIT_MV: return("inherited common p value");
49 case INDIVPT_MV: return("indiv prop table address");
50 case INHERIT_INDIV_MV: return("inherited indiv p value");
51 case MAIN_MV: return("ref to Main");
52 case SYMBOL_MV: return("ref to symbol value");
54 /* Additional marker values used in module backpatching */
56 case VARIABLE_MV: return("global variable");
57 case IDENT_MV: return("prop identifier number");
58 case ACTION_MV: return("action");
59 case OBJECT_MV: return("internal object");
61 /* Record types in the import/export table (not really marker
64 case EXPORT_MV: return("Export ");
65 case EXPORTSF_MV: return("Export sf");
66 case EXPORTAC_MV: return("Export ##");
67 case IMPORT_MV: return("Import ");
69 return("** No such MV **");
72 /* ------------------------------------------------------------------------- */
73 /* Import/export records */
74 /* ------------------------------------------------------------------------- */
76 typedef struct importexport_s
85 static void describe_importexport(ImportExport *I)
86 { printf("%8s %20s %04d %04x %s\n",
87 describe_mv(I->module_value), I->symbol_name,
88 I->symbol_number, I->symbol_value, typename(I->symbol_type));
91 /* ========================================================================= */
92 /* Linking in external modules: this code is run when the external */
93 /* program hits a Link directive. */
94 /* ------------------------------------------------------------------------- */
95 /* This map is between global variable numbers in the module and in the */
96 /* external program: variables_map[n] will be the external global variable */
97 /* no for module global variable no n. (The entries [0] to [15] are not */
99 /* ------------------------------------------------------------------------- */
101 static int variables_map[256], actions_map[256];
103 int32 module_map[16];
107 /* ------------------------------------------------------------------------- */
108 /* These are offsets within the module: */
109 /* ------------------------------------------------------------------------- */
111 static int32 m_code_offset, m_strs_offset, m_static_offset, m_dict_offset,
112 m_vars_offset, m_objs_offset, m_props_offset, m_class_numbers,
113 m_individuals_offset, m_individuals_length;
115 static int m_no_objects, m_no_globals, p_no_globals, lowest_imported_global_no;
117 int32 *xref_table; int xref_top;
118 int32 *property_identifier_map;
119 int *accession_numbers_map;
120 int32 routine_replace[64],
121 routine_replace_with[64]; int no_rr;
123 /* ------------------------------------------------------------------------- */
124 /* Reading and writing bytes/words in the module (as loaded in), indexing */
125 /* via "marker addresses". */
126 /* ------------------------------------------------------------------------- */
128 static int32 read_marker_address(uchar *p, int size,
129 int zmachine_area, int32 offset)
131 /* A routine to read the value referred to by the marker address
132 (zmachine_area, offset): size is 1 for byte, 2 for word, and the
133 module itself resides at p. */
137 switch(zmachine_area)
139 case DYNAMIC_ARRAY_ZA:
140 addr = m_vars_offset; break;
142 addr = m_code_offset; break;
143 case STATIC_STRINGS_ZA:
144 addr = m_strs_offset; break;
146 addr = m_dict_offset; break;
148 addr = m_objs_offset; break;
150 addr = m_props_offset; break;
151 case INDIVIDUAL_PROP_ZA:
152 addr = m_individuals_offset; break;
154 if (size == 1) return p[addr+offset];
155 return 256*p[addr+offset] + p[addr+offset+1];
158 static void write_marker_address(uchar *p, int size,
159 int zmachine_area, int32 offset, int32 value)
161 /* Similar, but to write to it. */
165 switch(zmachine_area)
167 case DYNAMIC_ARRAY_ZA:
168 addr = m_vars_offset; break;
170 addr = m_code_offset; break;
171 case STATIC_STRINGS_ZA:
172 addr = m_strs_offset; break;
174 addr = m_dict_offset; break;
176 addr = m_objs_offset; break;
178 addr = m_props_offset; break;
179 case INDIVIDUAL_PROP_ZA:
180 addr = m_individuals_offset; break;
182 if (size == 1) { p[addr+offset] = value%256; return; }
183 p[addr+offset] = value/256;
184 p[addr+offset+1] = value%256;
189 static int get_next_record(uchar *p)
191 int record_type = p[m_read_pos++];
198 IE.module_value = record_type;
199 i=p[m_read_pos++]; IE.symbol_number = 256*i + p[m_read_pos++];
200 IE.symbol_type = p[m_read_pos++];
201 if (record_type != IMPORT_MV) IE.backpatch = p[m_read_pos++];
202 i=p[m_read_pos++]; IE.symbol_value = 256*i + p[m_read_pos++];
203 IE.symbol_name = (char *) (p+m_read_pos);
204 m_read_pos += strlen((char *) (p+m_read_pos))+1;
205 if (linker_trace_level >= 2) describe_importexport(&IE);
208 printf("Marker value of %d\n", record_type);
209 compiler_error("Link: illegal import/export marker value");
215 static char link_errorm[128];
217 static void accept_export(void)
218 { int32 index, map_to = IE.symbol_value % 0x10000;
219 index = symbol_index(IE.symbol_name, -1);
221 xref_table[IE.symbol_number] = index;
223 if (!(sflags[index] & UNKNOWN_SFLAG))
224 { if (IE.module_value == EXPORTAC_MV)
225 { if ((!(sflags[index] & ACTION_SFLAG))
226 && (stypes[index] != FAKE_ACTION_T))
228 "action name clash with", IE.symbol_name);
231 if (stypes[index] == IE.symbol_type)
232 { switch(IE.symbol_type)
234 if ((!(svals[index] == IE.symbol_value))
235 || (IE.backpatch != 0))
237 "program and module give differing values of", IE.symbol_name);
239 case INDIVIDUAL_PROPERTY_T:
240 property_identifier_map[IE.symbol_value] = svals[index];
243 if ((IE.module_value == EXPORTSF_MV)
244 && (sflags[index] & REPLACE_SFLAG))
248 "%s '%s' in both program and module",
249 typename(IE.symbol_type), IE.symbol_name);
250 link_error(link_errorm);
255 { sprintf(link_errorm,
256 "'%s' has type %s in program but type %s in module",
257 IE.symbol_name, typename(stypes[index]),
258 typename(IE.symbol_type));
259 link_error(link_errorm);
263 { if (IE.module_value == EXPORTAC_MV)
264 { IE.symbol_value = no_actions;
265 action_symbol[no_actions++] = index;
266 if (linker_trace_level >= 4)
267 printf("Creating action ##%s\n", (char *) symbs[index]);
270 switch(IE.symbol_type)
272 if ((IE.module_value == EXPORTSF_MV)
273 && (sflags[index] & REPLACE_SFLAG))
274 { routine_replace[no_rr] = IE.symbol_value;
275 routine_replace_with[no_rr++] = index;
278 IE.symbol_value += (zmachine_pc/scale_factor);
282 IE.symbol_value += no_objects;
285 IE.symbol_value += dynamic_array_area_size - (MAX_GLOBAL_VARIABLES*2);
287 case GLOBAL_VARIABLE_T:
290 "failed because too many extra global variables needed");
293 variables_map[16 + m_no_globals++] = 16 + no_globals;
294 set_variable_value(no_globals, IE.symbol_value);
295 IE.symbol_value = 16 + no_globals++;
297 case INDIVIDUAL_PROPERTY_T:
298 property_identifier_map[IE.symbol_value]
299 = no_individual_properties;
300 IE.symbol_value = no_individual_properties++;
302 if (debugfile_switch)
303 { debug_file_printf("<property>");
305 ("<identifier>%s</identifier>", IE.symbol_name);
307 ("<value>%d</value>", IE.symbol_value);
308 debug_file_printf("</property>");
313 assign_symbol(index, IE.backpatch*0x10000 + IE.symbol_value,
315 if (IE.backpatch != 0) sflags[index] |= CHANGE_SFLAG;
316 sflags[index] |= EXPORT_SFLAG;
317 if (IE.module_value == EXPORTSF_MV)
318 sflags[index] |= INSF_SFLAG;
319 if (IE.module_value == EXPORTAC_MV)
320 sflags[index] |= ACTION_SFLAG;
323 if (IE.module_value == EXPORTAC_MV)
324 { if (linker_trace_level >= 4)
325 printf("Map %d '%s' to %d\n",
326 IE.symbol_value, (char *) (symbs[index]), svals[index]);
327 actions_map[map_to] = svals[index];
331 static void accept_import(void)
334 index = symbol_index(IE.symbol_name, -1);
335 sflags[index] |= USED_SFLAG;
336 xref_table[IE.symbol_number] = index;
338 if (!(sflags[index] & UNKNOWN_SFLAG))
339 { switch (IE.symbol_type)
341 case GLOBAL_VARIABLE_T:
342 if (stypes[index] != GLOBAL_VARIABLE_T)
344 "module (wrongly) declared this a variable:", IE.symbol_name);
345 variables_map[IE.symbol_value] = svals[index];
346 if (IE.symbol_value < lowest_imported_global_no)
347 lowest_imported_global_no = IE.symbol_value;
350 switch(stypes[index])
353 "this attribute is undeclared within module:", IE.symbol_name);; break;
356 "this property is undeclared within module:", IE.symbol_name); break;
357 case INDIVIDUAL_PROPERTY_T:
367 "this was referred to as a constant, but isn't:", IE.symbol_name);
374 { switch (IE.symbol_type)
376 case GLOBAL_VARIABLE_T:
377 if (stypes[index] != GLOBAL_VARIABLE_T)
379 "Module tried to import a Global variable not defined here:",
381 variables_map[IE.symbol_value] = 16;
382 if (IE.symbol_value < lowest_imported_global_no)
383 lowest_imported_global_no = IE.symbol_value;
389 static int32 backpatch_backpatch(int32 v)
390 { switch(backpatch_marker)
392 /* Backpatches made now which are final */
396 backpatch_marker = NULL_MV;
400 if ((v<0) || (v>=256) || (actions_map[v] == -1))
401 { link_error("unmapped action number");
402 printf("*** Link: unmapped action number %d ***", v);
407 backpatch_marker = NULL_MV;
411 { int f = v & 0x8000;
412 v = f + property_identifier_map[v-f];
413 backpatch_marker = NULL_MV;
418 backpatch_marker = NULL_MV;
419 if (v < lowest_imported_global_no)
420 { v = v + p_no_globals; break;
422 if (variables_map[v] == -1)
423 { printf("** Unmapped variable %d! **\n", v);
424 variables_map[v] = 16;
425 link_error("unmapped variable error"); break;
427 v = variables_map[v];
430 /* Backpatch values which are themselves being backpatched */
433 v += individuals_length;
438 if ((v<0) || (v>=no_symbols))
439 { printf("** Symbol number %d cannot be crossreferenced **\n", v);
440 link_error("symbol crossreference error"); v=0;
446 v += static_strings_extent/scale_factor;
451 for (i=0;i<no_rr;i++)
452 if (v == routine_replace[i])
453 { v = routine_replace_with[i];
454 backpatch_marker = SYMBOL_MV;
457 v += zmachine_pc/scale_factor;
466 if (v < (MAX_GLOBAL_VARIABLES*2))
467 { v = 2*(variables_map[v/2 + 16] - 16);
470 { v += dynamic_array_area_size - (MAX_GLOBAL_VARIABLES*2);
475 v = accession_numbers_map[v];
479 v += properties_table_size;
482 case INHERIT_INDIV_MV:
483 v += individuals_length;
489 static void backpatch_module_image(uchar *p,
490 int marker_value, int zmachine_area, int32 offset)
491 { int size = (marker_value>=0x80)?1:2; int32 v;
492 marker_value &= 0x7f;
494 backpatch_marker = marker_value;
496 if (zmachine_area == PROP_DEFAULTS_ZA) return;
498 if (linker_trace_level >= 3)
499 printf("Backpatch %s area %d offset %04x size %d: ",
500 describe_mv(marker_value), zmachine_area, offset, size);
502 v = read_marker_address(p, size, zmachine_area, offset);
503 if (linker_trace_level >= 3) printf("%04x ", v);
505 v = backpatch_backpatch(v);
507 write_marker_address(p, size, zmachine_area, offset, v);
508 if (linker_trace_level >= 3) printf("%04x\n", v);
511 /* ------------------------------------------------------------------------- */
512 /* The main routine: linking in a module with the given filename. */
513 /* ------------------------------------------------------------------------- */
515 char current_module_filename[128];
517 void link_module(char *given_filename)
522 int32 last, i, j, k, l, m, vn, len, size, link_offset, module_size, map,
523 max_property_identifier, symbols_base = no_symbols;
525 strcpy(current_module_filename, given_filename);
527 /* (1) Load in the module to link */
531 { i = translate_link_filename(i, filename, given_filename);
532 fin=fopen(filename,"rb");
533 } while ((fin == NULL) && (i != 0));
536 { error_named("Couldn't open module file", filename); return;
539 for (i=0;i<64;i++) p0[i]=fgetc(fin);
542 if ((vn<65) || (vn>75))
543 { error_named("File isn't a module:", filename);
547 if (vn != 64 + version_number)
550 "module compiled as Version %d (so it can't link\
551 into this V%d game):", vn-64, version_number);
552 error_named(ebuff, filename);
556 module_size = (256*p0[26] + p0[27])*scale_factor;
557 p = my_malloc(module_size + 16, "link module storage");
558 /* The + 16 allows for rounding errors */
560 for (k=0;k<64;k++) p[k] = p0[k];
561 for (k=64;k<module_size;k++) p[k] = fgetc(fin);
564 if ((p0[52] != 0) || (p0[53] != 0))
565 { /* Then the module contains a character set table */
566 if (alphabet_modified)
567 { k = FALSE; m = 256*p0[52] + p0[53];
568 for (i=0;i<3;i++) for (j=0;j<26;j++)
569 { l = alphabet[i][j]; if (l == '~') l = '\"';
570 if (l != p[m]) k = TRUE;
573 link_error("module and game both define non-standard character sets, \
580 { if (alphabet_modified) k = TRUE;
584 link_error("module and game use different character sets");
587 if (i > MODULE_VERSION_NUMBER)
588 warning_named("module has a more advanced format than this release \
589 of the Inform 6 compiler knows about: it may not link in correctly", filename);
591 /* (2) Calculate offsets: see the header-writing code in "tables.c" */
593 map = (256*p[6] + p[7]);
594 for (i=0; i<16; i++) module_map[i] = 256*p[map + i*2] + p[map + i*2 + 1];
596 m_vars_offset = (256*p[12] + p[13]);
597 m_static_offset = (256*p[14] + p[15]);
598 m_dict_offset = (256*p[8] + p[9]);
599 m_code_offset = (256*p[4] + p[5]);
601 /* (3) Read the "module map" table */
603 if (linker_trace_level>=4)
604 { printf("[Reading module map:\n");
605 for (i=0; i<16; i++) printf("%04x ", module_map[i]);
609 m_objs_offset = module_map[0];
610 m_props_offset = module_map[1];
611 m_strs_offset = scale_factor*module_map[2];
612 m_class_numbers = module_map[3];
613 m_individuals_offset = module_map[4];
614 m_individuals_length = module_map[5];
616 for (i=16;i<256;i++) variables_map[i] = -1;
617 for (i=0;i<16;i++) variables_map[i] = i;
618 for (i=LOWEST_SYSTEM_VAR_NUMBER;i<256;i++) variables_map[i] = i;
620 for (i=0;i<256;i++) actions_map[i] = -1;
622 xref_table = my_calloc(sizeof(int32), module_map[6],
623 "linker cross-references table");
624 for (i=0;i<module_map[6];i++) xref_table[i] = -1;
626 max_property_identifier = module_map[7];
627 property_identifier_map = my_calloc(sizeof(int32), max_property_identifier,
628 "property identifier map");
629 for (i=0; i<max_property_identifier; i++)
630 property_identifier_map[i] = i;
632 m_no_objects = module_map[8];
633 link_offset = module_map[9];
635 m_no_globals = 0; p_no_globals = no_globals;
636 lowest_imported_global_no=236;
640 if ((linker_trace_level>=1) || transcript_switch)
641 { char link_banner[128];
643 "[Linking release %d.%c%c%c%c%c%c of module '%s' (size %dK)]",
644 p[2]*256 + p[3], p[18], p[19], p[20], p[21], p[22], p[23],
645 filename, module_size/1024);
646 if (linker_trace_level >= 1) printf("%s\n", link_banner);
647 if (transcript_switch)
648 write_to_transcript_file(link_banner);
651 /* (4) Merge in the dictionary */
653 if (linker_trace_level >= 2)
654 printf("Merging module's dictionary at %04x\n", m_dict_offset);
655 k=m_dict_offset; k+=p[k]+1;
657 size = p[k]*256 + p[k+1]; k+=2;
659 accession_numbers_map = my_calloc(sizeof(int), size,
660 "dictionary accession numbers map");
662 for (i=0;i<size;i++, k+=len)
664 word_to_ascii(p+k,word);
665 if (linker_trace_level >= 3)
666 printf("%03d %04x '%s' %02x %02x %02x\n",i,k,
667 word, p[k+len-3], p[k+len-2], p[k+len-1]);
669 accession_numbers_map[i]
670 = dictionary_add(word, p[k+len-3], p[k+len-2], p[k+len-1]);
673 /* (5) Run through import/export table */
675 m_read_pos = module_map[9];
676 if (linker_trace_level>=2)
677 printf("Import/export table is at byte offset %04x\n", m_read_pos);
680 { record_type = get_next_record(p);
681 if (((record_type == EXPORT_MV) || (record_type == EXPORTSF_MV))
682 && (IE.symbol_type == INDIVIDUAL_PROPERTY_T))
683 { int32 si = symbol_index(IE.symbol_name, -1);
684 property_identifier_map[IE.symbol_value] = svals[si];
690 accept_export(); break;
692 accept_import(); break;
694 } while (record_type != 0);
696 if ((linker_trace_level >= 4) && (no_rr != 0))
697 { printf("Replaced routine addresses:\n");
698 for (i=0; i<no_rr; i++)
699 { printf("Replace code offset %04x with %04x\n",
700 routine_replace[i], routine_replace_with[i]);
704 if (linker_trace_level >= 4)
705 { printf("Symbol cross-references table:\n");
706 for (i=0; i<module_map[6]; i++)
707 { if (xref_table[i] != -1)
708 printf("module %4d -> story file '%s'\n", i,
709 (char *) symbs[xref_table[i]]);
713 if (linker_trace_level >= 4)
714 { printf("Action numbers map:\n");
715 for (i=0; i<256; i++)
716 if (actions_map[i] != -1)
717 printf("%3d -> %3d\n", i, actions_map[i]);
720 if ((linker_trace_level >= 4) && (max_property_identifier > 72))
721 { printf("Property identifier number map:\n");
722 for (i=72; i<max_property_identifier; i++)
723 { printf("module %04x -> program %04x\n",
724 i, property_identifier_map[i]);
728 /* (6) Backpatch the backpatch markers attached to exported symbols */
730 for (i=symbols_base; i<no_symbols; i++)
731 { if ((sflags[i] & CHANGE_SFLAG) && (sflags[i] & EXPORT_SFLAG))
732 { backpatch_marker = svals[i]/0x10000;
733 j = svals[i] % 0x10000;
735 j = backpatch_backpatch(j);
737 svals[i] = backpatch_marker*0x10000 + j;
738 if (backpatch_marker == 0) sflags[i] &= (~(CHANGE_SFLAG));
742 /* (7) Run through the Z-code backpatch table */
744 for (i=module_map[11]; i<module_map[11]+module_map[12]; i += 3)
745 { int marker_value = p[i];
746 int32 offset = 256*p[i+1] + p[i+2];
748 switch(marker_value & 0x7f)
753 backpatch_module_image(p, marker_value, ZCODE_ZA, offset);
756 backpatch_module_image(p, marker_value, ZCODE_ZA, offset);
757 write_byte_to_memory_block(&zcode_backpatch_table,
758 zcode_backpatch_size++, backpatch_marker);
759 write_byte_to_memory_block(&zcode_backpatch_table,
760 zcode_backpatch_size++, (offset + zmachine_pc)/256);
761 write_byte_to_memory_block(&zcode_backpatch_table,
762 zcode_backpatch_size++, (offset + zmachine_pc)%256);
767 /* (8) Run through the Z-machine backpatch table */
769 for (i=module_map[13]; i<module_map[13]+module_map[14]; i += 4)
770 { int marker_value = p[i], zmachine_area = p[i+1];
771 int32 offset = 256*p[i+2] + p[i+3];
777 backpatch_module_image(p, marker_value, zmachine_area, offset);
780 backpatch_module_image(p, marker_value, zmachine_area, offset);
781 switch(zmachine_area)
782 { case PROP_DEFAULTS_ZA:
785 offset += properties_table_size; break;
786 case INDIVIDUAL_PROP_ZA:
787 offset += individuals_length; break;
788 case DYNAMIC_ARRAY_ZA:
789 if (offset < (MAX_GLOBAL_VARIABLES*2))
790 { offset = 2*(variables_map[offset/2 + 16] - 16);
793 { offset += dynamic_array_area_size - (MAX_GLOBAL_VARIABLES*2);
797 backpatch_zmachine(backpatch_marker, zmachine_area, offset);
802 /* (9) Adjust initial values of variables */
804 if (linker_trace_level >= 3)
805 printf("\nFinal variables map, Module -> Main:\n");
808 if (variables_map[i]!=-1)
809 { if (linker_trace_level>=2)
810 printf("%d->%d ",i,variables_map[i]);
811 if (i<lowest_imported_global_no)
812 { int32 j = read_marker_address(p, 2,
813 DYNAMIC_ARRAY_ZA, 2*(i-16));
814 set_variable_value(variables_map[i]-16, j);
815 if (linker_trace_level>=2)
816 printf("(set var %d to %d) ",
817 variables_map[i], j);
820 if (linker_trace_level>=2) printf("\n");
822 /* (10) Glue in the dynamic array data */
824 i = m_static_offset - m_vars_offset - MAX_GLOBAL_VARIABLES*2;
825 if (dynamic_array_area_size + i >= MAX_STATIC_DATA)
826 memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
828 if (linker_trace_level >= 2)
829 printf("Inserting dynamic array area, %04x to %04x, at %04x\n",
830 m_vars_offset + MAX_GLOBAL_VARIABLES*2, m_static_offset,
831 variables_offset + dynamic_array_area_size);
833 { dynamic_array_area[dynamic_array_area_size+k]
834 = p[m_vars_offset+MAX_GLOBAL_VARIABLES*2+k];
836 dynamic_array_area_size+=i;
838 /* (11) Glue in the code area */
840 if (linker_trace_level >= 2)
841 printf("Inserting code area, %04x to %04x, at code offset %04x (+%04x)\n",
842 m_code_offset, m_strs_offset, code_offset, zmachine_pc);
844 for (k=m_code_offset;k<m_strs_offset;k++)
845 { if (temporary_files_switch)
846 { fputc(p[k],Temp2_fp);
850 write_byte_to_memory_block(&zcode_area, zmachine_pc++, p[k]);
853 /* (12) Glue in the static strings area */
855 if (linker_trace_level >= 2)
856 printf("Inserting strings area, %04x to %04x, \
857 at strings offset %04x (+%04x)\n",
858 m_strs_offset, link_offset, strings_offset,
859 static_strings_extent);
860 for (k=m_strs_offset;k<link_offset;k++)
861 { if (temporary_files_switch)
862 { fputc(p[k], Temp1_fp);
863 static_strings_extent++;
866 write_byte_to_memory_block(&static_strings_area,
867 static_strings_extent++, p[k]);
870 /* (13) Append the class object-numbers table: note that modules
871 provide extra information in this table */
875 { j = p[i]*256 + p[i+1]; i+=2;
878 class_object_numbers[no_classes] = j + no_objects;
879 j = p[i]*256 + p[i+1]; i+=2;
880 class_begins_at[no_classes++] = j + properties_table_size;
884 /* (14) Glue on the object tree */
886 if ((linker_trace_level>=2) && (m_no_objects>0))
887 printf("Joining on object tree of size %d\n", m_no_objects);
889 for (i=0, k=no_objects, last=m_props_offset;i<m_no_objects;i++)
890 { objectsz[no_objects].atts[0]=p[m_objs_offset+14*i];
891 objectsz[no_objects].atts[1]=p[m_objs_offset+14*i+1];
892 objectsz[no_objects].atts[2]=p[m_objs_offset+14*i+2];
893 objectsz[no_objects].atts[3]=p[m_objs_offset+14*i+3];
894 objectsz[no_objects].atts[4]=p[m_objs_offset+14*i+4];
895 objectsz[no_objects].atts[5]=p[m_objs_offset+14*i+5];
896 objectsz[no_objects].parent =
897 (p[m_objs_offset+14*i+6])*256+p[m_objs_offset+14*i+7];
898 objectsz[no_objects].next =
899 (p[m_objs_offset+14*i+8])*256+p[m_objs_offset+14*i+9];
900 objectsz[no_objects].child =
901 (p[m_objs_offset+14*i+10])*256+p[m_objs_offset+14*i+11];
902 if (linker_trace_level>=4)
903 printf("Module objects[%d] has %d,%d,%d\n",
904 i,objectsz[no_objects].parent,
905 objectsz[no_objects].next,objectsz[no_objects].child);
906 if (objectsz[no_objects].parent == 0x7fff)
907 { objectsz[no_objects].parent = 1;
908 if (objectsz[1].child == 0)
909 { objectsz[1].child = no_objects+1;
912 { int j1 = 0, j2 = objectsz[1].child;
915 j2 = objectsz[j2].next;
917 objectsz[j1].next = no_objects+1;
919 objectsz[no_objects].next = 0;
922 if (objectsz[no_objects].parent>0) objectsz[no_objects].parent += k;
923 if (objectsz[no_objects].next>0) objectsz[no_objects].next += k;
924 if (objectsz[no_objects].child>0) objectsz[no_objects].child += k;
925 objectsz[no_objects].propsize =
926 (p[m_objs_offset+14*i+12])*256+p[m_objs_offset+14*i+13];
927 last += objectsz[no_objects].propsize;
928 if (linker_trace_level>=4)
929 printf("Objects[%d] has %d,%d,%d\n",
930 no_objects,objectsz[no_objects].parent,
931 objectsz[no_objects].next,objectsz[no_objects].child);
935 /* (15) Glue on the properties */
937 if (last>m_props_offset)
938 { i = m_static_offset - m_vars_offset - MAX_GLOBAL_VARIABLES*2;
939 if (dynamic_array_area_size + i >= MAX_STATIC_DATA)
940 memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
942 if (linker_trace_level >= 2)
943 printf("Inserting object properties area, %04x to %04x, at +%04x\n",
944 m_props_offset, last, properties_table_size);
945 for (k=0;k<last-m_props_offset;k++)
946 properties_table[properties_table_size++] = p[m_props_offset+k];
949 /* (16) Bitwise OR Flags 2 (Z-machine requirements flags) */
951 j = p[16]*256 + p[17];
952 for (i=0, k=1;i<16;i++, k=k*2) flags2_requirements[i] |= ((j/k)%2);
954 /* (17) Append the individual property values table */
956 i = m_individuals_length;
957 if (individuals_length + i >= MAX_INDIV_PROP_TABLE_SIZE)
958 memoryerror("MAX_INDIV_PROP_TABLE_SIZE",
959 MAX_INDIV_PROP_TABLE_SIZE);
961 if (linker_trace_level >= 2)
962 printf("Inserting individual prop tables area, %04x to %04x, at +%04x\n",
963 m_individuals_offset, m_individuals_offset + i,
966 { individuals_table[individuals_length + k]
967 = p[m_individuals_offset + k];
969 individuals_length += i;
973 if (linker_trace_level >= 2)
974 printf("Link complete\n");
976 my_free(&p, "link module storage");
977 my_free(&xref_table, "linker cross-references table");
978 my_free(&property_identifier_map, "property identifier map");
979 my_free(&accession_numbers_map, "accession numbers map");
982 /* ========================================================================= */
983 /* Writing imports, exports and markers to the link data table during */
984 /* module compilation */
985 /* ------------------------------------------------------------------------- */
986 /* Writing to the link data table */
987 /* ------------------------------------------------------------------------- */
989 static void write_link_byte(int x)
990 { *link_data_top=(unsigned char) x; link_data_top++; link_data_size++;
991 if (subtract_pointers(link_data_top,link_data_holding_area)
992 >= MAX_LINK_DATA_SIZE)
993 { memoryerror("MAX_LINK_DATA_SIZE",MAX_LINK_DATA_SIZE);
997 extern void flush_link_data(void)
999 j = subtract_pointers(link_data_top, link_data_holding_area);
1000 if (temporary_files_switch)
1001 for (i=0;i<j;i++) fputc(link_data_holding_area[i], Temp3_fp);
1004 write_byte_to_memory_block(&link_data_area, link_data_size-j+i,
1005 link_data_holding_area[i]);
1006 link_data_top=link_data_holding_area;
1009 static void write_link_word(int32 x)
1010 { write_link_byte(x/256); write_link_byte(x%256);
1013 static void write_link_string(char *s)
1015 for (i=0; s[i]!=0; i++) write_link_byte(s[i]);
1019 /* ------------------------------------------------------------------------- */
1020 /* Exports and imports */
1021 /* ------------------------------------------------------------------------- */
1023 static void export_symbols(void)
1024 { int symbol_number;
1026 for (symbol_number = 0; symbol_number < no_symbols; symbol_number++)
1027 { int export_flag = FALSE, import_flag = FALSE;
1029 if (stypes[symbol_number]==GLOBAL_VARIABLE_T)
1030 { if (svals[symbol_number] < LOWEST_SYSTEM_VAR_NUMBER)
1031 { if (sflags[symbol_number] & IMPORT_SFLAG)
1034 if (!(sflags[symbol_number] & SYSTEM_SFLAG))
1039 { if (!(sflags[symbol_number] & SYSTEM_SFLAG))
1040 { if (sflags[symbol_number] & UNKNOWN_SFLAG)
1041 { if (sflags[symbol_number] & IMPORT_SFLAG)
1045 switch(stypes[symbol_number])
1052 default: export_flag = TRUE;
1058 { if (linker_trace_level >= 1)
1059 { IE.module_value = EXPORT_MV;
1060 IE.symbol_number = symbol_number;
1061 IE.symbol_type = stypes[symbol_number];
1062 IE.symbol_value = svals[symbol_number];
1063 IE.symbol_name = (char *) (symbs[symbol_number]);
1064 describe_importexport(&IE);
1067 if (sflags[symbol_number] & ACTION_SFLAG)
1068 write_link_byte(EXPORTAC_MV);
1070 if (sflags[symbol_number] & INSF_SFLAG)
1071 write_link_byte(EXPORTSF_MV);
1073 write_link_byte(EXPORT_MV);
1075 write_link_word(symbol_number);
1076 write_link_byte(stypes[symbol_number]);
1077 if (sflags[symbol_number] & CHANGE_SFLAG)
1078 write_link_byte(svals[symbol_number] / 0x10000);
1079 else write_link_byte(0);
1080 write_link_word(svals[symbol_number] % 0x10000);
1081 write_link_string((char *) (symbs[symbol_number]));
1086 { if (linker_trace_level >= 1)
1087 { IE.module_value = IMPORT_MV;
1088 IE.symbol_number = symbol_number;
1089 IE.symbol_type = stypes[symbol_number];
1090 IE.symbol_value = svals[symbol_number];
1091 IE.symbol_name = (char *) (symbs[symbol_number]);
1092 describe_importexport(&IE);
1095 write_link_byte(IMPORT_MV);
1096 write_link_word(symbol_number);
1097 write_link_byte(stypes[symbol_number]);
1098 write_link_word(svals[symbol_number]);
1099 write_link_string((char *) (symbs[symbol_number]));
1105 /* ------------------------------------------------------------------------- */
1106 /* Marking for later importation */
1107 /* ------------------------------------------------------------------------- */
1109 int mv_vref=LOWEST_SYSTEM_VAR_NUMBER-1;
1111 void import_symbol(int32 symbol_number)
1112 { sflags[symbol_number] |= IMPORT_SFLAG;
1113 switch(stypes[symbol_number])
1114 { case GLOBAL_VARIABLE_T:
1115 assign_symbol(symbol_number, mv_vref--, stypes[symbol_number]);
1120 /* ========================================================================= */
1121 /* Data structure management routines */
1122 /* ------------------------------------------------------------------------- */
1124 extern void init_linker_vars(void)
1125 { link_data_size = 0;
1126 initialise_memory_block(&link_data_area);
1129 extern void linker_begin_pass(void)
1130 { link_data_top = link_data_holding_area;
1133 extern void linker_endpass(void)
1139 extern void linker_allocate_arrays(void)
1140 { if (!module_switch)
1141 link_data_holding_area
1142 = my_malloc(64, "link data holding area");
1144 link_data_holding_area
1145 = my_malloc(MAX_LINK_DATA_SIZE, "link data holding area");
1148 extern void linker_free_arrays(void)
1149 { my_free(&link_data_holding_area, "link data holding area");
1150 deallocate_memory_block(&link_data_area);
1153 /* ========================================================================= */