comparison keiko/linker.c @ 0:bfdcc3820b32

Basis
author Mike Spivey <mike@cs.ox.ac.uk>
date Thu, 05 Oct 2017 08:04:15 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:bfdcc3820b32
1 /*
2 * linker.c
3 *
4 * This file is part of the Oxford Oberon-2 compiler
5 * Copyright (c) 2006--2016 J. M. Spivey
6 * All rights reserved
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <ctype.h>
32 #include "oblink.h"
33 #include "keiko.h"
34
35 static FILE *binfp; /* File for code output */
36
37 /* binwrite -- output code */
38 static void binwrite(void *buf, int size) {
39 int UNUSED nwritten = fwrite(buf, 1, size, binfp);
40 }
41
42 /* hexchar -- convert character from two-digit hex */
43 static char hexchar(char *s) {
44 char buf[3];
45
46 buf[0] = s[0]; buf[1] = s[1]; buf[2] = '\0';
47 return (char) strtoul(buf, NULL, 16);
48 }
49
50 static int iloc = 0, bloc = 0; /* Sizes of code, bss segments */
51 static int nmods = 0, nprocs = 0; /* Number of modules and procedures */
52 static symbol this_module; /* Current module */
53 static symbol this_proc; /* Current procedure */
54 static int proc_start; /* Start of procedure in dbuf */
55 static int code_size; /* Size of bytecode for procedure */
56
57 /* Instructions are stored as 'phrases' in abuf, a doubly-linked list.
58 Each phrase has a tentative assignment of a template, which describes
59 at least what arguments there should be; before the code is output, the
60 template may be replaced by one with bigger fields in order to make the
61 arguments fit. The code for a procedure is built up in abuf and output
62 at the end of the procedure. */
63
64 struct _phrase { /* An instruction in the assembler */
65 const char *q_name; /* Instruction name */
66 template q_templ; /* Best estimate of template */
67 int q_arg[MAXARGS]; /* Arguments */
68 int q_addr; /* Estimated address from start of proc */
69 symbol q_sym; /* Symbol for this address */
70 phrase q_target; /* Branch target */
71 phrase q_prev, q_next; /* Links in the list */
72 };
73
74 phrase abuf;
75
76 #define for_phrases(q) \
77 for (phrase q = abuf->q_next; q != abuf; q = q->q_next)
78
79 mempool pool;
80
81 static phrase alloc_phrase(void) {
82 return (phrase) pool_alloc(&pool, sizeof(struct _phrase));
83 }
84
85 static void init_abuf(void) {
86 pool_reset(&pool);
87 abuf = alloc_phrase();
88 abuf->q_name = (char *) "*dummy*";
89 abuf->q_templ = NULL;
90 abuf->q_addr = 0;
91 abuf->q_sym = NULL;
92 abuf->q_target = NULL;
93 abuf->q_prev = abuf->q_next = abuf;
94 }
95
96 static growdecl(dbuf);
97 #define dbuf growbuf(dbuf, uchar)
98 #define dloc growsize(dbuf)
99
100 static growdecl(rbuf);
101 #define rbuf growbuf(rbuf, unsigned)
102 #define rloc growsize(rbuf)
103
104 static growdecl(prims);
105 #define prims growbuf(prims, int)
106 #define nprims growsize(prims)
107
108 /* relocate -- record relocation bits */
109 void relocate(int loc, int bits) {
110 /* Each byte of relocation info covers CODES_PER_BYTE words */
111 int index = loc/(WORD_SIZE * CODES_PER_WORD);
112 int shift = loc/WORD_SIZE % CODES_PER_WORD * BITS_PER_CODE;
113
114 if (rloc < index+1) rloc = index+1;
115 buf_grow(rbuf);
116 rbuf[index] = (rbuf[index] & ~(CODE_MASK << shift)) | (bits << shift);
117 #ifdef DEBUG
118 if (dflag) printf("Reloc %d %d %#08x\n", loc, bits, rbuf[index]);
119 #endif
120 }
121
122 static void put_value(int addr, int value, int reloc) {
123 /* We carefully store all 4-byte values in dbuf in
124 machine-independent byte order: little-endian even if the host
125 is a big-endian machine. The value reloc determines how the
126 value should be relocated when the program is loaded by obx. */
127 put4(&dbuf[addr], value);
128 relocate(addr, reloc);
129 }
130
131 static int const_value(char *s) {
132 /* We must allow both signed and unsigned (especially hex)
133 constants, so negative numbers must be treated separately.
134 Note that strtol is specified to truncate to MAXINT on
135 overflow, not to operate mod 2^32. */
136
137 if (s == NULL)
138 return 0;
139 else if (s[0] == '-')
140 return strtol(s, NULL, 0);
141 else
142 return strtoul(s, NULL, 0);
143 }
144
145 static void data_value(int value, int reloc) {
146 buf_grow(dbuf);
147 put_value(dloc, value, reloc);
148 dloc += 4;
149 }
150
151 static void data_word(char *s) {
152 buf_grow(dbuf);
153 if (s == NULL || isdigit((int) s[0]) || s[0] == '-')
154 put_value(dloc, const_value(s), R_WORD);
155 else
156 use_global(find_symbol(s), dbuf, dloc);
157 dloc += 4;
158 }
159
160 static void put_string(char *str) {
161 char *s = str;
162 do {
163 buf_grow(dbuf);
164 dbuf[dloc++] = *s;
165 } while (*s++ != '\0');
166 }
167
168
169 /* Constant pool */
170
171 static growdecl(const_sym);
172 #define const_sym growbuf(const_sym, symbol)
173 #define nconsts growsize(const_sym)
174
175 #define get_const(n) get4(dbuf + proc_start + 4 * (CP_CONST+(n)))
176
177 static int find_const(int value, symbol sym) {
178 int i;
179
180 for (i = 0; i < nconsts; i++) {
181 if (sym == NULL
182 ? (const_sym[i] == NULL && get_const(i) == value)
183 : const_sym[i] == sym)
184 return i;
185 }
186
187 i = nconsts++;
188 buf_grow(const_sym);
189 const_sym[i] = sym;
190 buf_grow(dbuf);
191
192 if (sym == NULL)
193 put_value(dloc, value, R_WORD);
194 else
195 use_global(sym, dbuf, dloc);
196
197 dloc += 4;
198 return i;
199 }
200
201 static int find_dconst(int val0, int val1) {
202 int i;
203
204 for (i = 0; i < nconsts-1; i++) {
205 if (const_sym[i] == NULL && const_sym[i+1] == NULL
206 && get_const(i) == val0 && get_const(i+1) == val1)
207 return i;
208 }
209
210 i = nconsts; nconsts += 2;
211 buf_grow(const_sym);
212 const_sym[i] = const_sym[i+1] = NULL;
213 data_value(val0, R_WORD);
214 data_value(val1, R_WORD);
215
216 return i;
217 }
218
219 static int make_const(char *s) {
220 if (isdigit((int) s[0]) || s[0] == '-')
221 return find_const(const_value(s), NULL);
222 else
223 return find_const(0, find_symbol(s));
224 }
225
226
227 /* Instruction templates */
228
229 /* find_template -- find first template for instruction */
230 static template find_template(const char *name) {
231 const char *s = name;
232 int q = 0;
233 char ch;
234
235 /* The templates are organised in a trie */
236
237 do {
238 ch = *s++ & 0x7f;
239
240 if (templ_check[q+ch] != ch)
241 panic("*no template found for %s", name);
242
243 q = templ_trie[q+ch];
244 } while (ch != '\0');
245
246 return &templates[q];
247 }
248
249 /* fits -- test if an integer fits in a certain number of bits */
250 static mybool fits(int x, int n) {
251 int max = 1 << (n-1);
252 return (-max <= x && x < max);
253 }
254
255 /* fix_labels -- compute target for jump */
256 static void fix_labels(phrase q) {
257 const char *p = q->q_templ->t_pattern;
258
259 for (int j = 0; p[j] != '\0'; j++)
260 if (p[j] == 'R' || p[j] == 'S')
261 q->q_target = find_label(q->q_arg[j]);
262 }
263
264 /* displacement -- calculate branch displacement */
265 static int displacement(phrase q) {
266 /* Phrase |q| is a branch instruction. The signed displacement
267 is the distance from the opcode to the target. */
268 return (q->q_target->q_addr - q->q_addr);
269 }
270
271 /* match -- test whether a template matches its arguments */
272 static mybool match(phrase q, template t) {
273 /* Just check the last operand */
274 int n = strlen(t->t_pattern);
275 const char *p = t->t_pattern;
276 int *a = q->q_arg;
277
278 if (n == 0) return TRUE;
279
280 switch (p[n-1]) {
281 case 'N':
282 { int val = a[n-1];
283 return (val >= t->t_lo && val <= t->t_hi
284 && (val - t->t_lo) % t->t_step == 0); }
285 case '1':
286 case 'K':
287 return fits(a[n-1], 8);
288 case '2':
289 case 'L':
290 return fits(a[n-1], 16);
291 case 'R':
292 return fits(displacement(q), 16);
293 case 'S':
294 return fits(displacement(q), 8);
295 default:
296 return TRUE;
297 }
298 }
299
300 #ifdef DEBUG
301 static void print_args(phrase q) {
302 const char *patt = q->q_templ->t_pattern;
303
304 for (int j = 0; patt[j] != '\0'; j++) {
305 switch (patt[j]) {
306 case '1':
307 case '2':
308 case 'N':
309 case 'K':
310 case 'L':
311 printf(" %d", q->q_arg[j]); break;
312 case 'R':
313 case 'S':
314 printf(" %+d", displacement(q)); break;
315 default:
316 printf(" ???");
317 }
318 }
319 }
320 #endif
321
322 static int get_arg(char tmpl, char *rand, template t, int cxt[]) {
323 if (rand[0] == '$' && cxt != NULL)
324 return cxt[rand[1] - 'a'];
325
326 switch (tmpl) {
327 case '1':
328 case '2':
329 case 'N':
330 if (isdigit((int) rand[0]) || rand[0] == '-')
331 return const_value(rand);
332 else
333 return sym_value(find_symbol(rand));
334
335 case 'R':
336 case 'S':
337 return make_label(find_symbol(rand));
338
339 case 'K':
340 case 'L':
341 return make_const(rand);
342
343 default:
344 panic("*bad template %c for %s", tmpl, t->t_name);
345 return 0;
346 }
347 }
348
349 /* do_template -- enter an instruction */
350 static phrase do_template(template t, char *rands[], phrase rgt, int cxt[]) {
351 /* Template t determines the number and kinds of operands for the
352 instruction; depending on the values of the operands, it may or
353 may not end up actually matching the instruction. */
354
355 phrase q = alloc_phrase();
356 phrase lft = rgt->q_prev;
357 const char *patt = t->t_pattern;
358
359 q->q_name = t->t_name;
360 q->q_templ = t;
361 for (int i = 0; patt[i] != '\0'; i++)
362 q->q_arg[i] = get_arg(patt[i], rands[i], t, cxt);
363 q->q_addr = 0;
364 q->q_sym = NULL;
365 q->q_target = NULL;
366 q->q_prev = lft; q->q_next = rgt;
367 lft->q_next = rgt->q_prev = q;
368 return q;
369 }
370
371 /* expand -- replace macro by its expansion */
372 static phrase expand(phrase q) {
373 static char buf[128];
374 char *words[10];
375 template t = q->q_templ;
376 phrase r = q->q_prev, q1;
377
378 for (int i = 0; t->t_macro[i] != NULL; i++) {
379 strcpy(buf, t->t_macro[i]);
380 int n = split_line(buf, words);
381 template t1 = find_template(words[0]);
382 if (strlen(t1->t_pattern) != n-1 || t->t_size < 0)
383 panic("*macro expansion failed");
384
385 /* Insert expansion before original phrase */
386 q1 = do_template(t1, &words[1], q, q->q_arg);
387 fix_labels(q1);
388 }
389
390 /* Delete the original */
391 q->q_prev->q_next = q->q_next;
392 q->q_next->q_prev = q->q_prev;
393
394 return r->q_next;
395 }
396
397 /* check_matches -- revise choice of templates, return TRUE if ok already */
398 static mybool check_matches(void) {
399 mybool ok = TRUE;
400
401 for (phrase q = abuf->q_next; q != abuf; ) {
402 template t = q->q_templ;
403
404 if (t->t_macro[0] != NULL) {
405 /* A macro instruction: expand it */
406 q = expand(q);
407 ok = FALSE;
408 } else if (! match(q, t)) {
409 t++;
410
411 if (t >= &templates[NTEMPLATES] || t->t_name != NULL) {
412 panic("*no template fits %s", q->q_name);
413 }
414
415 q->q_templ = t;
416 ok = FALSE;
417 } else {
418 q = q->q_next;
419 }
420 }
421
422 return ok;
423 }
424
425 /* assemble -- assemble instructions */
426 static void assemble(void) {
427 mybool ok;
428 int trial = 0;
429
430 for_phrases (q) fix_labels(q);
431
432 /* A tentative assignment of templates has already been computed,
433 but the arguments may not fit in the field sizes assigned. So
434 now we repeatedly revise the assignment until all arguments fit.
435 Changing the assignment will increase the size of some instructions,
436 perhaps making branches longer so that they no longer fit either
437 -- that's why iteration is necessary.
438
439 The invariant is that there is no feasible choice of templates that
440 makes any instruction smaller than it is in the current assignment.
441 The variant is the total number of templates that remain to be tried.
442 Correctness of the algorithm follows from the fact that making one
443 instruction larger cannot allow another to be smaller. */
444
445 do {
446 int a = 0;
447 trial++;
448 #ifdef DEBUG
449 if (dflag > 0)
450 printf("Checking templates (pass %d)\n", trial);
451 #endif
452
453 /* Calculate address of each instruction */
454 for_phrases (q) {
455 q->q_addr = a;
456 a += q->q_templ->t_size;
457 }
458
459 code_size = a;
460 ok = check_matches(); /* Revise template choices */
461 } while (!ok);
462 }
463
464 /* make_binary -- output binary code */
465 static void make_binary(void) {
466 for_phrases (q) {
467 template t = q->q_templ;
468 const char *p = t->t_pattern;
469 int *a = q->q_arg;
470
471 #ifdef DEBUG
472 if (dflag > 0) {
473 printf("%d: %s(%s)", q->q_addr, q->q_name, p);
474 print_args(q);
475 printf("\n");
476 }
477 #endif
478
479 if (q->q_sym != NULL)
480 def_global(q->q_sym, CODE, iloc + q->q_addr, X_LINE);
481
482 if (p[0] == 'N')
483 write_int(1, t->t_op + (a[0] - t->t_lo)/t->t_step);
484 else if (t->t_oplen > 0)
485 binwrite(&t->t_op, t->t_oplen);
486
487 for (int j = 0; p[j] != '\0'; j++) {
488 switch (p[j]) {
489 case 'N':
490 break;
491 case '1':
492 case 'K':
493 write_int(1, a[j]); break;
494 case '2':
495 case 'L':
496 write_int(2, a[j]); break;
497 case 'R':
498 write_int(2, displacement(q)); break;
499 case 'S':
500 write_int(1, displacement(q)); break;
501 default:
502 panic("*bad template %c", p[j]);
503 }
504 }
505 }
506 }
507
508 /* MARK pseudo-instructions generate no code, and are used to place labels,
509 line numbers, etc. */
510 struct _template mark = {
511 "*MARK*", "", 0, 0, 0, 0, 0, 0, { NULL }
512 };
513
514 static phrase put_mark(symbol s) {
515 phrase q = do_template(&mark, NULL, abuf, NULL);
516 q->q_sym = s;
517 return q;
518 }
519
520 /* const_head -- start of constant pool */
521 static void const_head(int prim, int code, int reloc,
522 int frame, int stack, char *map) {
523 data_value(prim, R_SUBR); /* Primitive */
524 data_value(code, reloc); /* Entry point */
525 data_value(0, R_WORD); /* Code size */
526 data_value(frame, R_WORD); /* Frame size in words */
527 data_value(stack, R_WORD); /* Stack size in words */
528 data_word(map); /* Frame map */
529 data_value(0, R_WORD); /* Stack map table */
530 }
531
532 typedef struct {
533 phrase sm_addr; /* Pointer to the JPROC instruction */
534 char *sm_text; /* Symbol or numeric value */
535 } stackmap;
536
537 static growdecl(smbuf);
538 #define smbuf growbuf(smbuf, stackmap)
539 #define smp growsize(smbuf)
540
541 /* fix_stackmaps -- fix up the stack maps for the current procedure */
542 static void fix_stackmaps(void) {
543 if (smp == 0) return;
544
545 /* Fill in the address of the table in the constant pool */
546 put_value(proc_start + 4*CP_STKMAP, dloc, R_DATA);
547
548 /* Create the table itself */
549 for (int i = 0; i < smp; i++) {
550 stackmap *sm = &smbuf[i];
551
552 /* The return address for the call: '+1' to allow for the space
553 occupied by the JPROC instruction */
554 data_value(iloc + sm->sm_addr->q_addr + 1, R_CODE);
555
556 /* The stack map */
557 data_word(sm->sm_text);
558 }
559
560 data_value(0, R_WORD);
561 }
562
563 typedef struct {
564 int h_begin, h_end; /* Scope of handler */
565 symbol h_excep; /* Exception */
566 phrase h_body; /* Handler code */
567 } handler;
568
569 /* check_inproc -- panic if not in a procedure */
570 static void check_inproc(const char *opcode) {
571 if (this_proc == NULL)
572 panic("*%s occurs outside any procedure", opcode);
573 }
574
575 /* do_directive -- process a directive */
576 static void do_directive(const char *dir, int n, char *rands[], int nrands) {
577 union { int n; float f; } fcvt;
578 dblbuf dcvt;
579 int v;
580
581 switch (n) {
582 case D_LABEL:
583 check_inproc(dir);
584 /* Each label is defined as the |abuf| index of its target */
585 def_label(find_symbol(rands[0]), put_mark(NULL));
586 break;
587
588 case D_STRING:
589 for (int i = 0; rands[0][2*i] != '\0'; i++) {
590 buf_grow(dbuf);
591 dbuf[dloc++] = hexchar(&rands[0][2*i]);
592 }
593 dloc = align(dloc, 4);
594 break;
595
596 case D_CONST:
597 check_inproc(dir);
598 if ((isdigit((int) rands[0][0]) || rands[0][0] == '-')
599 && fits(v = const_value(rands[0]), 16))
600 gen_inst("PUSH %d", v);
601 else
602 gen_inst("LDKW %d", make_const(rands[0]));
603 break;
604
605 case D_GLOBAL:
606 check_inproc(dir);
607 gen_inst("LDKW %d", make_const(rands[0]));
608 break;
609
610 case D_FCONST:
611 check_inproc(dir);
612 fcvt.f = atof(rands[0]);
613 gen_inst("LDKF %d", find_const(fcvt.n, NULL));
614 break;
615
616 case D_DCONST:
617 check_inproc(dir);
618 dcvt.d = atof(rands[0]);
619 gen_inst("LDKD %d", find_dconst(dcvt.n.lo, dcvt.n.hi));
620 break;
621
622 case D_QCONST:
623 check_inproc(dir);
624 dcvt.q = strtoll(rands[0], NULL, 0);
625 gen_inst("LDKQ %d", find_dconst(dcvt.n.lo, dcvt.n.hi));
626 break;
627
628 case D_WORD:
629 data_word(rands[0]);
630 break;
631
632 case D_GLOVAR:
633 def_global(find_symbol(rands[0]), BSS, bloc, X_DATA);
634 bloc = align(bloc + strtoul(rands[1], NULL, 0), 4);
635 break;
636
637 case D_MODULE:
638 nmods++;
639 this_module = find_symbol(rands[0]);
640 def_global(this_module, DATA, dloc, X_MODULE);
641 module_data(this_module, strtoul(rands[1], NULL, 0),
642 strtol(rands[2], NULL, 0));
643 break;
644
645 case D_PRIMDEF:
646 nprocs++;
647 dloc = align(dloc, 8);
648 buf_grow(prims);
649 prims[nprims++] = dloc;
650 def_global(find_symbol(rands[0]), DATA, dloc, X_PROC);
651 const_head(DLTRAP, dloc + 4*CP_CONST + 4, R_DATA, 0, 0, NULL);
652 data_value(0, R_WORD); // Pointer to access block
653 put_string(rands[2]); // Type descriptor
654 put_string(rands[1]); // Symbol name
655 dloc = align(dloc, 4);
656 break;
657
658 case D_PROC:
659 nprocs++;
660 dloc = align(dloc, 8);
661 this_proc = find_symbol(rands[0]);
662 proc_start = dloc;
663 def_global(this_proc, DATA, proc_start, X_PROC);
664 const_head(INTERP, iloc, R_CODE, atoi(rands[1]),
665 atoi(rands[2]), rands[3]);
666
667 init_abuf();
668 init_labels();
669 nconsts = 0;
670 smp = 0;
671 break;
672
673 case D_STKMAP:
674 /* Stack map for a procedure call */
675 check_inproc(dir);
676 buf_grow(smbuf);
677 smbuf[smp].sm_addr = put_mark(NULL);
678 smbuf[smp].sm_text = must_strdup(rands[0]);
679 smp++;
680 break;
681
682 case D_END:
683 /* End of procedure body */
684 check_inproc(dir);
685 assemble(); /* Finally choose templates */
686 fix_stackmaps(); /* Compile the stack maps */
687 make_binary(); /* Output the code */
688 put_value(proc_start + 4*CP_SIZE, code_size, R_WORD);
689 iloc += code_size;
690 this_proc = NULL;
691 break;
692
693 case D_IMPORT:
694 case D_ENDHDR:
695 /* Ignore directives that appear in the file header */
696 break;
697
698 case D_DEFINE:
699 def_global(find_symbol(rands[0]), DATA, dloc, X_DATA);
700 break;
701
702 case D_LINE:
703 check_inproc(dir);
704
705 if (gflag) {
706 char buf[64];
707 sprintf(buf, "%s.%s", sym_name(this_module), rands[0]);
708 put_mark(make_symbol(buf));
709 }
710
711 if (linecount)
712 put_inst("LNUM", rands, nrands);
713
714 break;
715
716 #ifdef SPECIALS
717 case D_PCALL:
718 check_inproc(dir);
719 gen_inst("CALL %d", atoi(rands[0])+1);
720 break;
721
722 case D_PCALLW:
723 check_inproc(dir);
724 gen_inst("CALLW %d", atoi(rands[0])+1);
725 break;
726 #endif
727
728 default:
729 panic("*unknown directive %s (%d)", dir, n);
730 }
731 }
732
733 /* put_inst -- process one instruction or directive */
734 void put_inst(const char *name, char *rands[], unsigned nrands) {
735 template t = find_template(name);
736
737 if (nrands != strlen(t->t_pattern)) {
738 fprintf(stderr, "Instruction: %s", name);
739 for (int i = 0; i < nrands; i++)
740 fprintf(stderr, " %s", rands[i]);
741 fprintf(stderr, ", File: %s\n", err_file);
742 panic("*%s needs %d operands, got %d",
743 name, strlen(t->t_pattern), nrands);
744 }
745
746 if (t->t_size < 0)
747 do_directive(t->t_name, t->t_op, rands, nrands);
748 else {
749 check_inproc(name);
750 do_template(t, rands, abuf, NULL);
751 }
752 }
753
754 /* gen_inst -- generate an instruction from text */
755 void gen_inst(const char *fmt, ...) {
756 char line[80];
757 char *words[10];
758 int nwords;
759
760 va_list ap;
761
762 va_start(ap, fmt);
763 vsprintf(line, fmt, ap);
764 strcat(line, "\n");
765 va_end(ap);
766
767 nwords = split_line(line, words);
768 put_inst(words[0], &words[1], nwords-1);
769 }
770
771 /* save_string -- save a string in the data segment */
772 void save_string(const char *label, char *str) {
773 def_global(find_symbol(label), DATA, dloc, X_DATA);
774 put_string(str);
775 dloc = align(dloc, 4);
776 }
777
778
779 /* Object file output */
780
781 static int start; /* Starting offset of binary */
782
783 void init_linker(char *outname, char *interp) {
784 buf_init(dbuf, INIT_XMEM, 4, uchar, "data");
785 buf_init(rbuf, INIT_XMEM/(WORD_SIZE * CODES_PER_WORD),
786 1, unsigned, "relocation");
787 buf_init(smbuf, 16, 1, stackmap, "stack maps");
788 buf_init(const_sym, 256, 1, symbol, "constant pool");
789 buf_init(prims, 256, 1, int, "primitives");
790
791 binfp = fopen(outname, "wb");
792 if (binfp == NULL) {
793 perror(outname);
794 exit(2);
795 }
796
797 if (interp != NULL)
798 fprintf(binfp, "#!%s\n", interp);
799
800 start = ftell(binfp);
801 }
802
803 /* end_linking -- write later parts of object file */
804 void end_linking(void) {
805 trailer t;
806 int fsize, csize, symcount = 0, nwritten;
807 const char *magic = MAGIC;
808
809 csize = ftell(binfp) - start;
810 if (csize != iloc) {
811 fprintf(stderr, "csize = %d, iloc = %d\n", csize, iloc);
812 panic("*Wrong code size");
813 }
814
815 fix_data(dbuf, dloc);
816 rloc = (dloc/WORD_SIZE+CODES_PER_WORD-1)/CODES_PER_WORD;
817 buf_grow(rbuf);
818
819 binwrite(dbuf, dloc);
820 binwrite(rbuf, rloc * sizeof(unsigned));
821 if (!sflag) symcount = write_symtab();
822
823 fsize = ftell(binfp) + sizeof(trailer);
824
825 #define sym_val(x) (known(x) ? sym_value(find_symbol(x)) : 0)
826
827 /* Trailer */
828 strncpy((char *) t.magic, magic, 4);
829 put4(t.sig, SIG);
830 put4(t.primsig, 0);
831 put4(t.start, start - fsize);
832 put4(t.entry, sym_val("MAIN"));
833 put4(t.gcmap, sym_val("GCMAP"));
834 put4(t.libdir, sym_val("LIBDIR"));
835 put4(t.segment[S_CODE], iloc);
836 put4(t.segment[S_DATA], dloc);
837 put4(t.segment[S_BSS], bloc);
838 put4(t.segment[S_STACK], stack_size);
839 put4(t.nprocs, (sflag ? 0 : nprocs));
840 put4(t.nmods, (sflag ? 0 : nmods));
841 put4(t.nsyms, symcount);
842 nwritten = fwrite(&t, sizeof(trailer), 1, binfp);
843 if (nwritten < 1)
844 panic("Couldn't write trailer");
845
846 fclose(binfp);
847 }
848
849
850 /* Routines for writing values in machine-independent byte order */
851
852 void put_int(int n, uchar *buf, int x) {
853 for (int i = 0; i < n; i++)
854 buf[i] = (x >> (8*i)) & 0xff;
855 }
856
857 int get4(uchar *buf) {
858 return buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
859 }
860
861 void write_string(const char *s) {
862 binwrite((void *) s, strlen(s)+1);
863 }
864
865 void write_int(int n, int x) {
866 uchar buf[4];
867 put_int(n, buf, x);
868 binwrite(buf, n);
869 }
870
871
872 /* Primitive table */
873
874 void dump_prims(void) {
875 printf("/* Generated by oblink */\n\n");
876 printf("#include \"primtab.h\"\n\n");
877 printf("#define PRIMS(direct, indirect, wrapper)");
878
879 for (int i = 0; i < nprims; i++) {
880 char *tstring = (char *) &dbuf[prims[i]] + 4*CP_CONST + 4;
881 char *name = tstring + strlen(tstring) + 1;
882
883 printf(" \\\n");
884 if (tstring[0] == '*')
885 /* Declare a direct primitive */
886 printf(" direct(%s)", name);
887 else {
888 /* Build a wrapper */
889 char *mac = (isupper(name[0]) ? "indirect" : "wrapper");
890 printf(" %s(%s", mac, name);
891 for (int i = 0; tstring[i] != '\0'; i++)
892 printf(", %c", tstring[i]);
893 printf(")");
894 }
895 }
896
897 printf("\n\n");
898 printf("PRIMTAB(PRIMS)");
899 }
900