lib.c 31.1 KB
Newer Older
Russ Cox's avatar
Russ Cox committed
1
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
2
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
Russ Cox's avatar
Russ Cox committed
3
// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
//
//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
//	Portions Copyright © 1997-1999 Vita Nuova Limited
//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
//	Portions Copyright © 2004,2006 Bruce Ellis
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include	"l.h"
#include	"lib.h"
34 35
#include	"../../pkg/runtime/stack.h"

36 37
#include	<ar.h>

38 39
int iconv(Fmt*);

40
char	symname[]	= SYMDEF;
Russ Cox's avatar
Russ Cox committed
41
char	pkgname[]	= "__.PKGDEF";
Shenghou Ma's avatar
Shenghou Ma committed
42
char**	libdir;
43
int	nlibdir = 0;
Shenghou Ma's avatar
Shenghou Ma committed
44
static int	maxlibdir = 0;
Russ Cox's avatar
Russ Cox committed
45
static int	cout = -1;
46 47 48 49

char*	goroot;
char*	goarch;
char*	goos;
Russ Cox's avatar
Russ Cox committed
50
char*	theline;
51 52 53 54

void
Lflag(char *arg)
{
Shenghou Ma's avatar
Shenghou Ma committed
55 56 57 58 59 60 61
	char **p;

	if(nlibdir >= maxlibdir) {
		if (maxlibdir == 0)
			maxlibdir = 8;
		else
			maxlibdir *= 2;
Shenghou Ma's avatar
Shenghou Ma committed
62
		p = realloc(libdir, maxlibdir * sizeof(*p));
Shenghou Ma's avatar
Shenghou Ma committed
63 64 65 66 67
		if (p == nil) {
			print("too many -L's: %d\n", nlibdir);
			usage();
		}
		libdir = p;
68 69 70 71 72 73 74
	}
	libdir[nlibdir++] = arg;
}

void
libinit(void)
{
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
75 76
	char *race;

77
	fmtinstall('i', iconv);
78
	fmtinstall('Y', Yconv);
Russ Cox's avatar
Russ Cox committed
79
	fmtinstall('Z', Zconv);
80 81 82 83 84
	mywhatsys();	// get goroot, goarch, goos
	if(strcmp(goarch, thestring) != 0)
		print("goarch is not known: %s\n", goarch);

	// add goroot to the end of the libdir list.
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
85
	race = "";
Russ Cox's avatar
Russ Cox committed
86
	if(flag_race)
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
87 88
		race = "_race";
	Lflag(smprint("%s/pkg/%s_%s%s", goroot, goos, goarch, race));
89

90 91 92 93
	// Unix doesn't like it when we write to a running (or, sometimes,
	// recently run) binary, so remove the output file before writing it.
	// On Windows 7, remove() can force the following create() to fail.
#ifndef _WIN32
94
	remove(outfile);
95
#endif
96 97 98 99 100 101 102 103 104 105 106
	cout = create(outfile, 1, 0775);
	if(cout < 0) {
		diag("cannot create %s", outfile);
		errorexit();
	}

	if(INITENTRY == nil) {
		INITENTRY = mal(strlen(goarch)+strlen(goos)+10);
		sprint(INITENTRY, "_rt0_%s_%s", goarch, goos);
	}
	lookup(INITENTRY, 0)->type = SXREF;
107 108 109 110 111 112 113
	if(flag_shared) {
		if(LIBINITENTRY == nil) {
			LIBINITENTRY = mal(strlen(goarch)+strlen(goos)+20);
			sprint(LIBINITENTRY, "_rt0_%s_%s_lib", goarch, goos);
		}
		lookup(LIBINITENTRY, 0)->type = SXREF;
	}
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
}

void
errorexit(void)
{
	if(nerrors) {
		if(cout >= 0)
			remove(outfile);
		exits("error");
	}
	exits(0);
}

void
addlib(char *src, char *obj)
{
	char name[1024], pname[1024], comp[256], *p;
	int i, search;

	if(histfrogp <= 0)
		return;

	search = 0;
	if(histfrog[0]->name[1] == '/') {
		sprint(name, "");
		i = 1;
	} else
141
	if(isalpha((uchar)histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') {
142 143 144
		strcpy(name, histfrog[0]->name+1);
		i = 1;
	} else
145 146 147 148 149 150 151 152 153 154
	if(histfrog[0]->name[1] == '.') {
		sprint(name, ".");
		i = 0;
	} else {
		sprint(name, "");
		i = 0;
		search = 1;
	}

	for(; i<histfrogp; i++) {
155
		snprint(comp, sizeof comp, "%s", histfrog[i]->name+1);
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
		for(;;) {
			p = strstr(comp, "$O");
			if(p == 0)
				break;
			memmove(p+1, p+2, strlen(p+2)+1);
			p[0] = thechar;
		}
		for(;;) {
			p = strstr(comp, "$M");
			if(p == 0)
				break;
			if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
				diag("library component too long");
				return;
			}
			memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
			memmove(p, thestring, strlen(thestring));
		}
		if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
			diag("library component too long");
			return;
		}
178 179
		if(i > 0 || !search)
			strcat(name, "/");
180 181
		strcat(name, comp);
	}
182
	cleanname(name);
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
	
	// runtime.a -> runtime
	p = nil;
	if(strlen(name) > 2 && name[strlen(name)-2] == '.') {
		p = name+strlen(name)-2;
		*p = '\0';
	}
	
	// already loaded?
	for(i=0; i<libraryp; i++)
		if(strcmp(library[i].pkg, name) == 0)
			return;
	
	// runtime -> runtime.a for search
	if(p != nil)
		*p = '.';
199 200 201 202 203 204 205 206

	if(search) {
		// try dot, -L "libdir", and then goroot.
		for(i=0; i<nlibdir; i++) {
			snprint(pname, sizeof pname, "%s/%s", libdir[i], name);
			if(access(pname, AEXIST) >= 0)
				break;
		}
207 208 209
	}else
		strcpy(pname, name);
	cleanname(pname);
Russ Cox's avatar
Russ Cox committed
210

211
	/* runtime.a -> runtime */
212 213
	if(p != nil)
		*p = '\0';
214

215
	if(debug['v'])
216
		Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
Russ Cox's avatar
Russ Cox committed
217

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
	addlibpath(src, obj, pname, name);
}

/*
 * add library to library list.
 *	srcref: src file referring to package
 *	objref: object file referring to package
 *	file: object file, e.g., /home/rsc/go/pkg/container/vector.a
 *	pkg: package import path, e.g. container/vector
 */
void
addlibpath(char *srcref, char *objref, char *file, char *pkg)
{
	int i;
	Library *l;
	char *p;
234 235

	for(i=0; i<libraryp; i++)
236
		if(strcmp(file, library[i].file) == 0)
237
			return;
238

239
	if(debug['v'] > 1)
240
		Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
241
			cputime(), srcref, objref, file, pkg);
242

243 244 245
	if(libraryp == nlibrary){
		nlibrary = 50 + 2*libraryp;
		library = realloc(library, sizeof library[0] * nlibrary);
246 247
	}

248 249
	l = &library[libraryp++];

250 251
	p = mal(strlen(objref) + 1);
	strcpy(p, objref);
252 253
	l->objref = p;

254 255
	p = mal(strlen(srcref) + 1);
	strcpy(p, srcref);
256 257
	l->srcref = p;

258 259
	p = mal(strlen(file) + 1);
	strcpy(p, file);
260 261
	l->file = p;

262 263
	p = mal(strlen(pkg) + 1);
	strcpy(p, pkg);
264
	l->pkg = p;
265 266 267
}

void
Russ Cox's avatar
Russ Cox committed
268
loadinternal(char *name)
269
{
270 271
	char pname[1024];
	int i, found;
272

273 274
	found = 0;
	for(i=0; i<nlibdir; i++) {
Russ Cox's avatar
Russ Cox committed
275
		snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name);
276
		if(debug['v'])
Russ Cox's avatar
Russ Cox committed
277
			Bprint(&bso, "searching for %s.a in %s\n", name, pname);
278
		if(access(pname, AEXIST) >= 0) {
Russ Cox's avatar
Russ Cox committed
279
			addlibpath("internal", "internal", pname, name);
280 281 282 283
			found = 1;
			break;
		}
	}
284
	if(!found)
Russ Cox's avatar
Russ Cox committed
285 286 287 288 289 290 291 292 293 294 295
		Bprint(&bso, "warning: unable to find %s.a\n", name);
}

void
loadlib(void)
{
	int i;

	loadinternal("runtime");
	if(thechar == '5')
		loadinternal("math");
Russ Cox's avatar
Russ Cox committed
296
	if(flag_race)
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
297
		loadinternal("runtime/race");
298

299 300
	for(i=0; i<libraryp; i++) {
		if(debug['v'])
301
			Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref);
302
		iscgo |= strcmp(library[i].pkg, "runtime/cgo") == 0;
303
		objfile(library[i].file, library[i].pkg);
304
	}
305 306 307 308 309 310 311 312 313 314
	
	// We've loaded all the code now.
	// If there are no dynamic libraries needed, gcc disables dynamic linking.
	// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
	// assumes that a dynamic binary always refers to at least one dynamic library.
	// Rather than be a source of test cases for glibc, disable dynamic linking
	// the same way that gcc would.
	//
	// Exception: on OS X, programs such as Shark only work with dynamic
	// binaries, so leave it enabled on OS X (Mach-O) binaries.
315
	if(!flag_shared && !havedynamic && HEADTYPE != Hdarwin)
316
		debug['d'] = 1;
Russ Cox's avatar
Russ Cox committed
317 318
	
	importcycles();
319
	sortdynexp();
320
}
321

322 323 324 325 326 327 328 329 330
/*
 * look for the next file in an archive.
 * adapted from libmach.
 */
int
nextar(Biobuf *bp, int off, struct ar_hdr *a)
{
	int r;
	int32 arsize;
Lucio De Re's avatar
Lucio De Re committed
331
	char *buf;
332 333 334 335

	if (off&01)
		off++;
	Bseek(bp, off, 0);
Lucio De Re's avatar
Lucio De Re committed
336 337 338 339 340 341 342
	buf = Brdline(bp, '\n');
	r = Blinelen(bp);
	if(buf == nil) {
		if(r == 0)
			return 0;
		return -1;
	}
343
	if(r != SAR_HDR)
Lucio De Re's avatar
Lucio De Re committed
344
		return -1;
345
	memmove(a, buf, SAR_HDR);
Lucio De Re's avatar
Lucio De Re committed
346
	if(strncmp(a->fmag, ARFMAG, sizeof a->fmag))
347 348 349 350
		return -1;
	arsize = strtol(a->size, 0, 0);
	if (arsize&1)
		arsize++;
Lucio De Re's avatar
Lucio De Re committed
351
	return arsize + r;
352 353 354
}

void
355
objfile(char *file, char *pkg)
356
{
357
	int32 off, l;
358 359
	Biobuf *f;
	char magbuf[SARMAG];
360
	char pname[150];
361
	struct ar_hdr arhdr;
Russ Cox's avatar
Russ Cox committed
362

363
	pkg = smprint("%i", pkg);
364 365

	if(debug['v'])
366
		Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg);
367 368 369 370 371 372 373 374 375 376 377
	Bflush(&bso);
	f = Bopen(file, 0);
	if(f == nil) {
		diag("cannot open file: %s", file);
		errorexit();
	}
	l = Bread(f, magbuf, SARMAG);
	if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
		/* load it as a regular file */
		l = Bseek(f, 0L, 2);
		Bseek(f, 0L, 0);
Russ Cox's avatar
Russ Cox committed
378
		ldobj(f, pkg, l, file, FileObj);
379
		Bterm(f);
Scott Lawrence's avatar
Scott Lawrence committed
380
		free(pkg);
381 382
		return;
	}
383
	
384
	/* skip over __.GOSYMDEF */
385 386
	off = Boffset(f);
	if((l = nextar(f, off, &arhdr)) <= 0) {
387 388 389 390 391 392 393
		diag("%s: short read on archive file symbol header", file);
		goto out;
	}
	if(strncmp(arhdr.name, symname, strlen(symname))) {
		diag("%s: first entry not symbol header", file);
		goto out;
	}
394 395 396 397 398 399
	off += l;
	
	/* skip over (or process) __.PKGDEF */
	if((l = nextar(f, off, &arhdr)) <= 0) {
		diag("%s: short read on archive file symbol header", file);
		goto out;
Russ Cox's avatar
Russ Cox committed
400
	}
401 402 403 404 405 406 407 408
	if(strncmp(arhdr.name, pkgname, strlen(pkgname))) {
		diag("%s: second entry not package header", file);
		goto out;
	}
	off += l;

	if(debug['u'])
		ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef);
Russ Cox's avatar
Russ Cox committed
409

410
	/*
411 412 413 414 415 416 417 418 419
	 * load all the object files from the archive now.
	 * this gives us sequential file access and keeps us
	 * from needing to come back later to pick up more
	 * objects.  it breaks the usual C archive model, but
	 * this is Go, not C.  the common case in Go is that
	 * we need to load all the objects, and then we throw away
	 * the individual symbols that are unused.
	 *
	 * loading every object will also make it possible to
420
	 * load foreign objects not referenced by __.GOSYMDEF.
421
	 */
422 423 424 425 426 427 428
	for(;;) {
		l = nextar(f, off, &arhdr);
		if(l == 0)
			break;
		if(l < 0) {
			diag("%s: malformed archive", file);
			goto out;
429
		}
430 431 432 433 434 435 436 437
		off += l;

		l = SARNAME;
		while(l > 0 && arhdr.name[l-1] == ' ')
			l--;
		snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name);
		l = atolwhex(arhdr.size);
		ldobj(f, pkg, l, pname, ArchiveObj);
438 439 440 441
	}

out:
	Bterm(f);
Scott Lawrence's avatar
Scott Lawrence committed
442
	free(pkg);
443 444 445
}

void
Russ Cox's avatar
Russ Cox committed
446
ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
447
{
448 449 450
	char *line;
	int n, c1, c2, c3, c4;
	uint32 magic;
451
	vlong import0, import1, eof;
452
	char *t;
453 454 455

	eof = Boffset(f) + len;

456
	pn = strdup(pn);
457

458 459 460 461 462 463 464 465
	c1 = Bgetc(f);
	c2 = Bgetc(f);
	c3 = Bgetc(f);
	c4 = Bgetc(f);
	Bungetc(f);
	Bungetc(f);
	Bungetc(f);
	Bungetc(f);
466

467 468 469
	magic = c1<<24 | c2<<16 | c3<<8 | c4;
	if(magic == 0x7f454c46) {	// \x7F E L F
		ldelf(f, pkg, len, pn);
Scott Lawrence's avatar
Scott Lawrence committed
470
		free(pn);
471 472 473 474
		return;
	}
	if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) {
		ldmacho(f, pkg, len, pn);
Scott Lawrence's avatar
Scott Lawrence committed
475
		free(pn);
476
		return;
477
	}
Wei Guangjing's avatar
Wei Guangjing committed
478 479
	if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
		ldpe(f, pkg, len, pn);
Scott Lawrence's avatar
Scott Lawrence committed
480
		free(pn);
Wei Guangjing's avatar
Wei Guangjing committed
481 482
		return;
	}
483 484 485 486 487

	/* check the header */
	line = Brdline(f, '\n');
	if(line == nil) {
		if(Blinelen(f) > 0) {
488
			diag("%s: not an object file", pn);
489 490 491 492 493
			return;
		}
		goto eof;
	}
	n = Blinelen(f) - 1;
494 495
	line[n] = '\0';
	if(strncmp(line, "go object ", 10) != 0) {
496 497 498 499
		if(strlen(pn) > 3 && strcmp(pn+strlen(pn)-3, ".go") == 0) {
			print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thechar, pn, thechar, thechar);
			errorexit();
		}
500 501 502 503 504 505
		if(strcmp(line, thestring) == 0) {
			// old header format: just $GOOS
			diag("%s: stale object file", pn);
			return;
		}
		diag("%s: not an object file", pn);
Scott Lawrence's avatar
Scott Lawrence committed
506
		free(pn);
507 508
		return;
	}
Russ Cox's avatar
Russ Cox committed
509 510
	
	// First, check that the basic goos, string, and version match.
Scott Lawrence's avatar
Scott Lawrence committed
511
	t = smprint("%s %s %s ", goos, thestring, getgoversion());
Russ Cox's avatar
Russ Cox committed
512 513 514
	line[n] = ' ';
	if(strncmp(line+10, t, strlen(t)) != 0 && !debug['f']) {
		line[n] = '\0';
515 516
		diag("%s: object is [%s] expected [%s]", pn, line+10, t);
		free(t);
Scott Lawrence's avatar
Scott Lawrence committed
517
		free(pn);
518 519
		return;
	}
Russ Cox's avatar
Russ Cox committed
520 521 522 523 524 525 526 527 528 529 530 531
	
	// Second, check that longer lines match each other exactly,
	// so that the Go compiler and write additional information
	// that must be the same from run to run.
	line[n] = '\0';
	if(n-10 > strlen(t)) {
		if(theline == nil)
			theline = strdup(line+10);
		else if(strcmp(theline, line+10) != 0) {
			line[n] = '\0';
			diag("%s: object is [%s] expected [%s]", pn, line+10, theline);
			free(t);
Scott Lawrence's avatar
Scott Lawrence committed
532
			free(pn);
Russ Cox's avatar
Russ Cox committed
533 534 535
			return;
		}
	}
536 537
	free(t);
	line[n] = '\n';
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553

	/* skip over exports and other info -- ends with \n!\n */
	import0 = Boffset(f);
	c1 = '\n';	// the last line ended in \n
	c2 = Bgetc(f);
	c3 = Bgetc(f);
	while(c1 != '\n' || c2 != '!' || c3 != '\n') {
		c1 = c2;
		c2 = c3;
		c3 = Bgetc(f);
		if(c3 == Beof)
			goto eof;
	}
	import1 = Boffset(f);

	Bseek(f, import0, 0);
Russ Cox's avatar
Russ Cox committed
554
	ldpkg(f, pkg, import1 - import0 - 2, pn, whence);	// -2 for !\n
555 556
	Bseek(f, import1, 0);

557
	ldobj1(f, pkg, eof - Boffset(f), pn);
Scott Lawrence's avatar
Scott Lawrence committed
558
	free(pn);
559 560 561 562
	return;

eof:
	diag("truncated object file: %s", pn);
Scott Lawrence's avatar
Scott Lawrence committed
563
	free(pn);
564 565
}

566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
Sym*
newsym(char *symb, int v)
{
	Sym *s;
	int l;

	l = strlen(symb) + 1;
	s = mal(sizeof(*s));
	if(debug['v'] > 1)
		Bprint(&bso, "newsym %s\n", symb);

	s->dynid = -1;
	s->plt = -1;
	s->got = -1;
	s->name = mal(l + 1);
	memmove(s->name, symb, l);

	s->type = 0;
	s->version = v;
	s->value = 0;
	s->sig = 0;
	s->size = 0;
	nsymbol++;

	s->allsym = allsym;
	allsym = s;

	return s;
}

Russ Cox's avatar
Russ Cox committed
596 597
static Sym*
_lookup(char *symb, int v, int creat)
598 599 600 601 602 603 604 605 606 607
{
	Sym *s;
	char *p;
	int32 h;
	int l, c;

	h = v;
	for(p=symb; c = *p; p++)
		h = h+h+h + c;
	l = (p - symb) + 1;
608 609
	// not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
	h &= 0xffffff;
610
	h %= NHASH;
Russ Cox's avatar
Russ Cox committed
611
	for(s = hash[h]; s != S; s = s->hash)
612 613
		if(memcmp(s->name, symb, l) == 0)
			return s;
Russ Cox's avatar
Russ Cox committed
614 615
	if(!creat)
		return nil;
616

617
	s = newsym(symb, v);
Russ Cox's avatar
Russ Cox committed
618
	s->hash = hash[h];
619
	hash[h] = s;
620

621 622 623
	return s;
}

Russ Cox's avatar
Russ Cox committed
624 625 626 627 628 629 630 631 632 633 634 635 636
Sym*
lookup(char *name, int v)
{
	return _lookup(name, v, 1);
}

// read-only lookup
Sym*
rlookup(char *name, int v)
{
	return _lookup(name, v, 0);
}

637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
void
copyhistfrog(char *buf, int nbuf)
{
	char *p, *ep;
	int i;

	p = buf;
	ep = buf + nbuf;
	for(i=0; i<histfrogp; i++) {
		p = seprint(p, ep, "%s", histfrog[i]->name+1);
		if(i+1<histfrogp && (p == buf || p[-1] != '/'))
			p = seprint(p, ep, "/");
	}
}

void
addhist(int32 line, int type)
{
	Auto *u;
	Sym *s;
	int i, j, k;

	u = mal(sizeof(Auto));
	s = mal(sizeof(Sym));
	s->name = mal(2*(histfrogp+1) + 1);

	u->asym = s;
	u->type = type;
	u->aoffset = line;
	u->link = curhist;
	curhist = u;

	s->name[0] = 0;
	j = 1;
	for(i=0; i<histfrogp; i++) {
		k = histfrog[i]->value;
		s->name[j+0] = k>>8;
		s->name[j+1] = k;
		j += 2;
	}
	s->name[j] = 0;
	s->name[j+1] = 0;
}

void
histtoauto(void)
{
	Auto *l;

	while(l = curhist) {
		curhist = l->link;
		l->link = curauto;
		curauto = l;
	}
}

void
collapsefrog(Sym *s)
{
	int i;

	/*
	 * bad encoding of path components only allows
	 * MAXHIST components. if there is an overflow,
	 * first try to collapse xxx/..
	 */
	for(i=1; i<histfrogp; i++)
		if(strcmp(histfrog[i]->name+1, "..") == 0) {
			memmove(histfrog+i-1, histfrog+i+1,
				(histfrogp-i-1)*sizeof(histfrog[0]));
			histfrogp--;
			goto out;
		}

	/*
	 * next try to collapse .
	 */
	for(i=0; i<histfrogp; i++)
		if(strcmp(histfrog[i]->name+1, ".") == 0) {
			memmove(histfrog+i, histfrog+i+1,
				(histfrogp-i-1)*sizeof(histfrog[0]));
			goto out;
		}

	/*
	 * last chance, just truncate from front
	 */
	memmove(histfrog+0, histfrog+1,
		(histfrogp-1)*sizeof(histfrog[0]));

out:
	histfrog[histfrogp-1] = s;
}

void
nuxiinit(void)
{
	int i, c;

	for(i=0; i<4; i++) {
		c = find1(0x04030201L, i+1);
		if(i < 2)
			inuxi2[i] = c;
		if(i < 1)
			inuxi1[i] = c;
		inuxi4[i] = c;
743 744 745 746 747 748 749
		if(c == i) {
			inuxi8[i] = c;
			inuxi8[i+4] = c+4;
		} else {
			inuxi8[i] = c+4;
			inuxi8[i+4] = c;
		}
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
		fnuxi4[i] = c;
		fnuxi8[i] = c;
		fnuxi8[i+4] = c+4;
	}
	if(debug['v']) {
		Bprint(&bso, "inuxi = ");
		for(i=0; i<1; i++)
			Bprint(&bso, "%d", inuxi1[i]);
		Bprint(&bso, " ");
		for(i=0; i<2; i++)
			Bprint(&bso, "%d", inuxi2[i]);
		Bprint(&bso, " ");
		for(i=0; i<4; i++)
			Bprint(&bso, "%d", inuxi4[i]);
		Bprint(&bso, " ");
		for(i=0; i<8; i++)
			Bprint(&bso, "%d", inuxi8[i]);
		Bprint(&bso, "\nfnuxi = ");
		for(i=0; i<4; i++)
			Bprint(&bso, "%d", fnuxi4[i]);
		Bprint(&bso, " ");
		for(i=0; i<8; i++)
			Bprint(&bso, "%d", fnuxi8[i]);
		Bprint(&bso, "\n");
	}
	Bflush(&bso);
}

int
find1(int32 l, int c)
{
	char *p;
	int i;

	p = (char*)&l;
	for(i=0; i<4; i++)
		if(*p++ == c)
			return i;
	return 0;
}

int
find2(int32 l, int c)
{
794 795 796 797
	union {
		int32 l;
		short p[2];
	} u;
798 799 800
	short *p;
	int i;

801 802
	u.l = l;
	p = u.p;
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
	for(i=0; i<4; i+=2) {
		if(((*p >> 8) & 0xff) == c)
			return i;
		if((*p++ & 0xff) == c)
			return i+1;
	}
	return 0;
}

int32
ieeedtof(Ieee *e)
{
	int exp;
	int32 v;

	if(e->h == 0)
		return 0;
	exp = (e->h>>20) & ((1L<<11)-1L);
	exp -= (1L<<10) - 2L;
	v = (e->h & 0xfffffL) << 3;
	v |= (e->l >> 29) & 0x7L;
	if((e->l >> 28) & 1) {
		v++;
		if(v & 0x800000L) {
			v = (v & 0x7fffffL) >> 1;
			exp++;
		}
	}
831 832 833 834 835 836 837
	if(-148 <= exp && exp <= -126) {
		v |= 1<<23;
		v >>= -125 - exp;
		exp = -126;
	}
	else if(exp < -148 || exp >= 130)
		diag("double fp to single fp overflow: %.17g", ieeedtod(e));
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
	v |= ((exp + 126) & 0xffL) << 23;
	v |= e->h & 0x80000000L;
	return v;
}

double
ieeedtod(Ieee *ieeep)
{
	Ieee e;
	double fr;
	int exp;

	if(ieeep->h & (1L<<31)) {
		e.h = ieeep->h & ~(1L<<31);
		e.l = ieeep->l;
		return -ieeedtod(&e);
	}
	if(ieeep->l == 0 && ieeep->h == 0)
		return 0;
857 858
	exp = (ieeep->h>>20) & ((1L<<11)-1L);
	exp -= (1L<<10) - 2L;
859 860 861 862
	fr = ieeep->l & ((1L<<16)-1L);
	fr /= 1L<<16;
	fr += (ieeep->l>>16) & ((1L<<16)-1L);
	fr /= 1L<<16;
863 864 865 866 867
	if(exp == -(1L<<10) - 2L) {
		fr += (ieeep->h & (1L<<20)-1L);
		exp++;
	} else
		fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
	fr /= 1L<<21;
	return ldexp(fr, exp);
}

void
zerosig(char *sp)
{
	Sym *s;

	s = lookup(sp, 0);
	s->sig = 0;
}

int32
Bget4(Biobuf *f)
{
	uchar p[4];

	if(Bread(f, p, 4) != 4)
		return 0;
	return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}

void
mywhatsys(void)
{
894 895
	goroot = getgoroot();
	goos = getgoos();
896
	goarch = thestring;	// ignore $GOARCH - we know who we are
897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
}

int
pathchar(void)
{
	return '/';
}

static	uchar*	hunk;
static	uint32	nhunk;
#define	NHUNK	(10UL<<20)

void*
mal(uint32 n)
{
	void *v;

914
	n = (n+7)&~7;
915 916
	if(n > NHUNK) {
		v = malloc(n);
917 918 919 920
		if(v == nil) {
			diag("out of memory");
			errorexit();
		}
921 922 923 924 925
		memset(v, 0, n);
		return v;
	}
	if(n > nhunk) {
		hunk = malloc(NHUNK);
926 927 928 929
		if(hunk == nil) {
			diag("out of memory");
			errorexit();
		}
930 931 932 933 934 935 936 937 938 939
		nhunk = NHUNK;
	}

	v = hunk;
	nhunk -= n;
	hunk += n;

	memset(v, 0, n);
	return v;
}
940

941 942 943 944 945 946 947 948 949 950
void
unmal(void *v, uint32 n)
{
	n = (n+7)&~7;
	if(hunk - n == v) {
		hunk -= n;
		nhunk += n;
	}
}

951 952 953
// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
/*
 * Convert raw string to the prefix that will be used in the symbol table.
954
 * Invalid bytes turn into %xx.	 Right now the only bytes that need
955
 * escaping are %, ., and ", but we escape all control characters too.
956 957
 *
 * Must be same as ../gc/subr.c:/^pathtoprefix.
958 959 960 961 962
 */
static char*
pathtoprefix(char *s)
{
	static char hex[] = "0123456789abcdef";
963
	char *p, *r, *w, *l;
964 965
	int n;

966 967 968 969 970 971
	// find first character past the last slash, if any.
	l = s;
	for(r=s; *r; r++)
		if(*r == '/')
			l = r+1;

972 973 974
	// check for chars that need escaping
	n = 0;
	for(r=s; *r; r++)
975
		if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f)
976 977 978 979 980 981 982 983 984
			n++;

	// quick exit
	if(n == 0)
		return s;

	// escape
	p = mal((r-s)+1+2*n);
	for(r=s, w=p; *r; r++) {
985
		if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) {
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
			*w++ = '%';
			*w++ = hex[(*r>>4)&0xF];
			*w++ = hex[*r&0xF];
		} else
			*w++ = *r;
	}
	*w = '\0';
	return p;
}

int
iconv(Fmt *fp)
{
	char *p;

	p = va_arg(fp->args, char*);
	if(p == nil) {
		fmtstrcpy(fp, "<nil>");
		return 0;
	}
	p = pathtoprefix(p);
	fmtstrcpy(fp, p);
	return 0;
}

Russ Cox's avatar
Russ Cox committed
1011 1012 1013
void
mangle(char *file)
{
Russ Cox's avatar
Russ Cox committed
1014
	fprint(2, "%s: mangled input file\n", file);
Russ Cox's avatar
Russ Cox committed
1015 1016
	errorexit();
}
Russ Cox's avatar
Russ Cox committed
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032

Section*
addsection(Segment *seg, char *name, int rwx)
{
	Section **l;
	Section *sect;
	
	for(l=&seg->sect; *l; l=&(*l)->next)
		;
	sect = mal(sizeof *sect);
	sect->rwx = rwx;
	sect->name = name;
	sect->seg = seg;
	*l = sect;
	return sect;
}
1033

Russ Cox's avatar
Russ Cox committed
1034
void
1035
pclntab(void)
Russ Cox's avatar
Russ Cox committed
1036 1037 1038 1039
{
	vlong oldpc;
	Prog *p;
	int32 oldlc, v, s;
1040 1041 1042 1043
	Sym *sym;
	uchar *bp;
	
	sym = lookup("pclntab", 0);
1044
	sym->type = SPCLNTAB;
1045 1046 1047
	sym->reachable = 1;
	if(debug['s'])
		return;
Russ Cox's avatar
Russ Cox committed
1048 1049 1050

	oldpc = INITTEXT;
	oldlc = 0;
Russ Cox's avatar
Russ Cox committed
1051 1052
	for(cursym = textp; cursym != nil; cursym = cursym->next) {
		for(p = cursym->text; p != P; p = p->link) {
Russ Cox's avatar
Russ Cox committed
1053 1054 1055
			if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
				if(debug['O'])
					Bprint(&bso, "%6llux %P\n",
1056
						(vlong)p->pc, p);
Russ Cox's avatar
Russ Cox committed
1057 1058
				continue;
			}
Russ Cox's avatar
Russ Cox committed
1059
			if(debug['O'])
Russ Cox's avatar
Russ Cox committed
1060
				Bprint(&bso, "\t\t%6d", lcsize);
Russ Cox's avatar
Russ Cox committed
1061 1062 1063 1064 1065
			v = (p->pc - oldpc) / MINLC;
			while(v) {
				s = 127;
				if(v < 127)
					s = v;
1066 1067 1068
				symgrow(sym, lcsize+1);
				bp = sym->p + lcsize;
				*bp = s+128;	/* 129-255 +pc */
Russ Cox's avatar
Russ Cox committed
1069
				if(debug['O'])
Russ Cox's avatar
Russ Cox committed
1070
					Bprint(&bso, " pc+%d*%d(%d)", s, MINLC, s+128);
Russ Cox's avatar
Russ Cox committed
1071 1072
				v -= s;
				lcsize++;
Russ Cox's avatar
Russ Cox committed
1073
			}
Russ Cox's avatar
Russ Cox committed
1074 1075 1076 1077
			s = p->line - oldlc;
			oldlc = p->line;
			oldpc = p->pc + MINLC;
			if(s > 64 || s < -64) {
1078 1079 1080 1081 1082 1083 1084
				symgrow(sym, lcsize+5);
				bp = sym->p + lcsize;
				*bp++ = 0;	/* 0 vv +lc */
				*bp++ = s>>24;
				*bp++ = s>>16;
				*bp++ = s>>8;
				*bp = s;
Russ Cox's avatar
Russ Cox committed
1085 1086
				if(debug['O']) {
					if(s > 0)
Russ Cox's avatar
Russ Cox committed
1087
						Bprint(&bso, " lc+%d(%d,%d)\n",
Russ Cox's avatar
Russ Cox committed
1088 1089
							s, 0, s);
					else
Russ Cox's avatar
Russ Cox committed
1090
						Bprint(&bso, " lc%d(%d,%d)\n",
Russ Cox's avatar
Russ Cox committed
1091 1092
							s, 0, s);
					Bprint(&bso, "%6llux %P\n",
1093
						(vlong)p->pc, p);
Russ Cox's avatar
Russ Cox committed
1094 1095 1096
				}
				lcsize += 5;
				continue;
Russ Cox's avatar
Russ Cox committed
1097
			}
1098 1099
			symgrow(sym, lcsize+1);
			bp = sym->p + lcsize;
Russ Cox's avatar
Russ Cox committed
1100
			if(s > 0) {
1101
				*bp = 0+s;	/* 1-64 +lc */
Russ Cox's avatar
Russ Cox committed
1102
				if(debug['O']) {
Russ Cox's avatar
Russ Cox committed
1103
					Bprint(&bso, " lc+%d(%d)\n", s, 0+s);
Russ Cox's avatar
Russ Cox committed
1104
					Bprint(&bso, "%6llux %P\n",
1105
						(vlong)p->pc, p);
Russ Cox's avatar
Russ Cox committed
1106 1107
				}
			} else {
1108
				*bp = 64-s;	/* 65-128 -lc */
Russ Cox's avatar
Russ Cox committed
1109
				if(debug['O']) {
Russ Cox's avatar
Russ Cox committed
1110
					Bprint(&bso, " lc%d(%d)\n", s, 64-s);
Russ Cox's avatar
Russ Cox committed
1111
					Bprint(&bso, "%6llux %P\n",
1112
						(vlong)p->pc, p);
Russ Cox's avatar
Russ Cox committed
1113
				}
Russ Cox's avatar
Russ Cox committed
1114
			}
Russ Cox's avatar
Russ Cox committed
1115
			lcsize++;
Russ Cox's avatar
Russ Cox committed
1116
		}
Russ Cox's avatar
Russ Cox committed
1117
	}
1118 1119 1120
	if(lcsize & 1) {
		symgrow(sym, lcsize+1);
		sym->p[lcsize] = 129;
Russ Cox's avatar
Russ Cox committed
1121 1122
		lcsize++;
	}
1123 1124 1125
	sym->size = lcsize;
	lcsize = 0;

Russ Cox's avatar
Russ Cox committed
1126
	if(debug['v'] || debug['O'])
Russ Cox's avatar
Russ Cox committed
1127
		Bprint(&bso, "lcsize = %d\n", lcsize);
Russ Cox's avatar
Russ Cox committed
1128 1129
	Bflush(&bso);
}
Russ Cox's avatar
Russ Cox committed
1130 1131 1132 1133 1134 1135 1136 1137

#define	LOG	5
void
mkfwd(void)
{
	Prog *p;
	int i;
	int32 dwn[LOG], cnt[LOG];
1138
	Prog *lst[LOG];
Russ Cox's avatar
Russ Cox committed
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169

	for(i=0; i<LOG; i++) {
		if(i == 0)
			cnt[i] = 1;
		else
			cnt[i] = LOG * cnt[i-1];
		dwn[i] = 1;
		lst[i] = P;
	}
	i = 0;
	for(cursym = textp; cursym != nil; cursym = cursym->next) {
		for(p = cursym->text; p != P; p = p->link) {
			if(p->link == P) {
				if(cursym->next)
					p->forwd = cursym->next->text;
				break;
			}
			i--;
			if(i < 0)
				i = LOG-1;
			p->forwd = P;
			dwn[i]--;
			if(dwn[i] <= 0) {
				dwn[i] = cnt[i];
				if(lst[i] != P)
					lst[i]->forwd = p;
				lst[i] = p;
			}
		}
	}
}
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208

uint16
le16(uchar *b)
{
	return b[0] | b[1]<<8;
}

uint32
le32(uchar *b)
{
	return b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
}

uint64
le64(uchar *b)
{
	return le32(b) | (uint64)le32(b+4)<<32;
}

uint16
be16(uchar *b)
{
	return b[0]<<8 | b[1];
}

uint32
be32(uchar *b)
{
	return b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3];
}

uint64
be64(uchar *b)
{
	return (uvlong)be32(b)<<32 | be32(b+4);
}

Endian be = { be16, be32, be64 };
Endian le = { le16, le32, le64 };
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226

typedef struct Chain Chain;
struct Chain
{
	Sym *sym;
	Chain *up;
	int limit;  // limit on entry to sym
};

static int stkcheck(Chain*, int);
static void stkprint(Chain*, int);
static void stkbroke(Chain*, int);
static Sym *morestack;
static Sym *newstack;

enum
{
	HasLinkRegister = (thechar == '5'),
1227
	CallSize = (!HasLinkRegister)*PtrSize,	// bytes of stack required for a call
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
};

void
dostkcheck(void)
{
	Chain ch;
	Sym *s;
	
	morestack = lookup("runtime.morestack", 0);
	newstack = lookup("runtime.newstack", 0);

	// First the nosplits on their own.
	for(s = textp; s != nil; s = s->next) {
		if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) == 0)
			continue;
		cursym = s;
		ch.up = nil;
		ch.sym = s;
		ch.limit = StackLimit - CallSize;
		stkcheck(&ch, 0);
		s->stkcheck = 1;
	}
	
	// Check calling contexts.
	// Some nosplits get called a little further down,
1253
	// like newproc and deferproc.	We could hard-code
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
	// that knowledge but it's more robust to look at
	// the actual call sites.
	for(s = textp; s != nil; s = s->next) {
		if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) != 0)
			continue;
		cursym = s;
		ch.up = nil;
		ch.sym = s;
		ch.limit = StackLimit - CallSize;
		stkcheck(&ch, 0);
	}
}

static int
stkcheck(Chain *up, int depth)
{
	Chain ch, ch1;
	Prog *p;
	Sym *s;
	int limit, prolog;
	
	limit = up->limit;
	s = up->sym;
	p = s->text;
	
	// Small optimization: don't repeat work at top.
	if(s->stkcheck && limit == StackLimit-CallSize)
		return 0;
	
	if(depth > 100) {
		diag("nosplit stack check too deep");
		stkbroke(up, 0);
		return -1;
	}

	if(p == nil || p->link == nil) {
		// external function.
		// should never be called directly.
		// only diagnose the direct caller.
		if(depth == 1)
			diag("call to external function %s", s->name);
		return -1;
	}

	if(limit < 0) {
		stkbroke(up, limit);
		return -1;
	}

	// morestack looks like it calls functions,
	// but it switches the stack pointer first.
	if(s == morestack)
		return 0;

	ch.up = up;
	prolog = (s->text->textflag & NOSPLIT) == 0;
	for(p = s->text; p != P; p = p->link) {
		limit -= p->spadj;
		if(prolog && p->spadj != 0) {
			// The first stack adjustment in a function with a
			// split-checking prologue marks the end of the
			// prologue.  Assuming the split check is correct,
			// after the adjustment there should still be at least
			// StackLimit bytes available below the stack pointer.
			// If this is not the top call in the chain, no need
			// to duplicate effort, so just stop.
			if(depth > 0)
				return 0;
			prolog = 0;
			limit = StackLimit;
		}
		if(limit < 0) {
			stkbroke(up, limit);
			return -1;
		}
		if(iscall(p)) {
			limit -= CallSize;
			ch.limit = limit;
			if(p->to.type == D_BRANCH) {
				// Direct call.
				ch.sym = p->to.sym;
				if(stkcheck(&ch, depth+1) < 0)
					return -1;
			} else {
				// Indirect call.  Assume it is a splitting function,
				// so we have to make sure it can call morestack.
				limit -= CallSize;
				ch.sym = nil;
				ch1.limit = limit;
				ch1.up = &ch;
				ch1.sym = morestack;
				if(stkcheck(&ch1, depth+2) < 0)
					return -1;
				limit += CallSize;
			}
			limit += CallSize;
		}
		
	}
	return 0;
}

static void
stkbroke(Chain *ch, int limit)
{
	diag("nosplit stack overflow");
	stkprint(ch, limit);
}

static void
stkprint(Chain *ch, int limit)
{
	char *name;

	if(ch->sym)
		name = ch->sym->name;
	else
		name = "function pointer";

	if(ch->up == nil) {
		// top of chain.  ch->sym != nil.
		if(ch->sym->text->textflag & NOSPLIT)
			print("\t%d\tassumed on entry to %s\n", ch->limit, name);
		else
			print("\t%d\tguaranteed after split check in %s\n", ch->limit, name);
	} else {
		stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize);
		if(!HasLinkRegister)
			print("\t%d\ton entry to %s\n", ch->limit, name);
	}
	if(ch->limit != limit)
		print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit);
}
1387 1388 1389 1390 1391 1392 1393

int
headtype(char *name)
{
	int i;

	for(i=0; headers[i].name; i++)
1394 1395
		if(strcmp(name, headers[i].name) == 0) {
			headstring = headers[i].name;
1396
			return headers[i].val;
1397
		}
1398 1399 1400 1401
	fprint(2, "unknown header type -H %s\n", name);
	errorexit();
	return -1;  // not reached
}
Russ Cox's avatar
Russ Cox committed
1402 1403 1404 1405 1406 1407

void
undef(void)
{
	Sym *s;

Russ Cox's avatar
Russ Cox committed
1408
	for(s = allsym; s != S; s = s->allsym)
Russ Cox's avatar
Russ Cox committed
1409 1410 1411
		if(s->type == SXREF)
			diag("%s(%d): not defined", s->name, s->version);
}
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425

int
Yconv(Fmt *fp)
{
	Sym *s;
	Fmt fmt;
	int i;
	char *str;

	s = va_arg(fp->args, Sym*);
	if (s == S) {
		fmtprint(fp, "<nil>");
	} else {
		fmtstrinit(&fmt);
Lucio De Re's avatar
Lucio De Re committed
1426
		fmtprint(&fmt, "%s @0x%08llx [%lld]", s->name, (vlong)s->value, (vlong)s->size);
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446
		for (i = 0; i < s->size; i++) {
			if (!(i%8)) fmtprint(&fmt,  "\n\t0x%04x ", i);
			fmtprint(&fmt, "%02x ", s->p[i]);
		}
		fmtprint(&fmt, "\n");
		for (i = 0; i < s->nr; i++) {
			fmtprint(&fmt, "\t0x%04x[%x] %d %s[%llx]\n",
			      s->r[i].off,
			      s->r[i].siz,
			      s->r[i].type,
			      s->r[i].sym->name,
			      (vlong)s->r[i].add);
		}
		str = fmtstrflush(&fmt);
		fmtstrcpy(fp, str);
		free(str);
	}

	return 0;
}
Russ Cox's avatar
Russ Cox committed
1447 1448 1449

vlong coutpos;

1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466
static void
dowrite(int fd, char *p, int n)
{
	int m;
	
	while(n > 0) {
		m = write(fd, p, n);
		if(m <= 0) {
			cursym = S;
			diag("write error: %r");
			errorexit();
		}
		n -= m;
		p += m;
	}
}

Russ Cox's avatar
Russ Cox committed
1467 1468 1469 1470 1471 1472 1473 1474
void
cflush(void)
{
	int n;

	if(cbpmax < cbp)
		cbpmax = cbp;
	n = cbpmax - buf.cbuf;
1475 1476
	dowrite(cout, buf.cbuf, n);
	coutpos += n;
Russ Cox's avatar
Russ Cox committed
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
	cbp = buf.cbuf;
	cbc = sizeof(buf.cbuf);
	cbpmax = cbp;
}

vlong
cpos(void)
{
	return coutpos + cbp - buf.cbuf;
}

void
cseek(vlong p)
{
	vlong start;
	int delta;

	if(cbpmax < cbp)
		cbpmax = cbp;
	start = coutpos;
	if(start <= p && p <= start+(cbpmax - buf.cbuf)) {
//print("cseek %lld in [%lld,%lld] (%lld)\n", p, start, start+sizeof(buf.cbuf), cpos());
		delta = p - (start + cbp - buf.cbuf);
		cbp += delta;
		cbc -= delta;
//print("now at %lld\n", cpos());
		return;
	}

	cflush();
	seek(cout, p, 0);
	coutpos = p;
}

void
cwrite(void *buf, int n)
{
	cflush();
1515 1516
	if(n <= 0)
		return;
1517
	dowrite(cout, buf, n);
Russ Cox's avatar
Russ Cox committed
1518 1519
	coutpos += n;
}
1520

1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548
void
usage(void)
{
	fprint(2, "usage: %cl [options] main.%c\n", thechar, thechar);
	flagprint(2);
	exits("usage");
}

void
setheadtype(char *s)
{
	HEADTYPE = headtype(s);
}

void
setinterp(char *s)
{
	debug['I'] = 1; // denote cmdline interpreter override
	interpreter = s;
}

void
doversion(void)
{
	print("%cl version %s\n", thechar, getgoversion());
	errorexit();
}

1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629
void
genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
{
	Auto *a;
	Sym *s;

	// These symbols won't show up in the first loop below because we
	// skip STEXT symbols. Normal STEXT symbols are emitted by walking textp.
	s = lookup("text", 0);
	if(s->type == STEXT)
		put(s, s->name, 'T', s->value, s->size, s->version, 0);
	s = lookup("etext", 0);
	if(s->type == STEXT)
		put(s, s->name, 'T', s->value, s->size, s->version, 0);

	for(s=allsym; s!=S; s=s->allsym) {
		if(s->hide)
			continue;
		switch(s->type&SMASK) {
		case SCONST:
		case SRODATA:
		case SSYMTAB:
		case SPCLNTAB:
		case SDATA:
		case SNOPTRDATA:
		case SELFROSECT:
		case SMACHOGOT:
		case STYPE:
		case SSTRING:
		case SGOSTRING:
		case SWINDOWS:
		case SGCDATA:
		case SGCBSS:
			if(!s->reachable)
				continue;
			put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
			continue;

		case SBSS:
		case SNOPTRBSS:
			if(!s->reachable)
				continue;
			if(s->np > 0)
				diag("%s should not be bss (size=%d type=%d special=%d)", s->name, (int)s->np, s->type, s->special);
			put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
			continue;

		case SFILE:
			put(nil, s->name, 'f', s->value, 0, s->version, 0);
			continue;
		}
	}

	for(s = textp; s != nil; s = s->next) {
		if(s->text == nil)
			continue;

		/* filenames first */
		for(a=s->autom; a; a=a->link)
			if(a->type == D_FILE)
				put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
			else
			if(a->type == D_FILE1)
				put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);

		put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);

		/* frame, auto and param after */
		put(nil, ".frame", 'm', s->text->to.offset+PtrSize, 0, 0, 0);

		for(a=s->autom; a; a=a->link)
			if(a->type == D_AUTO)
				put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
			else
			if(a->type == D_PARAM)
				put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
	}
	if(debug['v'] || debug['n'])
		Bprint(&bso, "symsize = %ud\n", symsize);
	Bflush(&bso);
}