scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

ld.c (9572B)


      1 static char sccsid[] = "@(#) ./ld/main.c";
      2 
      3 #include <ctype.h>
      4 #include <errno.h>
      5 #include <limits.h>
      6 #include <stdarg.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 
     11 #include <scc/mach.h>
     12 #include <scc/scc.h>
     13 #include <scc/ar.h>
     14 #include <scc/syslibs.h>
     15 
     16 #define NR_SYMBOL 128
     17 
     18 typedef struct objlst Objlst;
     19 typedef struct symbol Symbol;
     20 typedef struct section Section;
     21 
     22 enum {
     23 	NOINSTALL,
     24 	INSTALL,
     25 };
     26 
     27 enum {
     28 	OUTLIB,
     29 	INLIB,
     30 };
     31 
     32 struct section {
     33 	char *name;
     34 	unsigned long long size;
     35 	FILE *fp;
     36 	Section *next;
     37 };
     38 
     39 struct objlst {
     40 	Obj *obj;
     41 	struct objlst *next;
     42 };
     43 
     44 struct symbol {
     45 	char *name;
     46 	Obj *obj;
     47 	Objsym *def;
     48 	unsigned long long size, value;
     49 	struct symbol *next, *prev;
     50 	struct symbol *hash;
     51 };
     52 
     53 char *output = "a.out", *entry = "start", *datasiz;
     54 
     55 static Section *sections;
     56 static int bintype = -1;
     57 static char *filename, *membname;
     58 static Objlst *objhead, *objlast;
     59 static Symbol *symtab[NR_SYMBOL];
     60 static Symbol refhead = {
     61 	.next = &refhead,
     62 	.prev = &refhead,
     63 };
     64 
     65 static int sflag;		/* discard all the symbols */
     66 static int xflag;		/* discard local symbols */
     67 static int Xflag;		/* discard locals starting with 'L' */
     68 static int rflag;		/* preserve relocation bits */
     69 static int dflag;		/* define common even with rflag */
     70 static int gflag;               /* preserve debug symbols */
     71 
     72 static int status;
     73 
     74 static char *
     75 errstr(void)
     76 {
     77 	return strerror(errno);
     78 }
     79 
     80 static void
     81 error(char *fmt, ...)
     82 {
     83 	va_list va;
     84 
     85 	va_start(va, fmt);
     86 	fprintf(stderr, "ld: %s: ", filename);
     87 	if (membname)
     88 		fprintf(stderr, "%s: ", membname);
     89 	vfprintf(stderr, fmt, va);
     90 	putc('\n', stderr);
     91 	va_end(va);
     92 
     93 	status = EXIT_FAILURE;
     94 }
     95 
     96 static void
     97 cleanup(void)
     98 {
     99 	if (status != EXIT_FAILURE)
    100 		remove(output);
    101 }
    102 
    103 static int
    104 moreundef(void)
    105 {
    106 
    107 	return refhead.next != &refhead;
    108 }
    109 
    110 static Symbol *
    111 lookup(char *name, int install)
    112 {
    113 	size_t len;
    114 	char *s;
    115 	unsigned h;
    116 	Symbol *sym;
    117 
    118 	h = genhash(name) % NR_SYMBOL;
    119 
    120 	for (sym = symtab[h]; sym; sym = sym->hash) {
    121 		if (!strcmp(name, sym->name))
    122 			return sym;
    123 	}
    124 
    125 	if (!install)
    126 		return NULL;
    127 
    128 	len = strlen(name) + 1;
    129 	sym = malloc(sizeof(*sym));
    130 	s = malloc(len);
    131 	if (!len || !s) {
    132 		error("out of memory");
    133 		exit(EXIT_FAILURE);
    134 	}
    135 
    136 	sym->obj = NULL;
    137 	sym->name = memcpy(s, name, len);
    138 	sym->hash = symtab[h];
    139 	symtab[h] = sym;
    140 	sym->value = 0;
    141 	sym->size = 0;
    142 
    143 	refhead.next->prev = sym;
    144 	sym->next = refhead.next;
    145 	refhead.next = sym;
    146 	sym->prev = &refhead;
    147 
    148 	return sym;
    149 }
    150 
    151 static Symbol *
    152 define(Objsym *osym, Obj *obj)
    153 {
    154 	Symbol *sym = lookup(osym->name, INSTALL);
    155 
    156 	if (sym->def && sym->def->type != 'C') {
    157 		error("%s: symbol redefined", osym->name);
    158 		return NULL;
    159 	}
    160 
    161 	sym->obj = obj;
    162 	sym->def = osym;
    163 	sym->size = osym->size;
    164 	sym->value = osym->value;
    165 
    166 	sym->next->prev = sym->prev;
    167 	sym->prev->next = sym->next;
    168 	sym->next = sym->prev = NULL;
    169 
    170 	return sym;
    171 }
    172 
    173 static int
    174 newsym(Objsym *osym, Obj *obj)
    175 {
    176 	Symbol *sym;
    177 
    178 	switch (osym->type) {
    179 	case 'U':
    180 		lookup(osym->name, INSTALL);
    181 	case '?':
    182 	case 'N':
    183 		break;
    184 	case 'C':
    185 		sym = lookup(osym->name, NOINSTALL);
    186 		if (!sym || !sym->def) {
    187 			define(osym, obj);
    188 			break;
    189 		}
    190 		if (sym->def->type != 'C')
    191 			break;
    192 		if (sym->size < osym->size)
    193 			sym->size = osym->size;
    194 		break;
    195 	default:
    196 		if (isupper(osym->type))
    197 			define(osym, obj);
    198 		break;
    199 	}
    200 
    201 	return 1;
    202 }
    203 
    204 static void
    205 newsect(Objsect *secp, FILE *fp)
    206 {
    207 	int c;
    208 	unsigned long long align, size;
    209 	Section *sp;
    210 
    211 	for (sp = sections; sp; sp = sp->next) {
    212 		if (!strcmp(sp->name, secp->name))
    213 			break;
    214 	}
    215 
    216 	if (!sp) {
    217 		size_t len = strlen(secp->name) + 1;
    218 		char * s = malloc(len);
    219 		FILE *fp = tmpfile();
    220 
    221 		sp = malloc(sizeof(*sp));
    222 		if (!s || !sp || !fp)
    223 			goto err;
    224 
    225 		sp->name = memcpy(s, secp->name, len);
    226 		sp->size = 0;
    227 		sp->fp = fp;
    228 		sp->next = sections;
    229 
    230 		if (!sections)
    231 			sections = sp;
    232 	}
    233 
    234 	align = secp->align-1;
    235 	size = (sp->size + align) & ~align;
    236 
    237 	for (; secp->size < size; secp->size++)
    238 		putc(0, sp->fp);
    239 
    240 	fseek(fp, secp->offset, SEEK_SET);
    241 	while ((c = getc(fp)) != EOF)
    242 		putc(c, sp->fp);
    243 	fflush(sp->fp);
    244 
    245 	if (!ferror(fp) && !ferror(sp->fp))
    246 		return;
    247 
    248 err:
    249 	error(errstr());
    250 }
    251 
    252 static void
    253 loadobj(Obj *obj, FILE *fp)
    254 {
    255 	int n;
    256 	Objlst *lst;
    257 	Objsym *sym;
    258 	Objsect *secp;
    259 
    260 	if ((lst = malloc(sizeof(*lst))) == NULL) {
    261 		error("out of memory");
    262 		return;
    263 	}
    264 
    265 	if (objsect(obj) < 0 || objsyms(obj) < 0)
    266 		goto err1;
    267 
    268 	lst->obj = obj;
    269 	lst->next = NULL;
    270 
    271 	if (!objlast)
    272 		objlast = objhead = lst;
    273 	else
    274 		objlast = objlast->next = lst;
    275 
    276 	for (sym = obj->syms; sym; sym = sym->next)
    277 		newsym(sym, obj);
    278 
    279 	for (secp = obj->secs; secp; secp = secp->next)
    280 		newsect(secp, fp);
    281 
    282 	return;
    283 
    284 err1:
    285 	free(lst);
    286 	error("out of memory");
    287 }
    288 
    289 static void
    290 newobject(FILE *fp, int type, int inlib)
    291 {
    292 	Obj *obj;
    293 	Symbol *sym, *p;
    294 
    295 	if ((obj = objnew(type)) == NULL) {
    296 		error("out of memory");
    297 		return;
    298 	}
    299 
    300 	if (bintype == -1) {
    301 		bintype = type;
    302 	} else if (bintype != type) {
    303 		error("not compatible object file");
    304 		return;
    305 	}
    306 	bintype = type;
    307 
    308 	if (objread(obj, fp) < 0) {
    309 		error("object file corrupted");
    310 		goto delete;
    311 	}
    312 
    313 	if (inlib) {
    314 		p = &refhead;
    315 		for (sym = p->next; sym != p; sym = sym->next) {
    316 			if (objlookup(obj, sym->name, 0))
    317 				break;
    318 		}
    319 		if (sym == p)
    320 			goto  delete;
    321 	}
    322 	loadobj(obj, fp);
    323 
    324 	return;
    325 
    326 delete:
    327 	objdel(obj);
    328 	return;
    329 }
    330 
    331 static void
    332 loadlib(FILE *fp)
    333 {
    334 	int t, loaded;
    335 	long n;
    336 	Objsymdef *def, *dp;
    337 	Symbol *sym;
    338 
    339 	if (getindex(bintype, &n, &def, fp) < 0) {
    340 		error("corrupted index");
    341 		return;
    342 	}
    343 
    344 	for (loaded = 1; moreundef() && loaded; ) {
    345 		loaded = 0;
    346 		for (dp = def; dp; dp = dp->next) {
    347 			sym = lookup(dp->name, NOINSTALL);
    348 			if (!sym || sym->def)
    349 				continue;
    350 
    351 			if (fseek(fp, dp->offset, SEEK_SET) == EOF) {
    352 				error(errstr());
    353 				goto clean;
    354 			}
    355 
    356 			if ((t = objtype(fp, NULL)) == -1) {
    357 				error("library file corrupted");
    358 				goto clean;
    359 			}
    360 
    361 			if (t != bintype) {
    362 				error("incompatible library");
    363 				goto clean;
    364 			}
    365 
    366 			newobject(fp, t, OUTLIB);
    367 			loaded = 1;
    368 		}
    369 	}
    370 clean:
    371 	free(def);
    372 }
    373 
    374 static int
    375 newmember(FILE *fp, char *name, void *data)
    376 {
    377 	int t;
    378 	int *nmemb = data;
    379 
    380 	membname = data;
    381 
    382 	if (bintype == -1) {
    383 		error("an object file is needed before any library");
    384 		return 0;
    385 	}
    386 
    387 	if (*nmemb++ == 0) {
    388 		if (!strncmp(name, "/", SARNAM) ||
    389 		    !strncmp(name, "__.SYMDEF", SARNAM)) {
    390 			loadlib(fp);
    391 			return 0;
    392 		}
    393 	}
    394 
    395 	if ((t = objtype(fp, NULL)) == -1)
    396 		return 1;
    397 
    398 	if (bintype != t) {
    399 		error("wrong object file format");
    400 		return 1;
    401 	}
    402 
    403 	newobject(fp, t, INLIB);
    404 
    405 	return 1;
    406 }
    407 
    408 static int
    409 newlibrary(FILE *fp)
    410 {
    411 	int nmemb = 0;
    412 
    413 	return formember(fp, newmember, &nmemb);
    414 }
    415 
    416 static FILE *
    417 openfile(char *name, char *buffer)
    418 {
    419 	size_t pathlen, len;
    420 	FILE *fp;
    421 	char **bp, **base, **end;
    422 	char libname[FILENAME_MAX];
    423 
    424 	filename = name;
    425 	membname = NULL;
    426 	if (name[0] != '-' || name[1] != 'l') {
    427 		if ((fp = fopen(name, "rb")) == NULL)
    428 			error(errstr());
    429 		return fp;
    430 	}
    431 
    432 	len = strlen(name+2) + 3;
    433 	if (len > FILENAME_MAX-1) {
    434 		error("library name too long");
    435 		return NULL;
    436 	}
    437 	strcat(strcpy(buffer, "lib"), name+2);
    438 
    439 	filename = buffer;
    440 	if ((fp = fopen(libname, "rb")) != NULL)
    441 		return fp;
    442 
    443 	base = syslibs;
    444 	end = &syslibs[MAX_LIB_PATHS];
    445 	for (bp = base; bp < end && *bp; ++bp) {
    446 		pathlen = strlen(*bp);
    447 		if (pathlen + len > FILENAME_MAX-1)
    448 			continue;
    449 		memcpy(libname, *bp, pathlen);
    450 		memcpy(libname+pathlen+1, buffer, len);
    451 		buffer[pathlen] = '/';
    452 
    453 		if ((fp = fopen(buffer, "rb")) != NULL)
    454 			return fp;
    455 	}
    456 
    457 	error("not found");
    458 	return NULL;
    459 }
    460 
    461 static void
    462 pass1(int argc, char *argv[])
    463 {
    464 	int t;
    465 	FILE *fp;
    466 	char buff[FILENAME_MAX];
    467 
    468 	for ( ; *argv; ++argv) {
    469 		if ((fp = openfile(*argv, buff)) == NULL)
    470 			continue;
    471 
    472 		if ((t = objtype(fp, NULL)) != -1)
    473 			newobject(fp, t, OUTLIB);
    474 		else if (archive(fp))
    475 			newlibrary(fp);
    476 		else
    477 			error("bad format");
    478 
    479 		fclose(fp);
    480 	}
    481 
    482 	if (moreundef()) {
    483 		Symbol *sym, *p;
    484 
    485 		p = &refhead;
    486 		for (sym = p->next; sym != p; sym = sym->next) {
    487 			fprintf(stderr,
    488 			        "ld: symbol '%s' not defined\n",
    489 			        sym->name);
    490 		}
    491 		exit(EXIT_FAILURE);
    492 	}
    493 }
    494 
    495 static void
    496 pass2(int argc, char *argv[])
    497 {
    498 }
    499 
    500 static void
    501 usage(void)
    502 {
    503 	fputs("usage: ld [options] file ...\n", stderr);
    504 	exit(EXIT_FAILURE);
    505 }
    506 
    507 static void
    508 Lpath(char *path)
    509 {
    510 	char **bp, **base, **end;
    511 
    512 	base = syslibs;
    513 	end = &syslibs[MAX_LIB_PATHS];
    514 	for (bp = base; bp < end && *bp; ++bp)
    515 		;
    516 	if (bp == end) {
    517 		fputs("ld: too many -L options\n", stderr);
    518 		exit(1);
    519 	}
    520 	*bp = path;
    521 }
    522 
    523 int
    524 main(int argc, char *argv[])
    525 {
    526 	char *cp, **p;
    527 
    528 	for (--argc; *++argv; --argc) {
    529 		if (argv[0][0] != '-' || argv[0][1] == 'l')
    530 			break;
    531 		if (argv[0][1] == '-') {
    532 			--argc, ++argv;
    533 			break;
    534 		}
    535 		for (cp = &argv[0][1]; *cp; ++cp) {
    536 			switch (*cp) {
    537 			case 's':
    538 				sflag = 1;
    539 				break;
    540 			case 'x':
    541 				xflag = 1;
    542 				break;
    543 			case 'X':
    544 				Xflag = 1;
    545 				break;
    546 			case 'r':
    547 				rflag = 1;
    548 				break;
    549 			case 'd':
    550 				dflag = 1;
    551 				break;
    552 			case 'i':
    553 			case 'n':
    554 				/* TODO */
    555 				break;
    556 			case 'L':
    557 				if (argc == 0)
    558 					goto usage;
    559 				++argv, --argc;
    560 				Lpath(*argv);
    561 				break;
    562 			case 'u':
    563 				if (argc == 0)
    564 					goto usage;
    565 				++argv, --argc;
    566 				lookup(*argv, INSTALL);
    567 				break;
    568 			case 'o':
    569 				if (argc == 0)
    570 					goto usage;
    571 				++argv, --argc;
    572 				output = *argv;
    573 				break;
    574 			case 'e':
    575 				if (argc == 0)
    576 					goto usage;
    577 				++argv, --argc;
    578 				entry = *argv;
    579 				break;
    580 			case 'D':
    581 				if (argc == 0)
    582 					goto usage;
    583 				++argv, --argc;
    584 				datasiz = *argv;
    585 				break;
    586 			default:
    587 			usage:
    588 				usage();
    589 			}
    590 		}
    591 	}
    592 
    593 	if (argc == 0)
    594 		usage();
    595 
    596 	atexit(cleanup);
    597 
    598 	pass1(argc, argv);
    599 	pass2(argc, argv);
    600 
    601 	return status;
    602 }