asm.c 28.7 KB
Newer Older
1 2 3 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
// Inferno utils/6l/asm.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
//
//	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.

Russ Cox's avatar
Russ Cox committed
31 32
// Writing object files.

33
#include	"l.h"
34
#include	"../ld/lib.h"
Russ Cox's avatar
Russ Cox committed
35
#include	"../ld/elf.h"
Luuk van Dijk's avatar
Luuk van Dijk committed
36
#include	"../ld/dwarf.h"
37
#include	"../ld/macho.h"
Wei Guangjing's avatar
Wei Guangjing committed
38
#include	"../ld/pe.h"
39

40
#define PADDR(a)	((uint32)(a) & ~0x80000000)
41

42
char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
43
char freebsddynld[] = "/libexec/ld-elf.so.1";
Joel Sing's avatar
Joel Sing committed
44
char openbsddynld[] = "/usr/libexec/ld.so";
45
char netbsddynld[] = "/libexec/ld.elf_so";
46 47

char	zeroes[32];
Ken Thompson's avatar
Ken Thompson committed
48 49 50 51 52 53 54 55 56 57 58 59 60

vlong
entryvalue(void)
{
	char *a;
	Sym *s;

	a = INITENTRY;
	if(*a >= '0' && *a <= '9')
		return atolwhex(a);
	s = lookup(a, 0);
	if(s->type == 0)
		return INITTEXT;
61
	if(s->type != STEXT)
Ken Thompson's avatar
Ken Thompson committed
62 63 64 65 66 67 68
		diag("entry not text: %s", s->name);
	return s->value;
}

vlong
datoff(vlong addr)
{
69 70
	if(addr >= segdata.vaddr)
		return addr - segdata.vaddr + segdata.fileoff;
71 72
	if(addr >= segtext.vaddr)
		return addr - segtext.vaddr + segtext.fileoff;
Ken Thompson's avatar
Ken Thompson committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
	diag("datoff %#llx", addr);
	return 0;
}

enum {
	ElfStrEmpty,
	ElfStrInterp,
	ElfStrHash,
	ElfStrGot,
	ElfStrGotPlt,
	ElfStrDynamic,
	ElfStrDynsym,
	ElfStrDynstr,
	ElfStrRela,
	ElfStrText,
	ElfStrData,
	ElfStrBss,
	ElfStrShstrtab,
	ElfStrSymtab,
	ElfStrStrtab,
93 94
	ElfStrRelaPlt,
	ElfStrPlt,
Russ Cox's avatar
Russ Cox committed
95 96
	ElfStrGnuVersion,
	ElfStrGnuVersionR,
97
	ElfStrNoteNetbsdIdent,
98
	ElfStrNoPtrData,
99
	ElfStrNoPtrBss,
Ken Thompson's avatar
Ken Thompson committed
100 101 102 103 104 105 106 107 108 109 110
	NElfStr
};

vlong elfstr[NElfStr];

static int
needlib(char *name)
{
	char *p;
	Sym *s;

111 112 113
	if(*name == '\0')
		return 0;

Ken Thompson's avatar
Ken Thompson committed
114 115 116
	/* reuse hash code in symbol table */
	p = smprint(".elfload.%s", name);
	s = lookup(p, 0);
117
	free(p);
Ken Thompson's avatar
Ken Thompson committed
118 119 120 121 122 123 124
	if(s->type == 0) {
		s->type = 100;	// avoid SDATA, etc.
		return 1;
	}
	return 0;
}

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
int nelfsym = 1;

static void addpltsym(Sym*);
static void addgotsym(Sym*);

void
adddynrel(Sym *s, Reloc *r)
{
	Sym *targ, *rela, *got;
	
	targ = r->sym;
	cursym = s;

	switch(r->type) {
	default:
		if(r->type >= 256) {
			diag("unexpected relocation type %d", r->type);
			return;
		}
		break;

	// Handle relocations found in ELF object files.
	case 256 + R_X86_64_PC32:
148
		if(targ->dynimpname != nil && !targ->dynexport)
149 150 151 152 153 154 155 156 157 158
			diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
		if(targ->type == 0 || targ->type == SXREF)
			diag("unknown symbol %s in pcrel", targ->name);
		r->type = D_PCREL;
		r->add += 4;
		return;
	
	case 256 + R_X86_64_PLT32:
		r->type = D_PCREL;
		r->add += 4;
159
		if(targ->dynimpname != nil && !targ->dynexport) {
Russ Cox's avatar
Russ Cox committed
160 161 162 163
			addpltsym(targ);
			r->sym = lookup(".plt", 0);
			r->add += targ->plt;
		}
164 165 166
		return;
	
	case 256 + R_X86_64_GOTPCREL:
167
		if(targ->dynimpname == nil || targ->dynexport) {
Russ Cox's avatar
Russ Cox committed
168
			// have symbol
169 170 171 172 173
			if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
				// turn MOVQ of GOT entry into LEAQ of symbol itself
				s->p[r->off-2] = 0x8d;
				r->type = D_PCREL;
				r->add += 4;
Russ Cox's avatar
Russ Cox committed
174 175
				return;
			}
176 177
			// fall back to using GOT and hope for the best (CMOV*)
			// TODO: just needs relocation, no need to put in .dynsym
178
			targ->dynimpname = targ->name;
Russ Cox's avatar
Russ Cox committed
179
		}
180 181 182 183 184 185 186 187
		addgotsym(targ);
		r->type = D_PCREL;
		r->sym = lookup(".got", 0);
		r->add += 4;
		r->add += targ->got;
		return;
	
	case 256 + R_X86_64_64:
188
		if(targ->dynimpname != nil && !targ->dynexport)
189 190 191 192 193 194 195 196 197 198
			diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
		r->type = D_ADDR;
		return;
	
	// Handle relocations found in Mach-O object files.
	case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0:
	case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0:
	case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
		// TODO: What is the difference between all these?
		r->type = D_ADDR;
199
		if(targ->dynimpname != nil && !targ->dynexport)
200 201 202 203
			diag("unexpected reloc for dynamic symbol %s", targ->name);
		return;

	case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
204
		if(targ->dynimpname != nil && !targ->dynexport) {
205 206 207 208 209 210 211 212 213 214 215 216 217
			addpltsym(targ);
			r->sym = lookup(".plt", 0);
			r->add = targ->plt;
			r->type = D_PCREL;
			return;
		}
		// fall through
	case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1:
	case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1:
	case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1:
	case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
	case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
		r->type = D_PCREL;
218
		if(targ->dynimpname != nil && !targ->dynexport)
219 220 221 222
			diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
		return;

	case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
223
		if(targ->dynimpname == nil || targ->dynexport) {
Russ Cox's avatar
Russ Cox committed
224 225 226 227 228 229 230 231 232 233 234
			// have symbol
			// turn MOVQ of GOT entry into LEAQ of symbol itself
			if(r->off < 2 || s->p[r->off-2] != 0x8b) {
				diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name);
				return;
			}
			s->p[r->off-2] = 0x8d;
			r->type = D_PCREL;
			return;
		}
		// fall through
235
	case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
236
		if(targ->dynimpname == nil || targ->dynexport)
Russ Cox's avatar
Russ Cox committed
237
			diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
238 239 240 241 242 243 244 245
		addgotsym(targ);
		r->type = D_PCREL;
		r->sym = lookup(".got", 0);
		r->add += targ->got;
		return;
	}
	
	// Handle references to ELF symbols from our own object files.
246
	if(targ->dynimpname == nil || targ->dynexport)
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
		return;

	switch(r->type) {
	case D_PCREL:
		addpltsym(targ);
		r->sym = lookup(".plt", 0);
		r->add = targ->plt;
		return;
	
	case D_ADDR:
		if(s->type != SDATA)
			break;
		if(iself) {
			adddynsym(targ);
			rela = lookup(".rela", 0);
			addaddrplus(rela, s, r->off);
			if(r->siz == 8)
				adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
			else
				adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
			adduint64(rela, r->add);
			r->type = 256;	// ignore during relocsym
			return;
		}
271
		if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
			// Mach-O relocations are a royal pain to lay out.
			// They use a compact stateful bytecode representation
			// that is too much bother to deal with.
			// Instead, interpret the C declaration
			//	void *_Cvar_stderr = &stderr;
			// as making _Cvar_stderr the name of a GOT entry
			// for stderr.  This is separate from the usual GOT entry,
			// just in case the C code assigns to the variable,
			// and of course it only works for single pointers,
			// but we only need to support cgo and that's all it needs.
			adddynsym(targ);
			got = lookup(".got", 0);
			s->type = got->type | SSUB;
			s->outer = got;
			s->sub = got->sub;
			got->sub = s;
			s->value = got->size;
			adduint64(got, 0);
			adduint32(lookup(".linkedit.got", 0), targ->dynid);
			r->type = 256;	// ignore during relocsym
			return;
		}
		break;
	}
	
	cursym = s;
	diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}

int
archreloc(Reloc *r, Sym *s, vlong *val)
{
304 305 306
	USED(r);
	USED(s);
	USED(val);
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
	return -1;
}

static void
elfsetupplt(void)
{
	Sym *plt, *got;

	plt = lookup(".plt", 0);
	got = lookup(".got.plt", 0);
	if(plt->size == 0) {
		// pushq got+8(IP)
		adduint8(plt, 0xff);
		adduint8(plt, 0x35);
		addpcrelplus(plt, got, 8);
		
		// jmpq got+16(IP)
		adduint8(plt, 0xff);
		adduint8(plt, 0x25);
		addpcrelplus(plt, got, 16);
		
		// nopl 0(AX)
		adduint32(plt, 0x00401f0f);
		
		// assume got->size == 0 too
		addaddrplus(got, lookup(".dynamic", 0), 0);
		adduint64(got, 0);
		adduint64(got, 0);
	}
}

static void
addpltsym(Sym *s)
{
	if(s->plt >= 0)
		return;
	
	adddynsym(s);
	
	if(iself) {
		Sym *plt, *got, *rela;

		plt = lookup(".plt", 0);
		got = lookup(".got.plt", 0);
		rela = lookup(".rela.plt", 0);
		if(plt->size == 0)
			elfsetupplt();
		
		// jmpq *got+size(IP)
		adduint8(plt, 0xff);
		adduint8(plt, 0x25);
		addpcrelplus(plt, got, got->size);
	
		// add to got: pointer to current pos in plt
		addaddrplus(got, plt, plt->size);
		
		// pushq $x
		adduint8(plt, 0x68);
		adduint32(plt, (got->size-24-8)/8);
		
		// jmpq .plt
		adduint8(plt, 0xe9);
		adduint32(plt, -(plt->size+4));
		
		// rela
		addaddrplus(rela, got, got->size-8);
		adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
		adduint64(rela, 0);
		
		s->plt = plt->size - 16;
377
	} else if(HEADTYPE == Hdarwin) {
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
		// To do lazy symbol lookup right, we're supposed
		// to tell the dynamic loader which library each 
		// symbol comes from and format the link info
		// section just so.  I'm too lazy (ha!) to do that
		// so for now we'll just use non-lazy pointers,
		// which don't need to be told which library to use.
		//
		// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
		// has details about what we're avoiding.

		Sym *plt;
		
		addgotsym(s);
		plt = lookup(".plt", 0);

		adduint32(lookup(".linkedit.plt", 0), s->dynid);

		// jmpq *got+size(IP)
		s->plt = plt->size;

		adduint8(plt, 0xff);
		adduint8(plt, 0x25);
		addpcrelplus(plt, lookup(".got", 0), s->got);
	} else {
		diag("addpltsym: unsupported binary format");
	}
}

static void
addgotsym(Sym *s)
{
Russ Cox's avatar
Russ Cox committed
409
	Sym *got, *rela;
410 411 412 413 414 415 416 417 418 419 420 421 422 423

	if(s->got >= 0)
		return;

	adddynsym(s);
	got = lookup(".got", 0);
	s->got = got->size;
	adduint64(got, 0);

	if(iself) {
		rela = lookup(".rela", 0);
		addaddrplus(rela, got, s->got);
		adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
		adduint64(rela, 0);
424
	} else if(HEADTYPE == Hdarwin) {
425 426 427 428 429 430
		adduint32(lookup(".linkedit.got", 0), s->dynid);
	} else {
		diag("addgotsym: unsupported binary format");
	}
}

Russ Cox's avatar
Russ Cox committed
431
void
432 433 434 435 436 437 438 439 440
adddynsym(Sym *s)
{
	Sym *d, *str;
	int t;
	char *name;

	if(s->dynid >= 0)
		return;

Russ Cox's avatar
Russ Cox committed
441 442 443
	if(s->dynimpname == nil)
		diag("adddynsym: no dynamic name for %s", s->name);

444 445
	if(iself) {
		s->dynid = nelfsym++;
Russ Cox's avatar
Russ Cox committed
446

447
		d = lookup(".dynsym", 0);
Russ Cox's avatar
Russ Cox committed
448

449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
		name = s->dynimpname;
		if(name == nil)
			name = s->name;
		adduint32(d, addstring(lookup(".dynstr", 0), name));
		/* type */
		t = STB_GLOBAL << 4;
		if(s->dynexport && s->type == STEXT)
			t |= STT_FUNC;
		else
			t |= STT_OBJECT;
		adduint8(d, t);
	
		/* reserved */
		adduint8(d, 0);
	
		/* section where symbol is defined */
		if(!s->dynexport && s->dynimpname != nil)
			adduint16(d, SHN_UNDEF);
		else {
			switch(s->type) {
			default:
			case STEXT:
				t = 11;
				break;
			case SRODATA:
				t = 12;
				break;
			case SDATA:
				t = 13;
				break;
			case SBSS:
				t = 14;
				break;
			}
			adduint16(d, t);
		}
	
		/* value */
		if(s->type == SDYNIMPORT)
			adduint64(d, 0);
		else
			addaddr(d, s);
	
		/* size of object */
		adduint64(d, 0);
	
		if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) {
			elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
				addstring(lookup(".dynstr", 0), s->dynimplib));
		}
499
	} else if(HEADTYPE == Hdarwin) {
500 501 502 503 504 505 506 507 508 509 510
		// Mach-o symbol nlist64
		d = lookup(".dynsym", 0);
		name = s->dynimpname;
		if(name == nil)
			name = s->name;
		s->dynid = d->size/16;
		// darwin still puts _ prefixes on all C symbols
		str = lookup(".dynstr", 0);
		adduint32(d, str->size);
		adduint8(str, '_');
		addstring(str, name);
Russ Cox's avatar
Russ Cox committed
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
		if(s->type == SDYNIMPORT) {
			adduint8(d, 0x01);	// type - N_EXT - external symbol
			adduint8(d, 0);	// section
		} else {
			adduint8(d, 0x0f);
			switch(s->type) {
			default:
			case STEXT:
				adduint8(d, 1);
				break;
			case SDATA:
				adduint8(d, 2);
				break;
			case SBSS:
				adduint8(d, 4);
				break;
			}
		}
529
		adduint16(d, 0);	// desc
Russ Cox's avatar
Russ Cox committed
530 531 532 533
		if(s->type == SDYNIMPORT)
			adduint64(d, 0);	// value
		else
			addaddr(d, s);
Wei Guangjing's avatar
Wei Guangjing committed
534
	} else if(HEADTYPE != Hwindows) {
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
		diag("adddynsym: unsupported binary format");
	}
}

void
adddynlib(char *lib)
{
	Sym *s;
	
	if(!needlib(lib))
		return;
	
	if(iself) {
		s = lookup(".dynstr", 0);
		if(s->size == 0)
			addstring(s, "");
		elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
552
	} else if(HEADTYPE == Hdarwin) {
553 554 555 556 557 558
		machoadddynlib(lib);
	} else {
		diag("adddynlib: unsupported binary format");
	}
}

Ken Thompson's avatar
Ken Thompson committed
559 560 561
void
doelf(void)
{
562
	Sym *s, *shstrtab, *dynstr;
Ken Thompson's avatar
Ken Thompson committed
563

564
	if(HEADTYPE != Hlinux && HEADTYPE != Hfreebsd && HEADTYPE != Hopenbsd && HEADTYPE != Hnetbsd)
Ken Thompson's avatar
Ken Thompson committed
565 566 567 568
		return;

	/* predefine strings we need for section headers */
	shstrtab = lookup(".shstrtab", 0);
569
	shstrtab->type = SELFROSECT;
570 571
	shstrtab->reachable = 1;

Ken Thompson's avatar
Ken Thompson committed
572 573
	elfstr[ElfStrEmpty] = addstring(shstrtab, "");
	elfstr[ElfStrText] = addstring(shstrtab, ".text");
574
	elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
Ken Thompson's avatar
Ken Thompson committed
575 576
	elfstr[ElfStrData] = addstring(shstrtab, ".data");
	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
577
	elfstr[ElfStrNoPtrBss] = addstring(shstrtab, ".noptrbss");
578 579
	if(HEADTYPE == Hnetbsd)
		elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
580 581
	addstring(shstrtab, ".elfdata");
	addstring(shstrtab, ".rodata");
582 583
	addstring(shstrtab, ".gosymtab");
	addstring(shstrtab, ".gopclntab");
Ken Thompson's avatar
Ken Thompson committed
584
	if(!debug['s']) {
Russ Cox's avatar
tabs  
Russ Cox committed
585 586 587
		elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
		elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
		dwarfaddshstrings(shstrtab);
Ken Thompson's avatar
Ken Thompson committed
588 589 590 591 592 593 594 595 596 597 598 599
	}
	elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");

	if(!debug['d']) {	/* -d suppresses dynamic loader format */
		elfstr[ElfStrInterp] = addstring(shstrtab, ".interp");
		elfstr[ElfStrHash] = addstring(shstrtab, ".hash");
		elfstr[ElfStrGot] = addstring(shstrtab, ".got");
		elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt");
		elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic");
		elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
		elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
		elfstr[ElfStrRela] = addstring(shstrtab, ".rela");
600 601
		elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.plt");
		elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
Russ Cox's avatar
Russ Cox committed
602 603
		elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
		elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
Ken Thompson's avatar
Ken Thompson committed
604 605 606

		/* dynamic symbol table - first entry all zeros */
		s = lookup(".dynsym", 0);
607
		s->type = SELFROSECT;
Ken Thompson's avatar
Ken Thompson committed
608
		s->reachable = 1;
609
		s->size += ELF64SYMSIZE;
Ken Thompson's avatar
Ken Thompson committed
610 611 612

		/* dynamic string table */
		s = lookup(".dynstr", 0);
613
		s->type = SELFROSECT;
614
		s->reachable = 1;
615 616
		if(s->size == 0)
			addstring(s, "");
Ken Thompson's avatar
Ken Thompson committed
617 618 619 620 621
		dynstr = s;

		/* relocation table */
		s = lookup(".rela", 0);
		s->reachable = 1;
622
		s->type = SELFROSECT;
Ken Thompson's avatar
Ken Thompson committed
623 624 625 626

		/* global offset table */
		s = lookup(".got", 0);
		s->reachable = 1;
627
		s->type = SELFSECT; // writable
628 629 630 631

		/* hash */
		s = lookup(".hash", 0);
		s->reachable = 1;
632
		s->type = SELFROSECT;
Ken Thompson's avatar
Ken Thompson committed
633 634 635

		s = lookup(".got.plt", 0);
		s->reachable = 1;
636
		s->type = SELFSECT; // writable
637 638 639

		s = lookup(".plt", 0);
		s->reachable = 1;
640
		s->type = SELFROSECT;
641
		
642 643 644
		elfsetupplt();
		
		s = lookup(".rela.plt", 0);
645
		s->reachable = 1;
646
		s->type = SELFROSECT;
Russ Cox's avatar
Russ Cox committed
647 648 649
		
		s = lookup(".gnu.version", 0);
		s->reachable = 1;
650
		s->type = SELFROSECT;
Russ Cox's avatar
Russ Cox committed
651 652 653
		
		s = lookup(".gnu.version_r", 0);
		s->reachable = 1;
654
		s->type = SELFROSECT;
Ken Thompson's avatar
Ken Thompson committed
655 656 657

		/* define dynamic elf table */
		s = lookup(".dynamic", 0);
658
		s->reachable = 1;
659
		s->type = SELFSECT; // writable
660

Ken Thompson's avatar
Ken Thompson committed
661 662 663 664 665 666 667 668 669 670 671
		/*
		 * .dynamic table
		 */
		elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
		elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
		elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
		elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
		elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
		elfwritedynentsym(s, DT_RELA, lookup(".rela", 0));
		elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0));
		elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
672 673
		if(rpath)
			elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
674 675 676 677 678
		
		elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
		elfwritedynent(s, DT_PLTREL, DT_RELA);
		elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
		elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
Russ Cox's avatar
Russ Cox committed
679
		
680 681
		elfwritedynent(s, DT_DEBUG, 0);

Russ Cox's avatar
Russ Cox committed
682
		// Do not write DT_NULL.  elfdynhash will finish it.
Ken Thompson's avatar
Ken Thompson committed
683 684 685 686 687 688
	}
}

void
shsym(ElfShdr *sh, Sym *s)
{
689 690 691 692 693
	vlong addr;
	addr = symaddr(s);
	if(sh->flags&SHF_ALLOC)
		sh->addr = addr;
	sh->off = datoff(addr);
Ken Thompson's avatar
Ken Thompson committed
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
	sh->size = s->size;
}

void
phsh(ElfPhdr *ph, ElfShdr *sh)
{
	ph->vaddr = sh->addr;
	ph->paddr = ph->vaddr;
	ph->off = sh->off;
	ph->filesz = sh->size;
	ph->memsz = sh->size;
	ph->align = sh->addralign;
}

void
asmb(void)
{
711
	int32 magic;
Ken Thompson's avatar
Ken Thompson committed
712
	int a, dynsym;
713
	vlong vl, startva, symo, dwarfoff, machlink, resoff;
Ken Thompson's avatar
Ken Thompson committed
714 715 716
	ElfEhdr *eh;
	ElfPhdr *ph, *pph;
	ElfShdr *sh;
717
	Section *sect;
718
	int o;
Ken Thompson's avatar
Ken Thompson committed
719 720 721 722 723 724

	if(debug['v'])
		Bprint(&bso, "%5.2f asmb\n", cputime());
	Bflush(&bso);

	elftextsh = 0;
725 726 727 728 729 730
	
	if(debug['v'])
		Bprint(&bso, "%5.2f codeblk\n", cputime());
	Bflush(&bso);

	sect = segtext.sect;
731
	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
732
	codeblk(sect->vaddr, sect->len);
Ken Thompson's avatar
Ken Thompson committed
733

734 735
	/* output read-only data in text segment (rodata, gosymtab and pclntab) */
	for(sect = sect->next; sect != nil; sect = sect->next) {
736
		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
737 738
		datblk(sect->vaddr, sect->len);
	}
739 740 741 742 743

	if(debug['v'])
		Bprint(&bso, "%5.2f datblk\n", cputime());
	Bflush(&bso);

744
	cseek(segdata.fileoff);
745 746 747
	datblk(segdata.vaddr, segdata.filelen);

	machlink = 0;
748 749 750 751 752 753 754 755 756 757 758
	if(HEADTYPE == Hdarwin) {
		if(debug['v'])
			Bprint(&bso, "%5.2f dwarf\n", cputime());

		dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
		cseek(dwarfoff);

		segdwarf.fileoff = cpos();
		dwarfemitdebugsections();
		segdwarf.filelen = cpos() - segdwarf.fileoff;

759
		machlink = domacholink();
760
	}
Ken Thompson's avatar
Ken Thompson committed
761 762 763

	switch(HEADTYPE) {
	default:
Russ Cox's avatar
Russ Cox committed
764
		diag("unknown header type %d", HEADTYPE);
765 766
	case Hplan9x32:
	case Helf:
Ken Thompson's avatar
Ken Thompson committed
767
		break;
768
	case Hdarwin:
Ken Thompson's avatar
Ken Thompson committed
769 770
		debug['8'] = 1;	/* 64-bit addresses */
		break;
771 772
	case Hlinux:
	case Hfreebsd:
773
	case Hnetbsd:
Joel Sing's avatar
Joel Sing committed
774
	case Hopenbsd:
Ken Thompson's avatar
Ken Thompson committed
775 776
		debug['8'] = 1;	/* 64-bit addresses */
		/* index of elf text section; needed by asmelfsym, double-checked below */
777
		/* !debug['d'] causes extra sections before the .text section */
778
		elftextsh = 2;
Russ Cox's avatar
Russ Cox committed
779
		if(!debug['d']) {
780
			elftextsh += 10;
Russ Cox's avatar
Russ Cox committed
781 782 783
			if(elfverneed)
				elftextsh += 2;
		}
784 785
		if(HEADTYPE == Hnetbsd)
			elftextsh += 1;
Ken Thompson's avatar
Ken Thompson committed
786
		break;
787
	case Hwindows:
Wei Guangjing's avatar
Wei Guangjing committed
788
		break;
Ken Thompson's avatar
Ken Thompson committed
789 790 791 792 793 794 795 796 797 798 799 800
	}

	symsize = 0;
	spsize = 0;
	lcsize = 0;
	symo = 0;
	if(!debug['s']) {
		if(debug['v'])
			Bprint(&bso, "%5.2f sym\n", cputime());
		Bflush(&bso);
		switch(HEADTYPE) {
		default:
801 802
		case Hplan9x32:
		case Helf:
Ken Thompson's avatar
Ken Thompson committed
803
			debug['s'] = 1;
804
			symo = HEADR+segtext.len+segdata.filelen;
Ken Thompson's avatar
Ken Thompson committed
805
			break;
806
		case Hdarwin:
807
			symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
Ken Thompson's avatar
Ken Thompson committed
808
			break;
809 810
		case Hlinux:
		case Hfreebsd:
811
		case Hnetbsd:
Joel Sing's avatar
Joel Sing committed
812
		case Hopenbsd:
813
			symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen;
Ken Thompson's avatar
Ken Thompson committed
814 815
			symo = rnd(symo, INITRND);
			break;
816
		case Hwindows:
Wei Guangjing's avatar
Wei Guangjing committed
817 818 819
			symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
			symo = rnd(symo, PEFILEALIGN);
			break;
Ken Thompson's avatar
Ken Thompson committed
820
		}
821
		cseek(symo);
822 823 824
		switch(HEADTYPE) {
		default:
			if(iself) {
825
				cseek(symo);
826
				asmelfsym();
827
				cflush();
828
				cwrite(elfstrdat, elfstrsize);
829 830 831 832 833 834 835 836

				if(debug['v'])
				       Bprint(&bso, "%5.2f dwarf\n", cputime());

				dwarfemitdebugsections();
			}
			break;
		case Hwindows:
Russ Cox's avatar
tabs  
Russ Cox committed
837 838
			if(debug['v'])
			       Bprint(&bso, "%5.2f dwarf\n", cputime());
Luuk van Dijk's avatar
Luuk van Dijk committed
839

Russ Cox's avatar
tabs  
Russ Cox committed
840
			dwarfemitdebugsections();
841
			break;
Luuk van Dijk's avatar
Luuk van Dijk committed
842
		}
Ken Thompson's avatar
Ken Thompson committed
843 844 845 846 847
	}

	if(debug['v'])
		Bprint(&bso, "%5.2f headr\n", cputime());
	Bflush(&bso);
848
	cseek(0L);
Ken Thompson's avatar
Ken Thompson committed
849 850
	switch(HEADTYPE) {
	default:
851
	case Hplan9x32:	/* plan9 */
Ken Thompson's avatar
Ken Thompson committed
852 853 854
		magic = 4*26*26+7;
		magic |= 0x00008000;		/* fat header */
		lputb(magic);			/* magic */
855
		lputb(segtext.filelen);			/* sizes */
856 857
		lputb(segdata.filelen);
		lputb(segdata.len - segdata.filelen);
Ken Thompson's avatar
Ken Thompson committed
858 859 860 861 862 863 864
		lputb(symsize);			/* nsyms */
		vl = entryvalue();
		lputb(PADDR(vl));		/* va of entry */
		lputb(spsize);			/* sp offsets */
		lputb(lcsize);			/* line offsets */
		vputb(vl);			/* va of entry */
		break;
865
	case Hplan9x64:	/* plan9 */
Ken Thompson's avatar
Ken Thompson committed
866 867
		magic = 4*26*26+7;
		lputb(magic);			/* magic */
868
		lputb(segtext.filelen);		/* sizes */
869 870
		lputb(segdata.filelen);
		lputb(segdata.len - segdata.filelen);
Ken Thompson's avatar
Ken Thompson committed
871 872 873 874 875
		lputb(symsize);			/* nsyms */
		lputb(entryvalue());		/* va of entry */
		lputb(spsize);			/* sp offsets */
		lputb(lcsize);			/* line offsets */
		break;
876
	case Hdarwin:
877
		asmbmacho();
Ken Thompson's avatar
Ken Thompson committed
878
		break;
879 880
	case Hlinux:
	case Hfreebsd:
881
	case Hnetbsd:
Joel Sing's avatar
Joel Sing committed
882
	case Hopenbsd:
Ken Thompson's avatar
Ken Thompson committed
883 884 885 886
		/* elf amd-64 */

		eh = getElfEhdr();
		startva = INITTEXT - HEADR;
887
		resoff = ELFRESERVE;
Ken Thompson's avatar
Ken Thompson committed
888 889

		/* This null SHdr must appear before all others */
890
		newElfShdr(elfstr[ElfStrEmpty]);
Ken Thompson's avatar
Ken Thompson committed
891 892 893 894 895 896 897 898 899 900

		/* program header info */
		pph = newElfPhdr();
		pph->type = PT_PHDR;
		pph->flags = PF_R + PF_X;
		pph->off = eh->ehsize;
		pph->vaddr = INITTEXT - HEADR + pph->off;
		pph->paddr = INITTEXT - HEADR + pph->off;
		pph->align = INITRND;

901 902 903 904 905 906 907 908 909 910 911
		/*
		 * PHDR must be in a loaded segment. Adjust the text
		 * segment boundaries downwards to include it.
		 */
		o = segtext.vaddr - pph->vaddr;
		segtext.vaddr -= o;
		segtext.len += o;
		o = segtext.fileoff - pph->off;
		segtext.fileoff -= o;
		segtext.filelen += o;

Ken Thompson's avatar
Ken Thompson committed
912 913 914 915 916 917
		if(!debug['d']) {
			/* interpreter */
			sh = newElfShdr(elfstr[ElfStrInterp]);
			sh->type = SHT_PROGBITS;
			sh->flags = SHF_ALLOC;
			sh->addralign = 1;
918 919
			if(interpreter == nil) {
				switch(HEADTYPE) {
920
				case Hlinux:
921 922
					interpreter = linuxdynld;
					break;
923
				case Hfreebsd:
924 925
					interpreter = freebsddynld;
					break;
926 927 928
				case Hnetbsd:
					interpreter = netbsddynld;
					break;
Joel Sing's avatar
Joel Sing committed
929 930 931
				case Hopenbsd:
					interpreter = openbsddynld;
					break;
932
				}
933
			}
934
			resoff -= elfinterp(sh, startva, resoff, interpreter);
Ken Thompson's avatar
Ken Thompson committed
935 936 937 938 939 940 941

			ph = newElfPhdr();
			ph->type = PT_INTERP;
			ph->flags = PF_R;
			phsh(ph, sh);
		}

942 943 944 945 946 947 948 949 950 951 952 953 954
		if(HEADTYPE == Hnetbsd) {
			sh = newElfShdr(elfstr[ElfStrNoteNetbsdIdent]);
			sh->type = SHT_NOTE;
			sh->flags = SHF_ALLOC;
			sh->addralign = 4;
			resoff -= elfnetbsdsig(sh, startva, resoff);

			ph = newElfPhdr();
			ph->type = PT_NOTE;
			ph->flags = PF_R;
			phsh(ph, sh);
		}

955 956
		elfphload(&segtext);
		elfphload(&segdata);
Ken Thompson's avatar
Ken Thompson committed
957 958

		/* Dynamic linking sections */
959
		if(!debug['d']) {	/* -d suppresses dynamic loader format */
Ken Thompson's avatar
Ken Thompson committed
960 961 962 963 964 965 966 967 968 969 970 971 972 973
			/* S headers for dynamic linking */
			sh = newElfShdr(elfstr[ElfStrGot]);
			sh->type = SHT_PROGBITS;
			sh->flags = SHF_ALLOC+SHF_WRITE;
			sh->entsize = 8;
			sh->addralign = 8;
			shsym(sh, lookup(".got", 0));

			sh = newElfShdr(elfstr[ElfStrGotPlt]);
			sh->type = SHT_PROGBITS;
			sh->flags = SHF_ALLOC+SHF_WRITE;
			sh->entsize = 8;
			sh->addralign = 8;
			shsym(sh, lookup(".got.plt", 0));
974
			
Ken Thompson's avatar
Ken Thompson committed
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
			dynsym = eh->shnum;
			sh = newElfShdr(elfstr[ElfStrDynsym]);
			sh->type = SHT_DYNSYM;
			sh->flags = SHF_ALLOC;
			sh->entsize = ELF64SYMSIZE;
			sh->addralign = 8;
			sh->link = dynsym+1;	// dynstr
			// sh->info = index of first non-local symbol (number of local symbols)
			shsym(sh, lookup(".dynsym", 0));

			sh = newElfShdr(elfstr[ElfStrDynstr]);
			sh->type = SHT_STRTAB;
			sh->flags = SHF_ALLOC;
			sh->addralign = 1;
			shsym(sh, lookup(".dynstr", 0));

Russ Cox's avatar
Russ Cox committed
991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
			if(elfverneed) {
				sh = newElfShdr(elfstr[ElfStrGnuVersion]);
				sh->type = SHT_GNU_VERSYM;
				sh->flags = SHF_ALLOC;
				sh->addralign = 2;
				sh->link = dynsym;
				sh->entsize = 2;
				shsym(sh, lookup(".gnu.version", 0));
				
				sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
				sh->type = SHT_GNU_VERNEED;
				sh->flags = SHF_ALLOC;
				sh->addralign = 8;
				sh->info = elfverneed;
				sh->link = dynsym+1;  // dynstr
				shsym(sh, lookup(".gnu.version_r", 0));
			}

1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
			sh = newElfShdr(elfstr[ElfStrRelaPlt]);
			sh->type = SHT_RELA;
			sh->flags = SHF_ALLOC;
			sh->entsize = ELF64RELASIZE;
			sh->addralign = 8;
			sh->link = dynsym;
			sh->info = eh->shnum;	// .plt
			shsym(sh, lookup(".rela.plt", 0));

			sh = newElfShdr(elfstr[ElfStrPlt]);
			sh->type = SHT_PROGBITS;
			sh->flags = SHF_ALLOC+SHF_EXECINSTR;
			sh->entsize = 16;
			sh->addralign = 4;
			shsym(sh, lookup(".plt", 0));

Ken Thompson's avatar
Ken Thompson committed
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
			sh = newElfShdr(elfstr[ElfStrHash]);
			sh->type = SHT_HASH;
			sh->flags = SHF_ALLOC;
			sh->entsize = 4;
			sh->addralign = 8;
			sh->link = dynsym;
			shsym(sh, lookup(".hash", 0));

			sh = newElfShdr(elfstr[ElfStrRela]);
			sh->type = SHT_RELA;
			sh->flags = SHF_ALLOC;
			sh->entsize = ELF64RELASIZE;
			sh->addralign = 8;
			sh->link = dynsym;
			shsym(sh, lookup(".rela", 0));

			/* sh and PT_DYNAMIC for .dynamic section */
			sh = newElfShdr(elfstr[ElfStrDynamic]);
			sh->type = SHT_DYNAMIC;
			sh->flags = SHF_ALLOC+SHF_WRITE;
			sh->entsize = 16;
			sh->addralign = 8;
			sh->link = dynsym+1;	// dynstr
			shsym(sh, lookup(".dynamic", 0));
			ph = newElfPhdr();
			ph->type = PT_DYNAMIC;
			ph->flags = PF_R + PF_W;
			phsh(ph, sh);
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
			
			/*
			 * Thread-local storage segment (really just size).
			 */
			if(tlsoffset != 0) {
				ph = newElfPhdr();
				ph->type = PT_TLS;
				ph->flags = PF_R;
				ph->memsz = -tlsoffset;
				ph->align = 8;
			}
Ken Thompson's avatar
Ken Thompson committed
1064 1065 1066 1067 1068 1069 1070
		}

		ph = newElfPhdr();
		ph->type = PT_GNU_STACK;
		ph->flags = PF_W+PF_R;
		ph->align = 8;

1071 1072 1073 1074 1075
		sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
		sh->type = SHT_STRTAB;
		sh->addralign = 1;
		shsym(sh, lookup(".shstrtab", 0));

Ken Thompson's avatar
Ken Thompson committed
1076 1077
		if(elftextsh != eh->shnum)
			diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
1078 1079 1080 1081
		for(sect=segtext.sect; sect!=nil; sect=sect->next)
			elfshbits(sect);
		for(sect=segdata.sect; sect!=nil; sect=sect->next)
			elfshbits(sect);
Ken Thompson's avatar
Ken Thompson committed
1082

1083
		if(!debug['s']) {
Russ Cox's avatar
tabs  
Russ Cox committed
1084 1085
			sh = newElfShdr(elfstr[ElfStrSymtab]);
			sh->type = SHT_SYMTAB;
1086 1087
			sh->off = symo;
			sh->size = symsize;
Russ Cox's avatar
tabs  
Russ Cox committed
1088 1089 1090 1091 1092 1093
			sh->addralign = 8;
			sh->entsize = 24;
			sh->link = eh->shnum;	// link to strtab

			sh = newElfShdr(elfstr[ElfStrStrtab]);
			sh->type = SHT_STRTAB;
1094
			sh->off = symo+symsize;
Russ Cox's avatar
tabs  
Russ Cox committed
1095 1096 1097 1098
			sh->size = elfstrsize;
			sh->addralign = 1;

			dwarfaddelfheaders();
Ken Thompson's avatar
Ken Thompson committed
1099 1100 1101 1102 1103 1104 1105
		}

		/* Main header */
		eh->ident[EI_MAG0] = '\177';
		eh->ident[EI_MAG1] = 'E';
		eh->ident[EI_MAG2] = 'L';
		eh->ident[EI_MAG3] = 'F';
1106
		if(HEADTYPE == Hfreebsd)
Joel Sing's avatar
Joel Sing committed
1107
			eh->ident[EI_OSABI] = ELFOSABI_FREEBSD;
1108 1109
		else if(HEADTYPE == Hnetbsd)
			eh->ident[EI_OSABI] = ELFOSABI_NETBSD;
Joel Sing's avatar
Joel Sing committed
1110 1111
		else if(HEADTYPE == Hopenbsd)
			eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
Ken Thompson's avatar
Ken Thompson committed
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
		eh->ident[EI_CLASS] = ELFCLASS64;
		eh->ident[EI_DATA] = ELFDATA2LSB;
		eh->ident[EI_VERSION] = EV_CURRENT;

		eh->type = ET_EXEC;
		eh->machine = EM_X86_64;
		eh->version = EV_CURRENT;
		eh->entry = entryvalue();

		pph->filesz = eh->phnum * eh->phentsize;
		pph->memsz = pph->filesz;

1124
		cseek(0);
Ken Thompson's avatar
Ken Thompson committed
1125 1126 1127 1128
		a = 0;
		a += elfwritehdr();
		a += elfwritephdrs();
		a += elfwriteshdrs();
1129 1130 1131
		a += elfwriteinterp(elfstr[ElfStrInterp]);
		if(HEADTYPE == Hnetbsd)
			a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
1132
		if(a > ELFRESERVE)	
Ken Thompson's avatar
Ken Thompson committed
1133 1134
			diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
		break;
1135
	case Hwindows:
Wei Guangjing's avatar
Wei Guangjing committed
1136 1137
		asmbpe();
		break;
Ken Thompson's avatar
Ken Thompson committed
1138 1139 1140 1141
	}
	cflush();
}

1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
vlong
rnd(vlong v, vlong r)
{
	vlong c;

	if(r <= 0)
		return v;
	v += r - 1;
	c = v % r;
	if(c < 0)
		c += r;
	v -= c;
	return v;
}
1156 1157 1158 1159 1160 1161 1162

void
genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
{
	Auto *a;
	Sym *s;

1163 1164 1165 1166
	s = lookup("etext", 0);
	if(s->type == STEXT)
		put(s, s->name, 'T', s->value, s->size, s->version, 0);

Russ Cox's avatar
Russ Cox committed
1167 1168 1169
	for(s=allsym; s!=S; s=s->allsym) {
		if(s->hide)
			continue;
1170
		switch(s->type&SMASK) {
Russ Cox's avatar
Russ Cox committed
1171 1172
		case SCONST:
		case SRODATA:
1173 1174
		case SSYMTAB:
		case SPCLNTAB:
Russ Cox's avatar
Russ Cox committed
1175
		case SDATA:
1176
		case SNOPTRDATA:
1177
		case SELFROSECT:
Russ Cox's avatar
Russ Cox committed
1178 1179 1180 1181 1182 1183
		case SMACHOGOT:
		case STYPE:
		case SSTRING:
		case SGOSTRING:
		case SWINDOWS:
			if(!s->reachable)
1184
				continue;
Russ Cox's avatar
Russ Cox committed
1185 1186
			put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
			continue;
1187

Russ Cox's avatar
Russ Cox committed
1188
		case SBSS:
1189
		case SNOPTRBSS:
Russ Cox's avatar
Russ Cox committed
1190
			if(!s->reachable)
1191
				continue;
1192 1193
			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);
Russ Cox's avatar
Russ Cox committed
1194 1195
			put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
			continue;
1196

Russ Cox's avatar
Russ Cox committed
1197 1198 1199
		case SFILE:
			put(nil, s->name, 'f', s->value, 0, s->version, 0);
			continue;
1200 1201 1202 1203
		}
	}

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

1207 1208 1209 1210 1211 1212 1213 1214
		/* 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);

1215
		put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230

		/* frame, auto and param after */
		put(nil, ".frame", 'm', s->text->to.offset+8, 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);
}