scc

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

ld.c (8622B)


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