scc

A fork of https://git.simple-cc.org/scc/ for Qute

git clone https://git.8pit.net/scc.git

  1#include <ctype.h>
  2#include <errno.h>
  3#include <limits.h>
  4#include <stdio.h>
  5#include <stdint.h>
  6#include <stdlib.h>
  7#include <string.h>
  8
  9#include <scc/cstd.h>
 10#include <scc/mach.h>
 11#include <scc/scc.h>
 12
 13#include "as.h"
 14
 15#define HASHSIZ 64
 16#define NALLOC  10
 17
 18/*
 19 * sym must be the first field because we generate
 20 * a pointer to lsymbol from the symbol
 21 */
 22struct lsymbol {
 23	Symbol sym;
 24	Section *sec;
 25	struct lsymbol *next;
 26	struct lsymbol *hash;
 27};
 28
 29/*
 30 * sec must be the first field because we generate
 31 * a pointer to lsection from the section
 32 */
 33struct lsection {
 34	Section sec;
 35	FILE *fp;
 36	unsigned long long curpc;
 37	unsigned long long pc;
 38	struct lsection *next;
 39};
 40
 41Section *cursec;
 42Section *sbss, *sdata, *stext;
 43Symbol *linesym;
 44int pass;
 45
 46static Obj *obj;
 47static Map *map;
 48static struct lsection *seclist;
 49static struct lsymbol *hashtbl[HASHSIZ], *symlast, *symlist;
 50
 51static Symbol *cursym;
 52static Alloc *tmpalloc;
 53static int secindex, symindex;
 54
 55#ifndef NDEBUG
 56void
 57dumpstab(char *msg)
 58{
 59	struct lsymbol **bp, *lp;
 60
 61	fprintf(stderr, "%s\n", msg);
 62	for (bp = hashtbl; bp < &hashtbl[HASHSIZ]; ++bp) {
 63		if (*bp == NULL)
 64			continue;
 65
 66		fprintf(stderr, "[%d]", (int) (bp - hashtbl));
 67		for (lp = *bp; lp; lp = lp->hash) {
 68			fprintf(stderr, " -> %s:%0X:%0llX",
 69			       lp->sym.name,
 70			       lp->sym.flags,
 71			       lp->sym.value);
 72		}
 73		putc('\n', stderr);
 74	}
 75}
 76#endif
 77
 78Symbol *
 79lookup(char *name)
 80{
 81	int r;
 82	unsigned h;
 83	Symbol *sym;
 84	struct lsymbol *lp;
 85	char *curname, buf[INTIDENTSIZ+1];
 86
 87	if (*name == '.' && cursym) {
 88		if (!cursym)
 89			error("local label '%s' without global label", name);
 90		curname = cursym->name;
 91		r = snprintf(buf, sizeof(buf), "%s%s", curname, name);
 92		if (r < 0 || r >= sizeof(buf))
 93			error("too long local label '%s%s'", curname, name);
 94		name = buf;
 95	}
 96
 97	h = genhash(name) & HASHSIZ-1;
 98	for (lp = hashtbl[h]; lp; lp = lp->hash) {
 99		if (!casecmp(lp->sym.name, name))
100			return &lp->sym;
101	}
102
103	lp = xmalloc(sizeof(*lp));
104	lp->next = NULL;
105	lp->hash = hashtbl[h];
106	lp->sec = NULL;
107	hashtbl[h] = lp;
108
109	if (symlast)
110		symlast->next = lp;
111	symlast = lp;
112
113	if (!symlist)
114		symlist = lp;
115
116	sym = &lp->sym;
117	sym->name = xstrdup(name);
118	sym->flags = 0;
119	sym->size = sym->value = 0;
120	sym->section = cursec ? cursec->index : -1;
121
122	return sym;
123}
124
125Symbol *
126deflabel(char *name)
127{
128	int local = 0;
129	Symbol *sym;
130	struct lsection *lsec;
131	char label[MAXSYM+1];
132
133	if (*name == '.') {
134		int r;
135
136		local = 1;
137		if (!cursym) {
138			error("local label '%s' without global label", name);
139			return NULL;
140		}
141		r = snprintf(label, sizeof(label),
142		             "%s%s",
143		             cursym->name, name);
144		if (r == sizeof(label)) {
145			error("local label '%s' in '%s' produces too long symbol",
146			      name, cursym->name);
147			return NULL;
148		}
149		name = label;
150	}
151
152	sym = lookup(name);
153	if (pass == 1 && (sym->flags & FDEF))
154		error("redefinition of label '%s'", name);
155	if (cursec->flags & SABS)
156		sym->flags |= FABS;
157
158	lsec = (struct lsection *) cursec;
159	sym->value = lsec->curpc;
160	sym->section = cursec->index;
161
162	if (!local)
163		cursym = sym;
164	return sym;
165}
166
167int
168toobig(Node *np, int type)
169{
170	unsigned long long val = np->sym->value;
171
172	switch (type) {
173	case AIMM2:
174		return val > 3;
175	case AIMM3:
176		return val > 7;
177	case AIMM5:
178		return val > 0x1F;
179	case AIMM8:
180		return val > 0xFF;
181	case AIMM16:
182		return val > 0xFFFF;
183	case AIMM32:
184		return val > 0xFFFFFFFF;
185	case AIMM64:
186		return 1;
187	default:
188		abort();
189	}
190}
191
192unsigned long long
193getpc(void)
194{
195	struct lsection *lsec;
196
197	lsec = (struct lsection *) cursec;
198	return lsec->curpc;
199}
200
201static void
202incpc(int nbytes)
203{
204	struct lsection *lsec;
205	unsigned long long siz;
206	unsigned long long pc, curpc;
207
208	lsec = (struct lsection *) cursec;
209
210	pc = lsec->pc;
211	curpc = lsec->curpc;
212
213	lsec->curpc += nbytes;
214	lsec->pc += nbytes;
215
216	if (pass == 2)
217		return;
218
219	siz = lsec->pc - cursec->base;
220	if (siz > cursec->size)
221		cursec->size = siz;
222
223	if (pc > lsec->pc ||
224	    curpc > lsec->curpc ||
225	    lsec->curpc > maxaddr ||
226	    lsec->pc > maxaddr) {
227		die("as: address overflow in section '%s'");
228	}
229}
230
231static int
232secflags(char *attr)
233{
234	int c, flags;
235
236	if (!attr)
237		return 0;
238
239	for (flags = 0; c = *attr++; ) {
240		switch (c) {
241		case 'w':
242			flags |= SWRITE;
243			break;
244		case 'r':
245			flags |= SREAD;
246			break;
247		case 'x':
248			flags |= SEXEC;
249			break;
250		case 'c':
251			flags |= SALLOC;
252			break;
253		case 'l':
254			flags |= SLOAD;
255			break;
256		case 'a':
257			flags |= SABS;
258			break;
259		case 'm':
260			flags |= SRELOC;
261			break;
262		default:
263			abort();
264		}
265	}
266
267	return flags;
268}
269
270static int
271sectype(int flags)
272{
273	if (flags & SEXEC)
274		return 'T';
275	if ((flags & (SALLOC|SLOAD|SREAD)) == (SALLOC|SLOAD|SREAD))
276		return 'D';
277	if ((flags  & (SALLOC|SLOAD|SREAD)) == (SALLOC|SREAD))
278		return 'B';
279	return '?';
280}
281
282static Section *
283newsec(Symbol *sym, char *attr)
284{
285	int idx;
286	Section *sec;
287	struct lsection *lsec;
288	struct lsymbol *lsym;
289
290	if (secindex == INT_MAX) {
291		fputs("as: too many sections\n", stderr);
292		exit(EXIT_FAILURE);
293	}
294
295	lsec = xmalloc(sizeof(*lsec));
296	lsec->pc = lsec->curpc = 0;
297	lsec->next = seclist;
298	lsec->fp = NULL;
299	seclist = lsec;
300
301	sec = &lsec->sec;
302	sec->name = sym->name;
303	sec->base = sec->size = 0;
304	sec->flags = 0;
305	sec->fill = 0;
306	sec->align = 0;
307	sec->index = secindex;
308	sec->flags |= secflags(attr);
309	sec->type = sectype(sec->flags);
310
311	/* sym->flags = ? */
312	sym->section = sec->index;
313	sym->type = tolower(sec->type);
314	sym->index = symindex;
315	lsym = (struct lsymbol *) sym;
316	lsym->sec = sec;
317
318	if (mapsec(map, sec, NULL, 0) < 0) {
319		fprintf(stderr,
320		       "as: error allocating section mapping '%s'\n",
321		        sym->name);
322		exit(EXIT_FAILURE);
323	}
324
325	if (!setsec(obj, &secindex, sec)) {
326		fprintf(stderr,
327		        "as: error adding section '%s' to output\n",
328		        sym->name);
329		exit(EXIT_FAILURE);
330	}
331
332	if (!setsym(obj, &symindex, sym)) {
333		fprintf(stderr,
334		        "as: error adding section symbol '%s' to output\n",
335		        sym->name);
336		exit(EXIT_FAILURE);
337	}
338
339	secindex++;
340	symindex++;
341
342	return sec;
343}
344
345Section *
346defsec(char *name, char *attr)
347{
348	struct lsymbol *lsym;
349	Section *sec;
350	Symbol *sym;
351
352	cursec = NULL;
353	sym = lookup(name);
354	if (sym->flags & ~FSECT)
355		error("invalid section name '%s'", name);
356
357	lsym = (struct lsymbol *) sym;
358	sec = lsym->sec;
359	if (sec == NULL) {
360		sec = newsec(sym, attr);
361		lsym->sec = sec;
362		sym->section = sec->index;
363		sym->flags = FSECT;
364	}
365
366	return cursec = sec;
367}
368
369void
370ibinfmt(void)
371{
372	int t;
373
374	if ((t = objtype("coff-z80")) < 0) {
375		fprintf(stderr,
376		        "as: invalid binary format %s\n", "coff32-z80");
377		exit(EXIT_FAILURE);
378	}
379
380	if ((obj = newobj(t)) == NULL) {
381		fputs("as: error allocating output\n", stderr);
382		exit(EXIT_FAILURE);
383	}
384
385	if ((map = newmap(4, 0)) == NULL) {
386		perror("as");
387		exit(EXIT_FAILURE);
388	}
389
390	stext = defsec(".text", "mrxcl");
391	sdata = defsec(".data", "mrwcl");
392	sbss = defsec(".bss", "rwc");
393}
394
395void
396cleansecs(void)
397{
398	int r;
399	Section *sec;
400	struct lsection *lsec;
401
402	for (lsec = seclist; lsec; lsec = lsec->next) {
403		sec = &lsec->sec;
404		lsec->curpc = lsec->pc = sec->base;
405		if (pass == 1 || (sec->flags & SALLOC) == 0)
406			continue;
407
408		lsec->fp = tmpfile();
409		r = mapsec(map, sec, lsec->fp, sec->size);
410
411		if (!lsec->fp || r < 0) {
412			perror("as: creating section mapping");
413			exit(EXIT_FAILURE);
414		}
415	}
416	cursec = stext;
417}
418
419void
420emit(unsigned char *bytes, int n)
421{
422	struct lsection *lsec = (struct lsection *) cursec;
423
424	if (lsec->fp)
425		fwrite(bytes, n, 1, lsec->fp);
426	incpc(n);
427}
428
429Symbol *
430tmpsym(unsigned long long val)
431{
432	Symbol *sym;
433
434	if (!tmpalloc)
435		tmpalloc = alloc(sizeof(*sym), NALLOC);
436	sym = new(tmpalloc);
437	sym->value = val;
438	sym->section = -1;
439	sym->flags = FABS;
440
441	return sym;
442}
443
444void
445killtmp(void)
446{
447	if (!tmpalloc)
448		return;
449	dealloc(tmpalloc);
450	tmpalloc = NULL;
451}
452
453static int
454dumpsec(FILE *src, FILE *dst)
455{
456	int c;
457
458	if (!src)
459		return 0;
460
461	rewind(src);
462	while ((c = getc(src)) != EOF)
463		putc(c, dst);
464
465	if (ferror(src))
466		return -1;
467
468	return 0;
469}
470
471void
472writecoff(char *fname)
473{
474	FILE *fp;
475
476	if ((fp = fopen(fname, "wb")) == NULL)
477		goto error;
478
479	if (writeobj(obj, map, fp) < 0) {
480		fputs("as: corrupted object type\n", stderr);
481		goto error;
482	}
483
484	if (fclose(fp) == EOF)
485		goto error;
486	outfile = NULL;
487	return;
488
489error:
490	fprintf(stderr, "as: %s: error writing output file\n", fname);
491	if (errno)
492		perror("as");
493	exit(EXIT_FAILURE);
494}
495
496void
497writeout(char *fname)
498{
499	FILE *fp;
500	struct lsection *lp;
501
502	if ((fp = fopen(fname, "wb")) == NULL)
503		goto error;
504
505
506	for (lp = seclist; lp; lp = lp->next) {
507		if (dumpsec(lp->fp, fp) < 0)
508			goto error;
509	}
510	fflush(fp);
511
512	if (ferror(fp))
513		goto error;
514
515	fclose(fp);
516	outfile = NULL;
517
518	return;
519
520error:
521	fprintf(stderr, "as: %s: %s\n", fname, strerror(errno));
522	exit(EXIT_FAILURE);
523}