1 #include "auxi.h"
2
3 /*
4 * in some embedded coff files, edata and end have type 0 not 4,
5 * and file value is pointer to next file sym (as here), but the last one
6 * points to an external symbol, not 0 as here.
7 */
8
9 #define C_NULL 0
10 #define C_AUTO 1
11 #define C_EXT 2
12 #define C_STAT 3
13 #define C_ARG 9
14 #define C_FCN 101
15 #define C_FILE 103
16
17 #define T_VOID 0
18 #define T_CHAR 2
19 #define T_SHORT 3
20 #define T_INT 4
21 #define T_LONG 5
22
23 #define DT_NON 0
24 #define DT_PTR 1
25 #define DT_FCN 2
26 #define DT_ARY 3
27
28 #define T(a, b) (((a)<<4)|b)
29
30 #define DOTTEXT ".text"
31 #define DOTDATA ".data"
32 #define DOTBSS ".bss"
33 #define DOTBF ".bf"
34 #define DOTEF ".ef"
35
36 #define SINDEX(s) (*((long*)(&s->become)))
37 #define LINDEX(s) (*((long*)(&s->used)))
38
39 typedef struct Hist Hist;
40
41 struct Hist{
42 Auto *a;
43 Hist *n;
44 };
45
46 static int nsym, nlc, lines;
47
48 static void cofflcsz(void);
49
50 static Hist *freeh, *curh;
51
52 static void
dohist(Auto * a)53 dohist(Auto *a)
54 {
55 Hist *h, **ha;
56
57 if(a->aoffset == 1){ /* new file */
58 for(ha = &curh; *ha != nil; ha = &((*ha)->n))
59 ;
60 *ha = freeh;
61 freeh = curh;
62 curh = nil;
63 }
64 if(freeh != nil){
65 h = freeh;
66 freeh = freeh->n;
67 }
68 else
69 h = malloc(sizeof(Hist));
70 h->a = a;
71 h->n = nil;
72 for(ha = &curh; *ha != nil; ha = &((*ha)->n))
73 ;
74 *ha = h;
75 }
76
77 static long
lineno(long n)78 lineno(long n)
79 {
80 long o, d;
81 Hist *h;
82
83 if(1)
84 return n; /* now using fileline() not pc2line() */
85
86 if(curh == nil)
87 return 0;
88 o = curh->a->aoffset-1;
89 d = 1;
90 for(h = curh->n; d && h != nil; h = h->n){
91 if(h->a->asym->name[1] || h->a->asym->name[2]){
92 if(h->a->type == D_FILE1) {
93 ;
94 }
95 else if(d == 1 && n < h->a->aoffset)
96 break;
97 else if(d++ == 1)
98 o -= h->a->aoffset;
99 }
100 else if(--d == 1)
101 o += h->a->aoffset;
102 }
103 return n-o;
104 }
105
106 static char *
filelookup(int k)107 filelookup(int k)
108 {
109 int i;
110 Symx *s;
111
112 for(i = 0; i < NHASH; i++){
113 for(s = hash[i]; s != nil; s = s->link){
114 if(s->type == SFILE && k == s->value)
115 return s->name+1;
116 }
117 }
118 return "";
119 }
120
121 static char*
filename(char * s)122 filename(char *s)
123 {
124 int j, k, l;
125 static char buf[256];
126
127 buf[0] = '\0';
128 if(s[0] != 0)
129 diag("bad filename");
130 for(j = 1; ; j += 2){
131 k = (s[j]<<8)|s[j+1];
132 if(k == 0)
133 break;
134 l = strlen(buf);
135 if(l != 0 && buf[l-1] != '/')
136 strcat(buf, "/");
137 strcat(buf, filelookup(k));
138 }
139 return buf;
140 }
141
142 static void
sput(char * s,int n)143 sput(char *s, int n)
144 {
145 int i;
146
147 for(i = 0; i < n && s != nil && *s != '\0'; i++, s++)
148 cput(*s);
149 for( ; i < n; i++)
150 cput(0);
151 }
152
153 static void
coffsect(char * s,long a,long sz,long o,long lp,long nl,long f)154 coffsect(char *s, long a, long sz, long o, long lp, long nl, long f)
155 {
156 if(0)
157 print("sect %s pa=%lux va=%lux sz=%lux\n", s, a, a, sz);
158 sput(s, 8); /* name <= 8 chars in len */
159 lputl(a); /* pa */
160 lputl(a); /* va */
161 lputl(sz); /* size */
162 lputl(o); /* file offset */
163 lputl(0); /* reloc */
164 lputl(lp); /* line nos */
165 lputl(0); /* no reloc entries */
166 lputl(nl); /* no line no entries */
167 lputl(f); /* flags */
168 hputl(0); /* reserved */
169 hputl(0); /* mem page no */
170 }
171
172 void
coffhdr(void)173 coffhdr(void)
174 {
175 if(0){
176 print("H=%lux t=%lux d=%lux b=%lux\n", HEADR, textsize, datsize, bsssize);
177 print("e=%lux ts=%lux ds=%lux\n", entryvalue(), INITTEXT, INITDAT);
178 }
179
180 /*
181 * file header
182 */
183 hputl(0xc2); /* version ID */
184 hputl(3); /* no section hdrs */
185 lputl(0); /* date stamp */
186 lputl(HEADR+textsize+datsize+6*nlc); /* sym table */
187 lputl(nsym); /* no sym table entries */
188 hputl(28); /* size optional hdr */
189 hputl(0x0103); /* flags */
190 hputl(0x97); /* target ID */
191 /*
192 * optional file header
193 */
194 hputl(0x108); /* magic */
195 hputl(0); /* version stamp */
196 lputl(textsize); /* text size */
197 lputl(datsize); /* data size */
198 lputl(bsssize); /* bss size */
199 lputl(entryvalue()); /* entry pt */
200 lputl(INITTEXT); /* text start */
201 lputl(INITDAT); /* data start */
202 /*
203 * sections
204 */
205 coffsect(DOTTEXT, INITTEXT, textsize, HEADR, HEADR+textsize+datsize, nlc, 0x20);
206 coffsect(DOTDATA, INITDAT, datsize, HEADR+textsize, 0, 0, 0x40);
207 coffsect(DOTBSS, INITDAT+datsize, bsssize, 0, 0, 0, 0x80);
208 }
209
210 static int
private(char * s)211 private(char *s)
212 {
213 return strcmp(s, "safe") == 0 || strcmp(s, "ret") == 0 || strcmp(s, "string") == 0;
214 }
215
216 static long stoff = 4;
217
218 static long
stput(char * s)219 stput(char *s)
220 {
221 long r;
222
223 r = stoff;
224 stoff += strlen(s)+1;
225 return r;
226 }
227
228 static long
strput(char * s)229 strput(char *s)
230 {
231 int l;
232
233 if((l = strlen(s)) > 8){
234 if(*s == '.' && private(s+1))
235 return 0;
236 while(*s)
237 cput(*s++);
238 cput(*s);
239 return l+1;
240 }
241 return 0;
242 }
243
244 static void
stflush(void)245 stflush(void)
246 {
247 int i;
248 long o;
249 Prog *p;
250 Auto *a, *f;
251 Symx *s;
252 char *fn, file[256];
253
254 lputl(stoff);
255 o = 4;
256 for(p = firstp; p != P; p = p->link){
257 if(p->as == ATEXT){
258 f = nil;
259 fn = nil;
260 for(a = p->to.autom; a != nil; a = a->link){
261 if(a->type == D_FILE){
262 f = a;
263 break;
264 }
265 }
266 if(f != nil)
267 fn = filename(f->asym->name);
268 if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){
269 strcpy(file, fn);
270 o += strput(file);
271 }
272 o += strput(p->from.sym->name);
273 for(a = p->to.autom; a != nil; a = a->link){
274 if(a->type == D_AUTO || a->type == D_PARAM)
275 o += strput(a->asym->name);
276 }
277 }
278 }
279 for(i = 0; i < NHASH; i++){
280 for(s = hash[i]; s != nil; s = s->link){
281 if(s->version > 0 && (s->type == SDATA || s->type == SBSS))
282 o += strput(s->name);
283 }
284 }
285 for(i = 0; i < NHASH; i++){
286 for(s = hash[i]; s != nil; s = s->link){
287 if(s->version == 0 && (s->type == SDATA || s->type == SBSS))
288 o += strput(s->name);
289 }
290 }
291 if(o != stoff)
292 diag("bad stflush offset");
293 }
294
295 static int
putsect(Symx * s)296 putsect(Symx *s)
297 {
298 int sz, ln;
299
300 sz = ln = 0;
301 // isn't this repetition ?
302 if(strcmp(s->name, DOTTEXT) == 0){
303 sz = textsize;
304 ln = nlc;
305 }
306 else if(strcmp(s->name, DOTDATA) == 0)
307 sz = datsize;
308 else if(strcmp(s->name, DOTBSS) == 0)
309 sz = bsssize;
310 else
311 diag("bad putsect sym");
312 lputl(sz);
313 hputl(0);
314 hputl(ln);
315 sput(nil, 10);
316 return 1;
317 }
318
319 static int
putfun(Symx * s)320 putfun(Symx *s)
321 {
322 /* lputl(SINDEX(s)+2); */
323 lputl(0);
324 lputl(0); /* patched later */
325 lputl(HEADR+textsize+datsize+LINDEX(s));
326 lputl(0); /* patched later */
327 sput(nil, 2);
328 return 1;
329 }
330
331 static int
putbf(int lno)332 putbf(int lno)
333 {
334 lputl(0);
335 hputl(lno);
336 hputl(lines);
337 lputl(autosize);
338 lputl(0); /* patched later */
339 sput(nil, 2);
340 return 1;
341 }
342
343 static int
putef(int lno)344 putef(int lno)
345 {
346 sput(nil, 4);
347 hputl(lno);
348 sput(nil, 12);
349 return 1;
350 }
351
352 static int
putsym(Symx * s,int sc,int t,int lno)353 putsym(Symx *s, int sc, int t, int lno)
354 {
355 long v;
356
357 if(s == nil || s->name == nil || s->name[0] == '\0' || (s->name[0] == '.' && private(s->name+1)))
358 return 0;
359 if(0)
360 print("putsym %s %d %ld %d %d\n", s->name, s->type, s->value, sc, t);
361 if(strlen(s->name) <= 8)
362 sput(s->name, 8);
363 else{
364 lputl(0);
365 lputl(stput(s->name));
366 }
367 /* value */
368 v = s->value;
369 if(s->type == SDATA || s->type == SDATA1 || s->type == SBSS)
370 lputl(INITDAT+v);
371 else if(sc == C_AUTO)
372 lputl(autosize+v);
373 else if(sc == C_ARG)
374 lputl(autosize+v+4);
375 else
376 lputl(v);
377 switch(s->type){ /* section number */
378 case STEXT:
379 case SLEAF:
380 hputl(1);
381 break;
382 case SDATA:
383 case SDATA1:
384 hputl(2);
385 break;
386 case SBSS:
387 hputl(3);
388 break;
389 case SFILE:
390 hputl(-2);
391 break;
392 default:
393 diag("type %d in putsym", s->type);
394 break;
395 }
396 hputl(t); /* type */
397 cput(sc); /* storage class */
398 /* aux entries */
399 if(sc == C_STAT && t == T_VOID && s->name[0] == '.'){ /* section */
400 cput(1);
401 return 1+putsect(s);
402 }
403 else if((t>>4) == DT_FCN){ /* function */
404 cput(1);
405 return 1+putfun(s);
406 }
407 else if(sc == C_FCN && strcmp(s->name, DOTBF) == 0){ /* bf */
408 cput(1);
409 return 1+putbf(lno);
410 }
411 else if(sc == C_FCN && strcmp(s->name, DOTEF) == 0){ /* ef */
412 cput(1);
413 return 1+putef(lno);
414 }
415 cput(0); /* 0 aux entry */
416 return 1;
417 }
418
419 static Symx*
defsym(char * p,int t,long v)420 defsym(char *p, int t, long v)
421 {
422 Symx *s;
423
424 s = lookupsym(p, 0);
425 if(s->type == SDATA || s->type == SBSS)
426 return nil; /* already output */
427 if(s->type == 0 || s->type == SXREF){
428 s->type = t;
429 s->value = v;
430 }
431 return s;
432 }
433
434 static int
specsym(char * p,int t,long v,int c)435 specsym(char *p, int t, long v, int c)
436 {
437 return putsym(defsym(p, t, v), c, T_VOID, 0);
438 }
439
440 static int
cclass(Symx * s)441 cclass(Symx *s)
442 {
443 /*
444 if(s->version > 0 && dclass == D_EXTERN)
445 diag("%s: version %d dclass EXTERN", s->name, s->version);
446 if(s->version == 0 && dclass == D_STATIC)
447 diag("%s: version %d dclass STATIC", s->name, s->version);
448 */
449 return s->version > 0 ? C_STAT : C_EXT;
450 }
451
452 static void
patchsym(long i,long o,long v)453 patchsym(long i, long o, long v)
454 {
455 long oo;
456
457 cflush();
458 oo = seek(cout, 0, 1);
459 seek(cout, HEADR+textsize+datsize+6*nlc+18*i+o, 0);
460 lputl(v);
461 cflush();
462 seek(cout, oo, 0);
463 }
464
465 void
coffsym(void)466 coffsym(void)
467 {
468 int i;
469 long ns, lno, lpc, v, vs, lastf;
470 Prog *p;
471 Auto *a, *f;
472 Symx *s, *bf, *ef, ts;
473 char *fn, file[256];
474
475 file[0] = '\0';
476 cofflcsz();
477 seek(cout, 6*nlc, 1); /* advance over line table */
478 ns = 0;
479 lpc = -1;
480 lno = -1;
481 lastf = -1;
482 bf = defsym(DOTBF, STEXT, 0);
483 ef = defsym(DOTEF, STEXT, 0);
484 for(p = firstp; p != P; p = p->link){
485 if(p->as != ATEXT){
486 if(p->line != 0)
487 lno = lineno(p->line);
488 }
489 if(p->as == ATEXT){
490 curtext = p;
491 autosize = p->to.offset+4;
492 if(lpc >= 0){
493 ef->value = lpc;
494 ns += putsym(ef, C_FCN, T_VOID, lno);
495 }
496 f = nil;
497 fn = nil;
498 for(a = p->to.autom; a != nil; a = a->link){
499 if(a->type == D_FILE || a->type == D_FILE1)
500 dohist(a);
501 if(f == nil && a->type == D_FILE)
502 f = a; /* main filename */
503 }
504 if(f != nil)
505 fn = filename(f->asym->name);
506 if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){
507 strcpy(file, fn);
508 ts.name = file;
509 ts.type = SFILE;
510 ts.value = 0;
511 if(lastf >= 0)
512 patchsym(lastf, 8, ns);
513 lastf = ns;
514 ns += putsym(&ts, C_FILE, T_VOID, 0);
515 }
516 if(p->link != P && p->link->line != 0)
517 lno = lineno(p->link->line);
518 else if(p->line != 0)
519 lno = lineno(p->line);
520 s = p->from.sym;
521 SINDEX(s) = ns;
522 ns += putsym(s, cclass(s), T(DT_FCN, T_INT), 0);
523 if(p->cond != P)
524 lines = LINDEX(p->cond->from.sym)-LINDEX(s)-1;
525 else
526 lines = 0;
527 bf->value = p->pc;
528 ns += putsym(bf, C_FCN, T_VOID, lno);
529 for(a = p->to.autom; a != nil; a = a->link){
530 if(a->type == D_AUTO || a->type == D_PARAM){
531 ts.name = a->asym->name;
532 ts.type = STEXT;
533 ts.value = a->aoffset;
534 ns += putsym(&ts, a->type == D_AUTO ? C_AUTO : C_ARG, T_INT, 0);
535 }
536 }
537 }
538 lpc = p->pc;
539 }
540 if(lpc >= 0){
541 ef->value = lpc;
542 ns += putsym(ef, C_FCN, T_VOID, lno);
543 }
544 /* patch up */
545 for(p = textp; p != P; p = p->cond){
546 s = p->from.sym;
547 if(p->cond != P){
548 v = SINDEX(p->cond->from.sym);
549 vs = p->cond->pc - p->pc;
550 }
551 else{
552 v = 0;
553 vs = INITTEXT+textsize-p->pc;
554 }
555 patchsym(SINDEX(s)+1, 4, 8*vs);
556 patchsym(SINDEX(s)+1, 12, v);
557 patchsym(SINDEX(s)+3, 12, v);
558 }
559 for(i = 0; i < NHASH; i++){
560 for(s = hash[i]; s != nil; s = s->link){
561 if(s->version > 0 && (s->type == SDATA || s->type == SBSS))
562 ns += putsym(s, cclass(s), T_INT, 0);
563 }
564 }
565 for(i = 0; i < NHASH; i++){
566 for(s = hash[i]; s != nil; s = s->link){
567 if(s->version == 0 && (s->type == SDATA || s->type == SBSS))
568 ns += putsym(s, cclass(s), T_INT, 0);
569 }
570 }
571 ns += specsym(DOTTEXT, STEXT, INITTEXT, C_STAT);
572 ns += specsym(DOTDATA, SDATA, 0, C_STAT);
573 ns += specsym(DOTBSS, SBSS, datsize, C_STAT);
574 ns += specsym("etext", STEXT, INITTEXT+textsize, C_EXT);
575 ns += specsym("edata", SDATA, datsize, C_EXT);
576 ns += specsym("end", SBSS, datsize+bsssize, C_EXT);
577 nsym = ns;
578 stflush();
579 }
580
581 void
cofflc(void)582 cofflc(void)
583 {
584 long olc, nl;
585 Symx *s;
586 Prog *p;
587 Auto *a;
588
589 cflush();
590 seek(cout, HEADR+textsize+datsize, 0);
591 nl = 0;
592 /* opc = INITTEXT; */
593 olc = 0;
594 for(p = firstp; p != P; p = p->link){
595 if(p->as == ATEXT){
596 curtext = p;
597 s = p->from.sym;
598 /* opc = p->pc; */
599 for(a = p->to.autom; a != nil; a = a->link){
600 if(a->type == D_FILE || a->type == D_FILE1)
601 dohist(a);
602 }
603 lputl(SINDEX(s));
604 hputl(0);
605 nl++;
606 continue;
607 }
608 if(p->line == 0 || p->line == olc || p->as == ANOP)
609 continue;
610 lputl(p->pc);
611 hputl(lineno(p->line));
612 nl++;
613 olc = p->line;
614 }
615 if(nl != nlc)
616 diag("bad line count in cofflc()");
617 nlc = nl;
618 }
619
620 static void
cofflcsz(void)621 cofflcsz(void)
622 {
623 long olc, nl;
624 Prog *p;
625
626 nl = 0;
627 olc = 0;
628 for(p = firstp; p != P; p = p->link){
629 if(p->as == ATEXT){
630 LINDEX(p->from.sym) = nl;
631 nl++;
632 continue;
633 }
634 if(p->line == 0 || p->line == olc || p->as == ANOP)
635 continue;
636 nl++;
637 olc = p->line;
638 }
639 nlc = nl;
640 }
641