Example #1
0
void
elfsetupplt(void)
{
	Sym *plt, *got;
	
	plt = lookup(".plt", 0);
	got = lookup(".got.plt", 0);
	if(plt->size == 0) {
		// pushl got+4
		adduint8(plt, 0xff);
		adduint8(plt, 0x35);
		addaddrplus(plt, got, 4);
		
		// jmp *got+8
		adduint8(plt, 0xff);
		adduint8(plt, 0x25);
		addaddrplus(plt, got, 8);

		// zero pad
		adduint32(plt, 0);
		
		// assume got->size == 0 too
		addaddrplus(got, lookup(".dynamic", 0), 0);
		adduint32(got, 0);
		adduint32(got, 0);
	}
}
Example #2
0
void
addstrdata(char *name, char *value)
{
	LSym *s, *sp;
	char *p;
	uchar reachable;

	p = smprint("%s.str", name);
	sp = linklookup(ctxt, p, 0);
	free(p);
	addstring(sp, value);
	sp->type = SRODATA;

	s = linklookup(ctxt, name, 0);
	s->size = 0;
	s->dupok = 1;
	reachable = s->reachable;
	addaddr(ctxt, s, sp);
	adduint32(ctxt, s, strlen(value));
	if(PtrSize == 8)
		adduint32(ctxt, s, 0);  // round struct to pointer width

	// addstring, addaddr, etc., mark the symbols as reachable.
	// In this case that is not necessarily true, so stick to what
	// we know before entering this function.
	s->reachable = reachable;
	sp->reachable = reachable;
}
Example #3
0
static void
addpltsym(Sym *s)
{
	Sym *plt, *got, *rel;
	
	if(s->plt >= 0)
		return;

	adddynsym(s);
	
	if(iself) {
		plt = lookup(".plt", 0);
		got = lookup(".got.plt", 0);
		rel = lookup(".rel.plt", 0);
		if(plt->size == 0)
			elfsetupplt();
		
		// jmpq *got+size
		adduint8(plt, 0xff);
		adduint8(plt, 0x25);
		addaddrplus(plt, got, got->size);
		
		// add to got: pointer to current pos in plt
		addaddrplus(got, plt, plt->size);
		
		// pushl $x
		adduint8(plt, 0x68);
		adduint32(plt, rel->size);
		
		// jmp .plt
		adduint8(plt, 0xe9);
		adduint32(plt, -(plt->size+4));
		
		// rel
		addaddrplus(rel, got, got->size-4);
		adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
		
		s->plt = plt->size - 16;
	} else if(HEADTYPE == Hdarwin) {
		// Same laziness as in 6l.
		
		Sym *plt;

		plt = lookup(".plt", 0);

		addgotsym(s);

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

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

		adduint8(plt, 0xff);
		adduint8(plt, 0x25);
		addaddrplus(plt, lookup(".got", 0), s->got);
	} else {
		diag("addpltsym: unsupported binary format");
	}
}
Example #4
0
void
elfwritedynent(Sym *s, int tag, uint64 val)
{
	if(elf64) {
		adduint64(s, tag);
		adduint64(s, val);
	} else {
		adduint32(s, tag);
		adduint32(s, val);
	}
}
Example #5
0
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);
	}
}
Example #6
0
File: elf.c Project: rosrad/go-rep
void
elfwritedynentsymsize(LSym *s, int tag, LSym *t)
{
	if(elf64)
		adduint64(ctxt, s, tag);
	else
		adduint32(ctxt, s, tag);
	addsize(ctxt, s, t);
}
Example #7
0
void
elfwritedynentsymsize(Sym *s, int tag, Sym *t)
{
	if(elf64)
		adduint64(s, tag);
	else
		adduint32(s, tag);
	addsize(s, t);
}
Example #8
0
File: data.c Project: pipul/lab
void
addstrdata(char *name, char *value)
{
	Sym *s, *sp;
	char *p;
	
	p = smprint("%s.str", name);
	sp = lookup(p, 0);
	free(p);
	addstring(sp, value);

	s = lookup(name, 0);
	s->dupok = 1;
	addaddr(s, sp);
	adduint32(s, strlen(value));
	if(PtrSize == 8)
		adduint32(s, 0);  // round struct to pointer width
}
Example #9
0
File: asm.c Project: 8l/go
void
adddynsym(Link *ctxt, LSym *s)
{
	LSym *d;
	int t;
	char *name;

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

	if(iself) {
		s->dynid = nelfsym++;

		d = linklookup(ctxt, ".dynsym", 0);

		name = s->extname;
		adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
		/* type */
		t = STB_GLOBAL << 4;
		if(s->cgoexport && (s->type&SMASK) == STEXT)
			t |= STT_FUNC;
		else
			t |= STT_OBJECT;
		adduint8(ctxt, d, t);
	
		/* reserved */
		adduint8(ctxt, d, 0);
	
		/* section where symbol is defined */
		if(s->type == SDYNIMPORT)
			adduint16(ctxt, d, SHN_UNDEF);
		else
			adduint16(ctxt, d, 1);
	
		/* value */
		if(s->type == SDYNIMPORT)
			adduint64(ctxt, d, 0);
		else
			addaddr(ctxt, d, s);
	
		/* size of object */
		adduint64(ctxt, d, s->size);
	
		if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) {
			elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED,
				addstring(linklookup(ctxt, ".dynstr", 0), s->dynimplib));
		}
	} else if(HEADTYPE == Hdarwin) {
		diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
	} else if(HEADTYPE == Hwindows) {
		// already taken care of
	} else {
		diag("adddynsym: unsupported binary format");
	}
}
Example #10
0
File: data.c Project: hfeeki/golang
void
addstrdata(char *name, char *value)
{
	Sym *s, *sp;
	char *p;

	p = smprint("%s.str", name);
	sp = lookup(p, 0);
	free(p);
	addstring(sp, value);

	s = lookup(name, 0);
	s->size = 0;
	s->dupok = 1;
	addaddr(s, sp);
	adduint32(s, strlen(value));
	if(PtrSize == 8)
		adduint32(s, 0);  // round struct to pointer width

	// in case reachability has already been computed
	sp->reachable = s->reachable;
}
Example #11
0
static void
addgotsym(Sym *s)
{
	Sym *got, *rel;
	
	if(s->got >= 0)
		return;
	
	adddynsym(s);
	got = lookup(".got", 0);
	s->got = got->size;
	adduint32(got, 0);
	
	if(iself) {
		rel = lookup(".rel", 0);
		addaddrplus(rel, got, s->got);
		adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
	} else if(HEADTYPE == Hdarwin) {
		adduint32(lookup(".linkedit.got", 0), s->dynid);
	} else {
		diag("addgotsym: unsupported binary format");
	}
}
Example #12
0
static void
addgotsym(LSym *s)
{
	LSym *got, *rela;

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

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

	if(iself) {
		rela = linklookup(ctxt, ".rela", 0);
		addaddrplus(ctxt, rela, got, s->got);
		adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
		adduint64(ctxt, rela, 0);
	} else if(HEADTYPE == Hdarwin) {
		adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
	} else {
		diag("addgotsym: unsupported binary format");
	}
}
Example #13
0
void
adddynrel(Sym *s, Reloc *r)
{
	Sym *targ, *rel, *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_386_PC32:
		if(targ->type == SDYNIMPORT)
			diag("unexpected R_386_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_386_PLT32:
		r->type = D_PCREL;
		r->add += 4;
		if(targ->type == SDYNIMPORT) {
			addpltsym(targ);
			r->sym = lookup(".plt", 0);
			r->add += targ->plt;
		}
		return;		
	
	case 256 + R_386_GOT32:
		if(targ->type != SDYNIMPORT) {
			// have symbol
			// turn MOVL of GOT entry into LEAL of symbol itself
			if(r->off < 2 || s->p[r->off-2] != 0x8b) {
				diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
				return;
			}
			s->p[r->off-2] = 0x8d;
			r->type = D_GOTOFF;
			return;
		}
		addgotsym(targ);
		r->type = D_CONST;	// write r->add during relocsym
		r->sym = S;
		r->add += targ->got;
		return;
	
	case 256 + R_386_GOTOFF:
		r->type = D_GOTOFF;
		return;
	
	case 256 + R_386_GOTPC:
		r->type = D_PCREL;
		r->sym = lookup(".got", 0);
		r->add += 4;
		return;

	case 256 + R_386_32:
		if(targ->type == SDYNIMPORT)
			diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
		r->type = D_ADDR;
		return;
	
	case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
		r->type = D_ADDR;
		if(targ->type == SDYNIMPORT)
			diag("unexpected reloc for dynamic symbol %s", targ->name);
		return;
	
	case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
		if(targ->type == SDYNIMPORT) {
			addpltsym(targ);
			r->sym = lookup(".plt", 0);
			r->add = targ->plt;
			r->type = D_PCREL;
			return;
		}
		r->type = D_PCREL;
		return;
	
	case 512 + MACHO_FAKE_GOTPCREL:
		if(targ->type != SDYNIMPORT) {
			// have symbol
			// turn MOVL of GOT entry into LEAL of symbol itself
			if(r->off < 2 || s->p[r->off-2] != 0x8b) {
				diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
				return;
			}
			s->p[r->off-2] = 0x8d;
			r->type = D_PCREL;
			return;
		}
		addgotsym(targ);
		r->sym = lookup(".got", 0);
		r->add += targ->got;
		r->type = D_PCREL;
		return;
	}
	
	// Handle references to ELF symbols from our own object files.
	if(targ->type != SDYNIMPORT)
		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);
			rel = lookup(".rel", 0);
			addaddrplus(rel, s, r->off);
			adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32));
			r->type = D_CONST;	// write r->add during relocsym
			r->sym = S;
			return;
		}
		if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
			// 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;
			adduint32(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);
}
Example #14
0
void
elfdynhash(void)
{
	Sym *s, *sy, *dynstr;
	int i, j, nbucket, b, nfile;
	uint32 hc, *chain, *buckets;
	int nsym;
	char *name;
	Elfaux **need;
	Elflib *needlib;
	Elflib *l;
	Elfaux *x;
	
	if(!iself)
		return;

	nsym = nelfsym;
	s = lookup(".hash", 0);
	s->type = SELFROSECT;
	s->reachable = 1;

	i = nsym;
	nbucket = 1;
	while(i > 0) {
		++nbucket;
		i >>= 1;
	}

	needlib = nil;
	need = malloc(nsym * sizeof need[0]);
	chain = malloc(nsym * sizeof chain[0]);
	buckets = malloc(nbucket * sizeof buckets[0]);
	if(need == nil || chain == nil || buckets == nil) {
		cursym = nil;
		diag("out of memory");
		errorexit();
	}
	memset(need, 0, nsym * sizeof need[0]);
	memset(chain, 0, nsym * sizeof chain[0]);
	memset(buckets, 0, nbucket * sizeof buckets[0]);
	for(sy=allsym; sy!=S; sy=sy->allsym) {
		if (sy->dynid <= 0)
			continue;

		if(sy->dynimpvers)
			need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers);

		name = sy->dynimpname;
		if(name == nil)
			name = sy->name;
		hc = elfhash((uchar*)name);

		b = hc % nbucket;
		chain[sy->dynid] = buckets[b];
		buckets[b] = sy->dynid;
	}

	adduint32(s, nbucket);
	adduint32(s, nsym);
	for(i = 0; i<nbucket; i++)
		adduint32(s, buckets[i]);
	for(i = 0; i<nsym; i++)
		adduint32(s, chain[i]);

	free(chain);
	free(buckets);
	
	// version symbols
	dynstr = lookup(".dynstr", 0);
	s = lookup(".gnu.version_r", 0);
	i = 2;
	nfile = 0;
	for(l=needlib; l; l=l->next) {
		nfile++;
		// header
		adduint16(s, 1);  // table version
		j = 0;
		for(x=l->aux; x; x=x->next)
			j++;
		adduint16(s, j);	// aux count
		adduint32(s, addstring(dynstr, l->file));  // file string offset
		adduint32(s, 16);  // offset from header to first aux
		if(l->next)
			adduint32(s, 16+j*16);  // offset from this header to next
		else
			adduint32(s, 0);
		
		for(x=l->aux; x; x=x->next) {
			x->num = i++;
			// aux struct
			adduint32(s, elfhash((uchar*)x->vers));  // hash
			adduint16(s, 0);  // flags
			adduint16(s, x->num);  // other - index we refer to this by
			adduint32(s, addstring(dynstr, x->vers));  // version string offset
			if(x->next)
				adduint32(s, 16);  // offset from this aux to next
			else
				adduint32(s, 0);
		}
	}

	// version references
	s = lookup(".gnu.version", 0);
	for(i=0; i<nsym; i++) {
		if(i == 0)
			adduint16(s, 0); // first entry - no symbol
		else if(need[i] == nil)
			adduint16(s, 1); // global
		else
			adduint16(s, need[i]->num);
	}

	free(need);

	s = lookup(".dynamic", 0);
	elfverneed = nfile;
	if(elfverneed) {
		elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0));
		elfwritedynent(s, DT_VERNEEDNUM, nfile);
		elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0));
	}
	elfwritedynent(s, DT_NULL, 0);
}
Example #15
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;
	} else if(HEADTYPE == Hdarwin) {
		// 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");
	}
}
Example #16
0
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:
		if(targ->dynimpname != nil && !targ->dynexport)
			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;
		if(targ->dynimpname != nil && !targ->dynexport) {
			addpltsym(targ);
			r->sym = lookup(".plt", 0);
			r->add += targ->plt;
		}
		return;
	
	case 256 + R_X86_64_GOTPCREL:
		if(targ->dynimpname == nil || targ->dynexport) {
			// have symbol
			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;
				return;
			}
			// fall back to using GOT and hope for the best (CMOV*)
			// TODO: just needs relocation, no need to put in .dynsym
			targ->dynimpname = targ->name;
		}
		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:
		if(targ->dynimpname != nil && !targ->dynexport)
			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;
		if(targ->dynimpname != nil && !targ->dynexport)
			diag("unexpected reloc for dynamic symbol %s", targ->name);
		return;

	case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
		if(targ->dynimpname != nil && !targ->dynexport) {
			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;
		if(targ->dynimpname != nil && !targ->dynexport)
			diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
		return;

	case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
		if(targ->dynimpname == nil || targ->dynexport) {
			// 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
	case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
		if(targ->dynimpname == nil || targ->dynexport)
			diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
		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.
	if(targ->dynimpname == nil || targ->dynexport)
		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;
		}
		if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
			// 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);
}
Example #17
0
File: asm.c Project: machinaut/go
void
adddynsym(Sym *s)
{
	Sym *d, *str;
	int t;
	char *name;
	
	if(s->dynid >= 0)
		return;
	
	if(s->dynimpname == nil)
		diag("adddynsym: no dynamic name for %s", s->name, *(int32*)0);

	if(iself) {
		s->dynid = nelfsym++;
		
		d = lookup(".dynsym", 0);

		/* name */
		name = s->dynimpname;
		if(name == nil)
			name = s->name;
		adduint32(d, addstring(lookup(".dynstr", 0), name));
		
		/* value */
		if(s->type == SDYNIMPORT)
			adduint32(d, 0);
		else
			addaddr(d, s);
		
		/* size */
		adduint32(d, 0);
	
		/* type */
		t = STB_GLOBAL << 4;
		if(s->dynexport && s->type == STEXT)
			t |= STT_FUNC;
		else
			t |= STT_OBJECT;
		adduint8(d, t);
		adduint8(d, 0);
	
		/* shndx */
		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);
		}
	} else if(HEADTYPE == Hdarwin) {
		// Mach-O symbol nlist32
		d = lookup(".dynsym", 0);
		name = s->dynimpname;
		if(name == nil)
			name = s->name;
		s->dynid = d->size/12;
		// darwin still puts _ prefixes on all C symbols
		str = lookup(".dynstr", 0);
		adduint32(d, str->size);
		adduint8(str, '_');
		addstring(str, name);
		adduint8(d, 0x01);	// type - N_EXT - external symbol
		adduint8(d, 0);	// section
		adduint16(d, 0);	// desc
		adduint32(d, 0);	// value
	} else if(HEADTYPE != Hwindows) {
		diag("adddynsym: unsupported binary format");
	}
}
Example #18
0
void
adddynsym(Sym *s)
{
	Sym *d, *str;
	int t;
	char *name;

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

	if(s->dynimpname == nil)
		diag("adddynsym: no dynamic name for %s", s->name);

	if(iself) {
		s->dynid = nelfsym++;

		d = lookup(".dynsym", 0);

		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));
		}
	} else if(HEADTYPE == Hdarwin) {
		// 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);
		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;
			}
		}
		adduint16(d, 0);	// desc
		if(s->type == SDYNIMPORT)
			adduint64(d, 0);	// value
		else
			addaddr(d, s);
	} else if(HEADTYPE != Hwindows) {
		diag("adddynsym: unsupported binary format");
	}
}
Example #19
0
void
adddynsym(Sym *s)
{
	Sym *d;
	int t;
	char *name;
	
	if(s->dynid >= 0)
		return;
	
	if(iself) {
		s->dynid = nelfsym++;
		
		d = lookup(".dynsym", 0);

		/* name */
		name = s->extname;
		adduint32(d, addstring(lookup(".dynstr", 0), name));
		
		/* value */
		if(s->type == SDYNIMPORT)
			adduint32(d, 0);
		else
			addaddr(d, s);
		
		/* size */
		adduint32(d, 0);
	
		/* type */
		t = STB_GLOBAL << 4;
		if(s->cgoexport && (s->type&SMASK) == STEXT)
			t |= STT_FUNC;
		else
			t |= STT_OBJECT;
		adduint8(d, t);
		adduint8(d, 0);
	
		/* shndx */
		if(s->type == SDYNIMPORT)
			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);
		}
	} else if(HEADTYPE == Hdarwin) {
		diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
	} else if(HEADTYPE == Hwindows) {
		// already taken care of
	} else {
		diag("adddynsym: unsupported binary format");
	}
}
Example #20
0
void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
	int32 ipc;
	Prog *p;
	Sym *h[NSYM], *s;
	int v, o, r, skip;
	uint32 sig;
	char *name;
	int ntext;
	int32 eof;
	char src[1024], *x;
	Prog *lastp;

	lastp = nil;
	ntext = 0;
	eof = Boffset(f) + len;
	src[0] = 0;

newloop:
	memset(h, 0, sizeof(h));
	version++;
	histfrogp = 0;
	ipc = pc;
	skip = 0;

loop:
	if(f->state == Bracteof || Boffset(f) >= eof)
		goto eof;
	o = BGETC(f);
	if(o == Beof)
		goto eof;

	if(o <= AXXX || o >= ALAST) {
		diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
		print("	probably not a .5 file\n");
		errorexit();
	}
	if(o == ANAME || o == ASIGNAME) {
		sig = 0;
		if(o == ASIGNAME)
			sig = Bget4(f);
		v = BGETC(f); /* type */
		o = BGETC(f); /* sym */
		r = 0;
		if(v == D_STATIC)
			r = version;
		name = Brdline(f, '\0');
		if(name == nil) {
			if(Blinelen(f) > 0) {
				fprint(2, "%s: name too long\n", pn);
				errorexit();
			}
			goto eof;
		}
		x = expandpkg(name, pkg);
		s = lookup(x, r);
		if(x != name)
			free(x);

		if(sig != 0){
			if(s->sig != 0 && s->sig != sig)
				diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name);
			s->sig = sig;
			s->file = pn;
		}

		if(debug['W'])
			print("	ANAME	%s\n", s->name);
		if(o < 0 || o >= nelem(h)) {
			fprint(2, "%s: mangled input file\n", pn);
			errorexit();
		}
		h[o] = s;
		if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
			s->type = SXREF;
		if(v == D_FILE) {
			if(s->type != SFILE) {
				histgen++;
				s->type = SFILE;
				s->value = histgen;
			}
			if(histfrogp < MAXHIST) {
				histfrog[histfrogp] = s;
				histfrogp++;
			} else
				collapsefrog(s);
		}
		goto loop;
	}

	p = mal(sizeof(Prog));
	p->as = o;
	p->scond = BGETC(f);
	p->reg = BGETC(f);
	p->line = Bget4(f);

	zaddr(f, &p->from, h);
	zaddr(f, &p->to, h);

	if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG)
		diag("register out of range %A %d", p->as, p->reg);

	p->link = P;
	p->cond = P;

	if(debug['W'])
		print("%P\n", p);

	switch(o) {
	case AHISTORY:
		if(p->to.offset == -1) {
			addlib(src, pn);
			histfrogp = 0;
			goto loop;
		}
		if(src[0] == '\0')
			copyhistfrog(src, sizeof src);
		addhist(p->line, D_FILE);		/* 'z' */
		if(p->to.offset)
			addhist(p->to.offset, D_FILE1);	/* 'Z' */
		histfrogp = 0;
		goto loop;

	case AEND:
		histtoauto();
		if(cursym != nil && cursym->text)
			cursym->autom = curauto;
		curauto = 0;
		cursym = nil;
		if(Boffset(f) == eof)
			return;
		goto newloop;

	case AGLOBL:
		s = p->from.sym;
		if(s == S) {
			diag("GLOBL must have a name\n%P", p);
			errorexit();
		}
		if(s->type == 0 || s->type == SXREF) {
			s->type = SBSS;
			s->value = 0;
		}
		if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
			diag("redefinition: %s\n%P", s->name, p);
			s->type = SBSS;
			s->value = 0;
		}
		if(p->to.offset > s->size)
			s->size = p->to.offset;
		if(p->reg & DUPOK)
			s->dupok = 1;
		if(p->reg & RODATA)
			s->type = SRODATA;
		else if(p->reg & NOPTR)
			s->type = SNOPTRBSS;
		break;

	case ADATA:
		// Assume that AGLOBL comes after ADATA.
		// If we've seen an AGLOBL that said this sym was DUPOK,
		// ignore any more ADATA we see, which must be
		// redefinitions.
		s = p->from.sym;
		if(s->dupok) {
//			if(debug['v'])
//				Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
			goto loop;
		}
		if(s->file == nil)
			s->file = pn;
		else if(s->file != pn) {
			diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
			errorexit();
		}
		savedata(s, p, pn);
		unmal(p, sizeof *p);
		break;

	case AGOK:
		diag("unknown opcode\n%P", p);
		p->pc = pc;
		pc++;
		break;

	case ATEXT:
		if(cursym != nil && cursym->text) {
			histtoauto();
			cursym->autom = curauto;
			curauto = 0;
		}
		s = p->from.sym;
		if(s == S) {
			diag("TEXT must have a name\n%P", p);
			errorexit();
		}
		cursym = s;
		if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) {
			skip = 1;
			goto casedef;
		}
		if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
			/* redefinition, so file has probably been seen before */
			if(debug['v'])
				Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
			return;
		}
		skip = 0;
		if(s->type != 0 && s->type != SXREF)
			diag("redefinition: %s\n%P", s->name, p);
		if(etextp)
			etextp->next = s;
		else
			textp = s;
		etextp = s;
		p->align = 4;
		autosize = (p->to.offset+3L) & ~3L;
		p->to.offset = autosize;
		autosize += 4;
		s->type = STEXT;
		s->text = p;
		s->value = pc;
		lastp = p;
		p->pc = pc;
		pc++;
		break;

	case ASUB:
		if(p->from.type == D_CONST)
		if(p->from.name == D_NONE)
		if(p->from.offset < 0) {
			p->from.offset = -p->from.offset;
			p->as = AADD;
		}
		goto casedef;

	case AADD:
		if(p->from.type == D_CONST)
		if(p->from.name == D_NONE)
		if(p->from.offset < 0) {
			p->from.offset = -p->from.offset;
			p->as = ASUB;
		}
		goto casedef;

	case AMOVWD:
	case AMOVWF:
	case AMOVDW:
	case AMOVFW:
	case AMOVFD:
	case AMOVDF:
	// case AMOVF:
	// case AMOVD:
	case ACMPF:
	case ACMPD:
	case AADDF:
	case AADDD:
	case ASUBF:
	case ASUBD:
	case AMULF:
	case AMULD:
	case ADIVF:
	case ADIVD:
		goto casedef;

	case AMOVF:
		if(skip)
			goto casedef;

		if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
		   (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
			/* size sb 9 max */
			sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
			s = lookup(literal, 0);
			if(s->type == 0) {
				s->type = SBSS;
				adduint32(s, ieeedtof(&p->from.ieee));
				s->reachable = 0;
			}
			p->from.type = D_OREG;
			p->from.sym = s;
			p->from.name = D_EXTERN;
			p->from.offset = 0;
		}
		goto casedef;

	case AMOVD:
		if(skip)
			goto casedef;

		if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
		   (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
			/* size sb 18 max */
			sprint(literal, "$%ux.%ux",
				p->from.ieee.l, p->from.ieee.h);
			s = lookup(literal, 0);
			if(s->type == 0) {
				s->type = SBSS;
				adduint32(s, p->from.ieee.l);
				adduint32(s, p->from.ieee.h);
				s->reachable = 0;
			}
			p->from.type = D_OREG;
			p->from.sym = s;
			p->from.name = D_EXTERN;
			p->from.offset = 0;
		}
		goto casedef;

	default:
	casedef:
		if(skip)
			nopout(p);
		p->pc = pc;
		pc++;
		if(p->to.type == D_BRANCH)
			p->to.offset += ipc;
		if(lastp == nil) {
			if(p->as != ANOP)
				diag("unexpected instruction: %P", p);
			break;
		}
		lastp->link = p;
		lastp = p;
		break;
	}
	goto loop;

eof:
	diag("truncated object file: %s", pn);
}
Example #21
0
File: obj.c Project: machinaut/go
void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
	int32 ipc;
	Prog *p;
	int v, o, r, skip;
	Sym *h[NSYM], *s;
	uint32 sig;
	int ntext;
	int32 eof;
	char *name, *x;
	char src[1024];
	Prog *lastp;

	lastp = nil;
	ntext = 0;
	eof = Boffset(f) + len;
	src[0] = 0;


newloop:
	memset(h, 0, sizeof(h));
	version++;
	histfrogp = 0;
	ipc = pc;
	skip = 0;

loop:
	if(f->state == Bracteof || Boffset(f) >= eof)
		goto eof;
	o = Bgetc(f);
	if(o == Beof)
		goto eof;
	o |= Bgetc(f) << 8;
	if(o <= AXXX || o >= ALAST) {
		if(o < 0)
			goto eof;
		diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
		print("	probably not a .%c file\n", thechar);
		errorexit();
	}

	if(o == ANAME || o == ASIGNAME) {
		sig = 0;
		if(o == ASIGNAME)
			sig = Bget4(f);
		v = Bgetc(f);	/* type */
		o = Bgetc(f);	/* sym */
		r = 0;
		if(v == D_STATIC)
			r = version;
		name = Brdline(f, '\0');
		if(name == nil) {
			if(Blinelen(f) > 0) {
				fprint(2, "%s: name too long\n", pn);
				errorexit();
			}
			goto eof;
		}
		x = expandpkg(name, pkg);
		s = lookup(x, r);
		if(x != name)
			free(x);

		if(debug['S'] && r == 0)
			sig = 1729;
		if(sig != 0){
			if(s->sig != 0 && s->sig != sig)
				diag("incompatible type signatures"
					"%ux(%s) and %ux(%s) for %s",
					s->sig, s->file, sig, pn, s->name);
			s->sig = sig;
			s->file = pn;
		}

		if(debug['W'])
			print("	ANAME	%s\n", s->name);
		if(o < 0 || o >= nelem(h))
			mangle(pn);
		h[o] = s;
		if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
			s->type = SXREF;
		if(v == D_FILE) {
			if(s->type != SFILE) {
				histgen++;
				s->type = SFILE;
				s->value = histgen;
			}
			if(histfrogp < MAXHIST) {
				histfrog[histfrogp] = s;
				histfrogp++;
			} else
				collapsefrog(s);
			dwarfaddfrag(s->value, s->name);
		}
		goto loop;
	}

	p = mal(sizeof(*p));
	p->as = o;
	p->line = Bget4(f);
	p->back = 2;
	p->ft = 0;
	p->tt = 0;
	zaddr(pn, f, &p->from, h);
	fromgotype = adrgotype;
	zaddr(pn, f, &p->to, h);

	if(debug['W'])
		print("%P\n", p);

	switch(p->as) {
	case AHISTORY:
		if(p->to.offset == -1) {
			addlib(src, pn);
			histfrogp = 0;
			goto loop;
		}
		if(src[0] == '\0')
			copyhistfrog(src, sizeof src);
		addhist(p->line, D_FILE);		/* 'z' */
		if(p->to.offset)
			addhist(p->to.offset, D_FILE1);	/* 'Z' */
		histfrogp = 0;
		goto loop;

	case AEND:
		histtoauto();
		if(cursym != nil && cursym->text)
			cursym->autom = curauto;
		curauto = 0;
		cursym = nil;
		if(Boffset(f) == eof)
			return;
		goto newloop;

	case AGLOBL:
		s = p->from.sym;
		if(s->type == 0 || s->type == SXREF) {
			s->type = SBSS;
			s->size = 0;
		}
		if(s->type != SBSS && !s->dupok) {
			diag("%s: redefinition: %s in %s",
				pn, s->name, TNAME);
			s->type = SBSS;
			s->size = 0;
		}
		if(p->to.offset > s->size)
			s->size = p->to.offset;
		if(p->from.scale & DUPOK)
			s->dupok = 1;
		if(p->from.scale & RODATA)
			s->type = SRODATA;
		goto loop;

	case ADATA:
		// Assume that AGLOBL comes after ADATA.
		// If we've seen an AGLOBL that said this sym was DUPOK,
		// ignore any more ADATA we see, which must be
		// redefinitions.
		s = p->from.sym;
		if(s->dupok) {
//			if(debug['v'])
//				Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
			goto loop;
		}
		if(s->file == nil)
			s->file = pn;
		else if(s->file != pn) {
			diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
			errorexit();
		}
		savedata(s, p, pn);
		unmal(p, sizeof *p);
		goto loop;

	case AGOK:
		diag("%s: GOK opcode in %s", pn, TNAME);
		pc++;
		goto loop;

	case ATEXT:
		s = p->from.sym;
		if(s->text != nil) {
			diag("%s: %s: redefinition", pn, s->name);
			return;
		}
		if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
			/* redefinition, so file has probably been seen before */
			if(debug['v'])
				diag("skipping: %s: redefinition: %s", pn, s->name);
			return;
		}
		if(cursym != nil && cursym->text) {
			histtoauto();
			cursym->autom = curauto;
			curauto = 0;
		}
		skip = 0;
		if(etextp)
			etextp->next = s;
		else
			textp = s;
		etextp = s;
		s->text = p;
		cursym = s;
		if(s->type != 0 && s->type != SXREF) {
			if(p->from.scale & DUPOK) {
				skip = 1;
				goto casdef;
			}
			diag("%s: redefinition: %s\n%P", pn, s->name, p);
		}
		s->type = STEXT;
		s->value = pc;
		lastp = p;
		p->pc = pc++;
		goto loop;

	case AFMOVF:
	case AFADDF:
	case AFSUBF:
	case AFSUBRF:
	case AFMULF:
	case AFDIVF:
	case AFDIVRF:
	case AFCOMF:
	case AFCOMFP:
		if(skip)
			goto casdef;
		if(p->from.type == D_FCONST) {
			/* size sb 9 max */
			sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
			s = lookup(literal, 0);
			if(s->type == 0) {
				s->type = SDATA;
				adduint32(s, ieeedtof(&p->from.ieee));
				s->reachable = 0;
			}
			p->from.type = D_EXTERN;
			p->from.sym = s;
			p->from.offset = 0;
		}
		goto casdef;

	case AFMOVD:
	case AFADDD:
	case AFSUBD:
	case AFSUBRD:
	case AFMULD:
	case AFDIVD:
	case AFDIVRD:
	case AFCOMD:
	case AFCOMDP:
		if(skip)
			goto casdef;
		if(p->from.type == D_FCONST) {
			/* size sb 18 max */
			sprint(literal, "$%ux.%ux",
				p->from.ieee.l, p->from.ieee.h);
			s = lookup(literal, 0);
			if(s->type == 0) {
				s->type = SDATA;
				adduint32(s, p->from.ieee.l);
				adduint32(s, p->from.ieee.h);
				s->reachable = 0;
			}
			p->from.type = D_EXTERN;
			p->from.sym = s;
			p->from.offset = 0;
		}
		goto casdef;

	casdef:
	default:
		if(skip)
			nopout(p);
		p->pc = pc;
		pc++;

		if(p->to.type == D_BRANCH)
			p->to.offset += ipc;
		if(lastp == nil) {
			if(p->as != ANOP)
				diag("unexpected instruction: %P", p);
			goto loop;
		}
		lastp->link = p;
		lastp = p;
		goto loop;
	}

eof:
	diag("truncated object file: %s", pn);
}
Example #22
0
File: asm.c Project: timnau/golang
void
adddynsym(Sym *s)
{
    Sym *d, *str;
    int t;
    char *name;
    vlong off;

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

    if(s->dynimpname == nil)
        diag("adddynsym: no dynamic name for %s", s->name);

    if(iself) {
        s->dynid = nelfsym++;

        d = lookup(".dynsym", 0);

        /* name */
        name = s->dynimpname;
        if(name == nil)
            name = s->name;
        adduint32(d, addstring(lookup(".dynstr", 0), name));

        /* value */
        if(s->type == SDYNIMPORT)
            adduint32(d, 0);
        else
            addaddr(d, s);

        /* size */
        adduint32(d, 0);

        /* type */
        t = STB_GLOBAL << 4;
        if(s->dynexport && (s->type&SMASK) == STEXT)
            t |= STT_FUNC;
        else
            t |= STT_OBJECT;
        adduint8(d, t);
        adduint8(d, 0);

        /* shndx */
        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);
        }
    } else if(HEADTYPE == Hdarwin) {
        // Mach-O symbol nlist32
        d = lookup(".dynsym", 0);
        name = s->dynimpname;
        if(name == nil)
            name = s->name;
        if(d->size == 0 && ndynexp > 0) { // pre-allocate for dynexps
            symgrow(d, ndynexp*12);
        }
        if(s->dynid <= -100) { // pre-allocated, see cmd/ld/go.c:^sortdynexp()
            s->dynid = -s->dynid-100;
            off = s->dynid*12;
        } else {
            off = d->size;
            s->dynid = off/12;
        }
        // darwin still puts _ prefixes on all C symbols
        str = lookup(".dynstr", 0);
        setuint32(d, off, str->size);
        off += 4;
        adduint8(str, '_');
        addstring(str, name);
        if(s->type == SDYNIMPORT) {
            setuint8(d, off, 0x01); // type - N_EXT - external symbol
            off++;
            setuint8(d, off, 0); // section
            off++;
        } else {
            setuint8(d, off, 0x0f);
            off++;
            switch(s->type) {
            default:
            case STEXT:
                setuint8(d, off, 1);
                break;
            case SDATA:
                setuint8(d, off, 2);
                break;
            case SBSS:
                setuint8(d, off, 4);
                break;
            }
            off++;
        }
        setuint16(d, off, 0); // desc
        off += 2;
        if(s->type == SDYNIMPORT)
            setuint32(d, off, 0); // value
        else
            setaddr(d, off, s);
        off += 4;
    } else if(HEADTYPE != Hwindows) {
        diag("adddynsym: unsupported binary format");
    }
}