Пример #1
0
void
elfsetupplt(void)
{
	LSym *plt, *got;
	
	plt = linklookup(ctxt, ".plt", 0);
	got = linklookup(ctxt, ".got.plt", 0);
	if(plt->size == 0) {
		// pushl got+4
		adduint8(ctxt, plt, 0xff);
		adduint8(ctxt, plt, 0x35);
		addaddrplus(ctxt, plt, got, 4);
		
		// jmp *got+8
		adduint8(ctxt, plt, 0xff);
		adduint8(ctxt, plt, 0x25);
		addaddrplus(ctxt, plt, got, 8);

		// zero pad
		adduint32(ctxt, plt, 0);
		
		// assume got->size == 0 too
		addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
		adduint32(ctxt, got, 0);
		adduint32(ctxt, got, 0);
	}
}
Пример #2
0
static int
readsym(PeObj *obj, int i, PeSym **y)
{
	LSym *s;
	PeSym *sym;
	char *name, *p;

	if(i >= obj->npesym || i < 0) {
		werrstr("invalid pe symbol index");
		return -1;
	}

	sym = &obj->pesym[i];
	*y = sym;
	
	if(sym->name[0] == '.') // .section
		name = obj->sect[sym->sectnum-1].sym->name;
	else {
		name = sym->name;
		if(strncmp(name, "__imp_", 6) == 0)
			name = &name[6]; // __imp_Name => Name
		if(thechar == '8' && name[0] == '_')
			name = &name[1]; // _Name => Name
	}
	// remove last @XXX
	p = strchr(name, '@');
	if(p)
		*p = 0;
	
	switch(sym->type) {
	default:
		werrstr("%s: invalid symbol type %d", sym->name, sym->type);
		return -1;
	case IMAGE_SYM_DTYPE_FUNCTION:
	case IMAGE_SYM_DTYPE_NULL:
		switch(sym->sclass) {
		case IMAGE_SYM_CLASS_EXTERNAL: //global
			s = linklookup(ctxt, name, 0);
			break;
		case IMAGE_SYM_CLASS_NULL:
		case IMAGE_SYM_CLASS_STATIC:
		case IMAGE_SYM_CLASS_LABEL:
			s = linklookup(ctxt, name, ctxt->version);
			s->dupok = 1;
			break;
		default:
			werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass);
			return -1;
		}
		break;
	}

	if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0))
		s->type = SXREF;
	if(strncmp(sym->name, "__imp_", 6) == 0)
		s->got = -2; // flag for __imp_
	sym->sym = s;

	return 0;
}
Пример #3
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;
}
Пример #4
0
void
elfsetupplt(void)
{
	LSym *plt, *got;

	plt = linklookup(ctxt, ".plt", 0);
	got = linklookup(ctxt, ".got.plt", 0);
	if(plt->size == 0) {
		// pushq got+8(IP)
		adduint8(ctxt, plt, 0xff);
		adduint8(ctxt, plt, 0x35);
		addpcrelplus(ctxt, plt, got, 8);
		
		// jmpq got+16(IP)
		adduint8(ctxt, plt, 0xff);
		adduint8(ctxt, plt, 0x25);
		addpcrelplus(ctxt, plt, got, 16);
		
		// nopl 0(AX)
		adduint32(ctxt, plt, 0x00401f0f);
		
		// assume got->size == 0 too
		addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
		adduint64(ctxt, got, 0);
		adduint64(ctxt, got, 0);
	}
}
Пример #5
0
// assign addresses to text
void
textaddress(void)
{
	uvlong va;
	Section *sect;
	LSym *sym, *sub;

	addsection(&segtext, ".text", 05);

	// Assign PCs in text segment.
	// Could parallelize, by assigning to text
	// and then letting threads copy down, but probably not worth it.
	sect = segtext.sect;
	sect->align = funcalign;
	linklookup(ctxt, "runtime.text", 0)->sect = sect;
	linklookup(ctxt, "runtime.etext", 0)->sect = sect;
	va = INITTEXT;
	sect->vaddr = va;
	for(sym = ctxt->textp; sym != nil; sym = sym->next) {
		sym->sect = sect;
		if(sym->type & SSUB)
			continue;
		if(sym->align != 0)
			va = rnd(va, sym->align);
		else
			va = rnd(va, funcalign);
		sym->value = 0;
		for(sub = sym; sub != S; sub = sub->sub)
			sub->value += va;
		if(sym->size == 0 && sym->sub != S)
			ctxt->cursym = sym;
		va += sym->size;
	}
	sect->len = va - sect->vaddr;
}
Пример #6
0
Файл: asm.c Проект: 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");
	}
}
Пример #7
0
void
zerosig(char *sp)
{
	LSym *s;

	s = linklookup(ctxt, sp, 0);
	s->sig = 0;
}
Пример #8
0
LSym*
linksym(Sym *s)
{
	char *p;

	if(s == nil)
		return nil;
	if(s->lsym != nil)
		return s->lsym;
	if(isblanksym(s))
		s->lsym = linklookup(ctxt, "_", 0);
	else {
		p = smprint("%s.%s", s->pkg->prefix, s->name);
		s->lsym = linklookup(ctxt, p, 0);
		free(p);
	}
	return s->lsym;	
}
Пример #9
0
void
adddynlib(char *lib)
{
	LSym *s;
	
	if(!needlib(lib))
		return;
	
	if(iself) {
		s = linklookup(ctxt, ".dynstr", 0);
		if(s->size == 0)
			addstring(s, "");
		elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
	} else if(HEADTYPE == Hdarwin) {
		machoadddynlib(lib);
	} else {
		diag("adddynlib: unsupported binary format");
	}
}
Пример #10
0
void
dynrelocsym(LSym *s)
{
	Reloc *r;

	if(HEADTYPE == Hwindows) {
		LSym *rel, *targ;

		rel = linklookup(ctxt, ".rel", 0);
		if(s == rel)
			return;
		for(r=s->r; r<s->r+s->nr; r++) {
			targ = r->sym;
			if(targ == nil)
				continue;
			if(!targ->reachable)
				diag("internal inconsistency: dynamic symbol %s is not reachable.", targ->name);
			if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files.
				targ->plt = rel->size;
				r->sym = rel;
				r->add = targ->plt;

				// jmp *addr
				if(thechar == '8') {
					adduint8(ctxt, rel, 0xff);
					adduint8(ctxt, rel, 0x25);
					addaddr(ctxt, rel, targ);
					adduint8(ctxt, rel, 0x90);
					adduint8(ctxt, rel, 0x90);
				} else {
					adduint8(ctxt, rel, 0xff);
					adduint8(ctxt, rel, 0x24);
					adduint8(ctxt, rel, 0x25);
					addaddrplus4(ctxt, rel, targ, 0);
					adduint8(ctxt, rel, 0x90);
				}
			} else if(r->sym->plt >= 0) {
				r->sym = rel;
				r->add = targ->plt;
			}
		}
		return;
	}

	for(r=s->r; r<s->r+s->nr; r++) {
		if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) {
			if(r->sym != S && !r->sym->reachable)
				diag("internal inconsistency: dynamic symbol %s is not reachable.", r->sym->name);
			adddynrel(s, r);
		}
	}
}
Пример #11
0
Файл: pe.c Проект: rosrad/go-rep
void
dope(void)
{
	LSym *rel;

	/* relocation table */
	rel = linklookup(ctxt, ".rel", 0);
	rel->reachable = 1;
	rel->type = SELFROSECT;

	initdynimport();
	initdynexport();
}
Пример #12
0
static void
addpltsym(Link *ctxt, LSym *s)
{
	LSym *plt, *got, *rel;
	
	if(s->plt >= 0)
		return;

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

		plt = linklookup(ctxt, ".plt", 0);

		addgotsym(ctxt, s);

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

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

		adduint8(ctxt, plt, 0xff);
		adduint8(ctxt, plt, 0x25);
		addaddrplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got);
	} else {
		diag("addpltsym: unsupported binary format");
	}
}
Пример #13
0
static void
addgotsym(Link *ctxt, LSym *s)
{
	LSym *got, *rel;
	
	if(s->got >= 0)
		return;
	
	adddynsym(ctxt, s);
	got = linklookup(ctxt, ".got", 0);
	s->got = got->size;
	adduint32(ctxt, got, 0);
	
	if(iself) {
		rel = linklookup(ctxt, ".rel", 0);
		addaddrplus(ctxt, rel, got, s->got);
		adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
	} else if(HEADTYPE == Hdarwin) {
		adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
	} else {
		diag("addgotsym: unsupported binary format");
	}
}
Пример #14
0
int
archreloc(Reloc *r, LSym *s, vlong *val)
{
	USED(s);
	if(linkmode == LinkExternal)
		return -1;
	switch(r->type) {
	case D_CONST:
		*val = r->add;
		return 0;
	case D_GOTOFF:
		*val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
		return 0;
	}
	return -1;
}
Пример #15
0
void
libinit(void)
{
	char *suffix, *suffixsep;

	fmtinstall('i', iconv);
	fmtinstall('Y', Yconv);
	fmtinstall('Z', Zconv);
	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.
	suffix = "";
	suffixsep = "";
	if(flag_installsuffix != nil) {
		suffixsep = "_";
		suffix = flag_installsuffix;
	} else if(flag_race) {
		suffixsep = "_";
		suffix = "race";
	}
	Lflag(smprint("%s/pkg/%s_%s%s%s", goroot, goos, goarch, suffixsep, suffix));

	// 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
	remove(outfile);
#endif
	cout = create(outfile, 1, 0775);
	if(cout < 0) {
		diag("cannot create %s: %r", outfile);
		errorexit();
	}

	if(INITENTRY == nil) {
		INITENTRY = mal(strlen(goarch)+strlen(goos)+20);
		if(!flag_shared) {
			sprint(INITENTRY, "_rt0_%s_%s", goarch, goos);
		} else {
			sprint(INITENTRY, "_rt0_%s_%s_lib", goarch, goos);
		}
	}
	linklookup(ctxt, INITENTRY, 0)->type = SXREF;
}
Пример #16
0
Файл: pe.c Проект: rosrad/go-rep
static Dll* 
initdynimport(void)
{
	Imp *m;
	Dll *d;
	LSym *s, *dynamic;

	dr = nil;
	m = nil;
	for(s = ctxt->allsym; s != S; s = s->allsym) {
		if(!s->reachable || s->type != SDYNIMPORT)
			continue;
		for(d = dr; d != nil; d = d->next) {
			if(strcmp(d->name,s->dynimplib) == 0) {
				m = mal(sizeof *m);
				break;
			}
		}
		if(d == nil) {
			d = mal(sizeof *d);
			d->name = s->dynimplib;
			d->next = dr;
			dr = d;
			m = mal(sizeof *m);
		}
		m->s = s;
		m->next = d->ms;
		d->ms = m;
	}
	
	dynamic = linklookup(ctxt, ".windynamic", 0);
	dynamic->reachable = 1;
	dynamic->type = SWINDOWS;
	for(d = dr; d != nil; d = d->next) {
		for(m = d->ms; m != nil; m = m->next) {
			m->s->type = SWINDOWS | SSUB;
			m->s->sub = dynamic->sub;
			dynamic->sub = m->s;
			m->s->value = dynamic->size;
			dynamic->size += PtrSize;
		}
		dynamic->size += PtrSize;
	}
		
	return dr;
}
Пример #17
0
static int
needlib(char *name)
{
	char *p;
	LSym *s;

	if(*name == '\0')
		return 0;

	/* reuse hash code in symbol table */
	p = smprint(".elfload.%s", name);
	s = linklookup(ctxt, p, 0);
	free(p);
	if(s->type == 0) {
		s->type = 100;	// avoid SDATA, etc.
		return 1;
	}
	return 0;
}
Пример #18
0
static void
addexcept(IMAGE_SECTION_HEADER *text)
{
	IMAGE_SECTION_HEADER *pdata, *xdata;
	vlong startoff;
	uvlong n;
	LSym *sym;

	USED(text);
	if(thechar != '6')
		return;

	// write unwind info
	sym = linklookup(ctxt, "runtime.sigtramp", 0);
	startoff = cpos();
	lputl(9);	// version=1, flags=UNW_FLAG_EHANDLER, rest 0
	lputl(sym->value - PEBASE);
	lputl(0);

	n = cpos() - startoff;
	xdata = addpesection(".xdata", n, n);
	xdata->Characteristics = IMAGE_SCN_MEM_READ|
		IMAGE_SCN_CNT_INITIALIZED_DATA;
	chksectoff(xdata, startoff);
	strnput("", xdata->SizeOfRawData - n);

	// write a function table entry for the whole text segment
	startoff = cpos();
	lputl(text->VirtualAddress);
	lputl(text->VirtualAddress + text->VirtualSize);
	lputl(xdata->VirtualAddress);

	n = cpos() - startoff;
	pdata = addpesection(".pdata", n, n);
	pdata->Characteristics = IMAGE_SCN_MEM_READ|
		IMAGE_SCN_CNT_INITIALIZED_DATA;
	chksectoff(pdata, startoff);
	strnput("", pdata->SizeOfRawData - n);

	dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = pdata->VirtualAddress;
	dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = pdata->VirtualSize;
}
Пример #19
0
static void
addpltsym(LSym *s)
{
	if(s->plt >= 0)
		return;
	
	adddynsym(ctxt, s);
	
	if(iself) {
		LSym *plt, *got, *rela;

		plt = linklookup(ctxt, ".plt", 0);
		got = linklookup(ctxt, ".got.plt", 0);
		rela = linklookup(ctxt, ".rela.plt", 0);
		if(plt->size == 0)
			elfsetupplt();
		
		// jmpq *got+size(IP)
		adduint8(ctxt, plt, 0xff);
		adduint8(ctxt, plt, 0x25);
		addpcrelplus(ctxt, plt, got, got->size);
	
		// add to got: pointer to current pos in plt
		addaddrplus(ctxt, got, plt, plt->size);
		
		// pushq $x
		adduint8(ctxt, plt, 0x68);
		adduint32(ctxt, plt, (got->size-24-8)/8);
		
		// jmpq .plt
		adduint8(ctxt, plt, 0xe9);
		adduint32(ctxt, plt, -(plt->size+4));
		
		// rela
		addaddrplus(ctxt, rela, got, got->size-8);
		adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
		adduint64(ctxt, 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.

		LSym *plt;
		
		addgotsym(s);
		plt = linklookup(ctxt, ".plt", 0);

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

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

		adduint8(ctxt, plt, 0xff);
		adduint8(ctxt, plt, 0x25);
		addpcrelplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got);
	} else {
		diag("addpltsym: unsupported binary format");
	}
}
Пример #20
0
void
loadlib(void)
{
	int i, w, x;
	LSym *s, *gmsym;
	char* cgostrsym;

	if(flag_shared) {
		s = linklookup(ctxt, "runtime.islibrary", 0);
		s->dupok = 1;
		adduint8(ctxt, s, 1);
	}

	loadinternal("runtime");
	if(thechar == '5')
		loadinternal("math");
	if(flag_race)
		loadinternal("runtime/race");

	for(i=0; i<ctxt->libraryp; i++) {
		if(debug['v'] > 1)
			Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), ctxt->library[i].file, ctxt->library[i].objref);
		iscgo |= strcmp(ctxt->library[i].pkg, "runtime/cgo") == 0;
		objfile(ctxt->library[i].file, ctxt->library[i].pkg);
	}
	
	if(linkmode == LinkExternal && !iscgo) {
		// This indicates a user requested -linkmode=external.
		// The startup code uses an import of runtime/cgo to decide
		// whether to initialize the TLS.  So give it one.  This could
		// be handled differently but it's an unusual case.
		loadinternal("runtime/cgo");

		// Pretend that we really imported the package.
		s = linklookup(ctxt, "go.importpath.runtime/cgo.", 0);
		s->type = SDATA;
		s->dupok = 1;
		s->reachable = 1;

		// Provided by the code that imports the package.
		// Since we are simulating the import, we have to provide this string.
		cgostrsym = "go.string.\"runtime/cgo\"";
		if(linkrlookup(ctxt, cgostrsym, 0) == nil)
			addstrdata(cgostrsym, "runtime/cgo");
	}

	if(linkmode == LinkAuto) {
		if(iscgo && externalobj)
			linkmode = LinkExternal;
		else
			linkmode = LinkInternal;
	}

	if(linkmode == LinkInternal) {
		// Drop all the cgo_import_static declarations.
		// Turns out we won't be needing them.
		for(s = ctxt->allsym; s != S; s = s->allsym)
			if(s->type == SHOSTOBJ) {
				// If a symbol was marked both
				// cgo_import_static and cgo_import_dynamic,
				// then we want to make it cgo_import_dynamic
				// now.
				if(s->extname != nil && s->dynimplib != nil && s->cgoexport == 0) {
					s->type = SDYNIMPORT;
				} else
					s->type = 0;
			}
	}
	
	gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
	gmsym->type = STLSBSS;
	gmsym->size = 2*PtrSize;
	gmsym->hide = 1;
	gmsym->reachable = 1;

	// Now that we know the link mode, trim the dynexp list.
	x = CgoExportDynamic;
	if(linkmode == LinkExternal)
		x = CgoExportStatic;
	w = 0;
	for(i=0; i<ndynexp; i++)
		if(dynexp[i]->cgoexport & x)
			dynexp[w++] = dynexp[i];
	ndynexp = w;
	
	// In internal link mode, read the host object files.
	if(linkmode == LinkInternal)
		hostobjs();
	else
		hostlinksetup();

	// 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.
	// Also leave it enabled on Solaris which doesn't support
	// statically linked binaries.
	if(!flag_shared && !havedynamic && HEADTYPE != Hdarwin && HEADTYPE != Hsolaris)
		debug['d'] = 1;
	
	importcycles();
}
Пример #21
0
void
asmbelf(vlong symo)
{
	vlong a, o;
	vlong startva, resoff;
	ElfEhdr *eh;
	ElfPhdr *ph, *pph, *pnote;
	ElfShdr *sh;
	Section *sect;

	eh = getElfEhdr();
	switch(thechar) {
	default:
		diag("unknown architecture in asmbelf");
		errorexit();
	case '5':
		eh->machine = EM_ARM;
		break;
	case '6':
		eh->machine = EM_X86_64;
		break;
	case '8':
		eh->machine = EM_386;
		break;
	}

	startva = INITTEXT - HEADR;
	resoff = ELFRESERVE;
	
	pph = nil;
	if(linkmode == LinkExternal) {
		/* skip program headers */
		eh->phoff = 0;
		eh->phentsize = 0;
		goto elfobj;
	}

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

	/*
	 * PHDR must be in a loaded segment. Adjust the text
	 * segment boundaries downwards to include it.
	 * Except on NaCl where it must not be loaded.
	 */
	if(HEADTYPE != Hnacl) {
		o = segtext.vaddr - pph->vaddr;
		segtext.vaddr -= o;
		segtext.len += o;
		o = segtext.fileoff - pph->off;
		segtext.fileoff -= o;
		segtext.filelen += o;
	}

	if(!debug['d']) {
		/* interpreter */
		sh = elfshname(".interp");
		sh->type = SHT_PROGBITS;
		sh->flags = SHF_ALLOC;
		sh->addralign = 1;
		if(interpreter == nil) {
			switch(HEADTYPE) {
			case Hlinux:
				interpreter = linuxdynld;
				break;
			case Hfreebsd:
				interpreter = freebsddynld;
				break;
			case Hnetbsd:
				interpreter = netbsddynld;
				break;
			case Hopenbsd:
				interpreter = openbsddynld;
				break;
			case Hdragonfly:
				interpreter = dragonflydynld;
				break;
			case Hsolaris:
				interpreter = solarisdynld;
				break;
			}
		}
		resoff -= elfinterp(sh, startva, resoff, interpreter);

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

	pnote = nil;
	if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) {
		sh = nil;
		switch(HEADTYPE) {
		case Hnetbsd:
			sh = elfshname(".note.netbsd.ident");
			resoff -= elfnetbsdsig(sh, startva, resoff);
			break;
		case Hopenbsd:
			sh = elfshname(".note.openbsd.ident");
			resoff -= elfopenbsdsig(sh, startva, resoff);
			break;
		}

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

	if(buildinfolen > 0) {
		sh = elfshname(".note.gnu.build-id");
		resoff -= elfbuildinfo(sh, startva, resoff);

		if(pnote == nil) {
			pnote = newElfPhdr();
			pnote->type = PT_NOTE;
			pnote->flags = PF_R;
		}
		phsh(pnote, sh);
	}

	// Additions to the reserved area must be above this line.
	USED(resoff);

	elfphload(&segtext);
	if(segrodata.sect != nil)
		elfphload(&segrodata);
	elfphload(&segdata);

	/* Dynamic linking sections */
	if(!debug['d']) {	/* -d suppresses dynamic loader format */
		sh = elfshname(".dynsym");
		sh->type = SHT_DYNSYM;
		sh->flags = SHF_ALLOC;
		if(elf64)
			sh->entsize = ELF64SYMSIZE;
		else
			sh->entsize = ELF32SYMSIZE;
		sh->addralign = RegSize;
		sh->link = elfshname(".dynstr")->shnum;
		// sh->info = index of first non-local symbol (number of local symbols)
		shsym(sh, linklookup(ctxt, ".dynsym", 0));

		sh = elfshname(".dynstr");
		sh->type = SHT_STRTAB;
		sh->flags = SHF_ALLOC;
		sh->addralign = 1;
		shsym(sh, linklookup(ctxt, ".dynstr", 0));

		if(elfverneed) {
			sh = elfshname(".gnu.version");
			sh->type = SHT_GNU_VERSYM;
			sh->flags = SHF_ALLOC;
			sh->addralign = 2;
			sh->link = elfshname(".dynsym")->shnum;
			sh->entsize = 2;
			shsym(sh, linklookup(ctxt, ".gnu.version", 0));
			
			sh = elfshname(".gnu.version_r");
			sh->type = SHT_GNU_VERNEED;
			sh->flags = SHF_ALLOC;
			sh->addralign = RegSize;
			sh->info = elfverneed;
			sh->link = elfshname(".dynstr")->shnum;
			shsym(sh, linklookup(ctxt, ".gnu.version_r", 0));
		}

		switch(eh->machine) {
		case EM_X86_64:
			sh = elfshname(".rela.plt");
			sh->type = SHT_RELA;
			sh->flags = SHF_ALLOC;
			sh->entsize = ELF64RELASIZE;
			sh->addralign = RegSize;
			sh->link = elfshname(".dynsym")->shnum;
			sh->info = elfshname(".plt")->shnum;
			shsym(sh, linklookup(ctxt, ".rela.plt", 0));

			sh = elfshname(".rela");
			sh->type = SHT_RELA;
			sh->flags = SHF_ALLOC;
			sh->entsize = ELF64RELASIZE;
			sh->addralign = 8;
			sh->link = elfshname(".dynsym")->shnum;
			shsym(sh, linklookup(ctxt, ".rela", 0));
			break;
		
		default:
			sh = elfshname(".rel.plt");
			sh->type = SHT_REL;
			sh->flags = SHF_ALLOC;
			sh->entsize = ELF32RELSIZE;
			sh->link = elfshname(".dynsym")->shnum;
			shsym(sh, linklookup(ctxt, ".rel.plt", 0));

			sh = elfshname(".rel");
			sh->type = SHT_REL;
			sh->flags = SHF_ALLOC;
			sh->entsize = ELF32RELSIZE;
			sh->addralign = 4;
			sh->link = elfshname(".dynsym")->shnum;
			shsym(sh, linklookup(ctxt, ".rel", 0));
			break;
		}

		sh = elfshname(".plt");
		sh->type = SHT_PROGBITS;
		sh->flags = SHF_ALLOC+SHF_EXECINSTR;
		if(eh->machine == EM_X86_64)
			sh->entsize = 16;
		else
			sh->entsize = 4;
		sh->addralign = 4;
		shsym(sh, linklookup(ctxt, ".plt", 0));

		sh = elfshname(".got");
		sh->type = SHT_PROGBITS;
		sh->flags = SHF_ALLOC+SHF_WRITE;
		sh->entsize = RegSize;
		sh->addralign = RegSize;
		shsym(sh, linklookup(ctxt, ".got", 0));

		sh = elfshname(".got.plt");
		sh->type = SHT_PROGBITS;
		sh->flags = SHF_ALLOC+SHF_WRITE;
		sh->entsize = RegSize;
		sh->addralign = RegSize;
		shsym(sh, linklookup(ctxt, ".got.plt", 0));
		
		sh = elfshname(".hash");
		sh->type = SHT_HASH;
		sh->flags = SHF_ALLOC;
		sh->entsize = 4;
		sh->addralign = RegSize;
		sh->link = elfshname(".dynsym")->shnum;
		shsym(sh, linklookup(ctxt, ".hash", 0));

		/* sh and PT_DYNAMIC for .dynamic section */
		sh = elfshname(".dynamic");
		sh->type = SHT_DYNAMIC;
		sh->flags = SHF_ALLOC+SHF_WRITE;
		sh->entsize = 2*RegSize;
		sh->addralign = RegSize;
		sh->link = elfshname(".dynstr")->shnum;
		shsym(sh, linklookup(ctxt, ".dynamic", 0));
		ph = newElfPhdr();
		ph->type = PT_DYNAMIC;
		ph->flags = PF_R + PF_W;
		phsh(ph, sh);
		
		/*
		 * Thread-local storage segment (really just size).
		 */
		// Do not emit PT_TLS for OpenBSD since ld.so(1) does
		// not currently support it. This is handled
		// appropriately in runtime/cgo.
		if(ctxt->tlsoffset != 0 && HEADTYPE != Hopenbsd) {
			ph = newElfPhdr();
			ph->type = PT_TLS;
			ph->flags = PF_R;
			ph->memsz = -ctxt->tlsoffset;
			ph->align = RegSize;
		}
	}

	if(HEADTYPE == Hlinux) {
		ph = newElfPhdr();
		ph->type = PT_GNU_STACK;
		ph->flags = PF_W+PF_R;
		ph->align = RegSize;
		
		ph = newElfPhdr();
		ph->type = PT_PAX_FLAGS;
		ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled
		ph->align = RegSize;
	}

elfobj:
	sh = elfshname(".shstrtab");
	sh->type = SHT_STRTAB;
	sh->addralign = 1;
	shsym(sh, linklookup(ctxt, ".shstrtab", 0));
	eh->shstrndx = sh->shnum;

	// put these sections early in the list
	if(!debug['s']) {
		elfshname(".symtab");
		elfshname(".strtab");
	}

	for(sect=segtext.sect; sect!=nil; sect=sect->next)
		elfshbits(sect);
	for(sect=segrodata.sect; sect!=nil; sect=sect->next)
		elfshbits(sect);
	for(sect=segdata.sect; sect!=nil; sect=sect->next)
		elfshbits(sect);

	if(linkmode == LinkExternal) {
		for(sect=segtext.sect; sect!=nil; sect=sect->next)
			elfshreloc(sect);
		for(sect=segrodata.sect; sect!=nil; sect=sect->next)
			elfshreloc(sect);
		for(sect=segdata.sect; sect!=nil; sect=sect->next)
			elfshreloc(sect);
		// add a .note.GNU-stack section to mark the stack as non-executable
		sh = elfshname(".note.GNU-stack");
		sh->type = SHT_PROGBITS;
		sh->addralign = 1;
		sh->flags = 0;
	}

	// generate .tbss section for dynamic internal linking (except for OpenBSD)
	// external linking generates .tbss in data.c
	if(linkmode == LinkInternal && !debug['d'] && HEADTYPE != Hopenbsd) {
		sh = elfshname(".tbss");
		sh->type = SHT_NOBITS;
		sh->addralign = RegSize;
		sh->size = -ctxt->tlsoffset;
		sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE;
	}

	if(!debug['s']) {
		sh = elfshname(".symtab");
		sh->type = SHT_SYMTAB;
		sh->off = symo;
		sh->size = symsize;
		sh->addralign = RegSize;
		sh->entsize = 8+2*RegSize;
		sh->link = elfshname(".strtab")->shnum;
		sh->info = elfglobalsymndx;

		sh = elfshname(".strtab");
		sh->type = SHT_STRTAB;
		sh->off = symo+symsize;
		sh->size = elfstrsize;
		sh->addralign = 1;

		dwarfaddelfheaders();
	}

	/* Main header */
	eh->ident[EI_MAG0] = '\177';
	eh->ident[EI_MAG1] = 'E';
	eh->ident[EI_MAG2] = 'L';
	eh->ident[EI_MAG3] = 'F';
	if(HEADTYPE == Hfreebsd)
		eh->ident[EI_OSABI] = ELFOSABI_FREEBSD;
	else if(HEADTYPE == Hnetbsd)
		eh->ident[EI_OSABI] = ELFOSABI_NETBSD;
	else if(HEADTYPE == Hopenbsd)
		eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
	else if(HEADTYPE == Hdragonfly)
		eh->ident[EI_OSABI] = ELFOSABI_NONE;
	if(elf64)
		eh->ident[EI_CLASS] = ELFCLASS64;
	else
		eh->ident[EI_CLASS] = ELFCLASS32;
	eh->ident[EI_DATA] = ELFDATA2LSB;
	eh->ident[EI_VERSION] = EV_CURRENT;

	if(linkmode == LinkExternal)
		eh->type = ET_REL;
	else
		eh->type = ET_EXEC;

	if(linkmode != LinkExternal)
		eh->entry = entryvalue();

	eh->version = EV_CURRENT;

	if(pph != nil) {
		pph->filesz = eh->phnum * eh->phentsize;
		pph->memsz = pph->filesz;
	}

	cseek(0);
	a = 0;
	a += elfwritehdr();
	a += elfwritephdrs();
	a += elfwriteshdrs();
	if(!debug['d'])
		a += elfwriteinterp();
	if(linkmode != LinkExternal) {
		if(HEADTYPE == Hnetbsd)
			a += elfwritenetbsdsig();
		if(HEADTYPE == Hopenbsd)
			a += elfwriteopenbsdsig();
		if(buildinfolen > 0)
			a += elfwritebuildinfo();
	}
	if(a > ELFRESERVE)	
		diag("ELFRESERVE too small: %lld > %d", a, ELFRESERVE);
}
Пример #22
0
void
main(int argc, char *argv[])
{
	linkarchinit();
	ctxt = linknew(thelinkarch);
	ctxt->thechar = thechar;
	ctxt->thestring = thestring;
	ctxt->diag = diag;
	ctxt->bso = &bso;

	Binit(&bso, 1, OWRITE);
	listinit();
	memset(debug, 0, sizeof(debug));
	nerrors = 0;
	outfile = nil;
	HEADTYPE = -1;
	INITTEXT = -1;
	INITDAT = -1;
	INITRND = -1;
	INITENTRY = 0;
	linkmode = LinkAuto;
	nuxiinit();
	
	if(thechar == '5' && ctxt->goarm == 5)
		debug['F'] = 1;

	flagcount("1", "use alternate profiling code", &debug['1']);
	if(thechar == '6')
		flagcount("8", "assume 64-bit addresses", &debug['8']);
	flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
	flagint64("D", "addr: data address", &INITDAT);
	flagstr("E", "sym: entry symbol", &INITENTRY);
	if(thechar == '5')
		flagcount("G", "debug pseudo-ops", &debug['G']);
	flagfn1("I", "interp: set ELF interp", setinterp);
	flagfn1("L", "dir: add dir to library path", Lflag);
	flagfn1("H", "head: header type", setheadtype);
	flagcount("K", "add stack underflow checks", &debug['K']);
	if(thechar == '5')
		flagcount("M", "disable software div/mod", &debug['M']);
	flagcount("O", "print pc-line tables", &debug['O']);
	flagcount("Q", "debug byte-register code gen", &debug['Q']);
	if(thechar == '5')
		flagcount("P", "debug code generation", &debug['P']);
	flagint32("R", "rnd: address rounding", &INITRND);
	flagcount("S", "check type signatures", &debug['S']);
	flagint64("T", "addr: text address", &INITTEXT);
	flagfn0("V", "print version and exit", doversion);
	flagcount("W", "disassemble input", &debug['W']);
	flagfn2("X", "name value: define string data", addstrdata);
	flagcount("Z", "clear stack frame on entry", &debug['Z']);
	flagcount("a", "disassemble output", &debug['a']);
	flagcount("c", "dump call graph", &debug['c']);
	flagcount("d", "disable dynamic executable", &debug['d']);
	flagstr("extld", "linker to run in external mode", &extld);
	flagstr("extldflags", "flags for external linker", &extldflags);
	flagcount("f", "ignore version mismatch", &debug['f']);
	flagcount("g", "disable go package data checks", &debug['g']);
	flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
	flagstr("k", "sym: set field tracking symbol", &tracksym);
	flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
	flagcount("n", "dump symbol table", &debug['n']);
	flagstr("o", "outfile: set output file", &outfile);
	flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
	flagcount("race", "enable race detector", &flag_race);
	flagcount("s", "disable symbol table", &debug['s']);
	if(thechar == '5' || thechar == '6')
		flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared);
	flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
	flagcount("u", "reject unsafe packages", &debug['u']);
	flagcount("v", "print link trace", &debug['v']);
	flagcount("w", "disable DWARF generation", &debug['w']);
	
	flagparse(&argc, &argv, usage);
	ctxt->bso = &bso;
	ctxt->debugdivmod = debug['M'];
	ctxt->debugfloat = debug['F'];
	ctxt->debughist = debug['O'];
	ctxt->debugpcln = debug['O'];
	ctxt->debugread = debug['W'];
	ctxt->debugstack = debug['K'];
	ctxt->debugvlog = debug['v'];

	if(argc != 1)
		usage();

	if(outfile == nil) {
		if(HEADTYPE == Hwindows)
			outfile = smprint("%c.out.exe", thechar);
		else
			outfile = smprint("%c.out", thechar);
	}
	libinit(); // creates outfile

	if(HEADTYPE == -1)
		HEADTYPE = headtype(goos);
	ctxt->headtype = HEADTYPE;
	if (headstring == nil)
		headstring = headstr(HEADTYPE);

	archinit();
	ctxt->debugfloat = debug['F'];

	if(debug['v'])
		Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
			HEADTYPE, INITTEXT, INITDAT, INITRND);
	Bflush(&bso);

	cbp = buf.cbuf;
	cbc = sizeof(buf.cbuf);

	addlibpath(ctxt, "command line", "command line", argv[0], "main");
	loadlib();
	
	if(thechar == '5') {
		// mark some functions that are only referenced after linker code editing
		if(debug['F'])
			mark(linkrlookup(ctxt, "_sfloat", 0));
		mark(linklookup(ctxt, "runtime.read_tls_fallback", 0));
	}

	deadcode();
	callgraph();
	paramspace = "SP";	/* (FP) now (SP) on output */

	doelf();
	if(HEADTYPE == Hdarwin)
		domacho();
	dostkcheck();
	if(HEADTYPE == Hwindows)
		dope();
	addexport();
	textaddress();
	pclntab();
	symtab();
	dodata();
	address();
	doweak();
	reloc();
	asmb();
	undef();
	hostlink();
	if(debug['v']) {
		Bprint(&bso, "%5.2f cpu time\n", cputime());
		Bprint(&bso, "%d symbols\n", ctxt->nsymbol);
		Bprint(&bso, "%d sizeof adr\n", sizeof(Addr));
		Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
		Bprint(&bso, "%lld liveness data\n", liveness);
	}
	Bflush(&bso);

	errorexit();
}
Пример #23
0
// This is a simplified copy of linklinefmt above.
// It doesn't allow printing the full stack, and it returns the file name and line number separately.
// TODO: Unify with linklinefmt somehow.
void
linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
{
	struct
	{
		Hist*	incl;	/* start of this include file */
		int32	idel;	/* delta line number to apply to include */
		Hist*	line;	/* start of this #line directive */
		int32	ldel;	/* delta line number to apply to #line */
	} a[HISTSZ];
	int32 lno, d, dlno;
	int n;
	Hist *h;
	char buf[1024], *file;

	lno = line;
	n = 0;
	for(h=ctxt->hist; h!=nil; h=h->link) {
		if(h->offset < 0)
			continue;
		if(lno < h->line)
			break;
		if(h->name) {
			if(h->offset > 0) {
				// #line directive
				if(n > 0 && n < HISTSZ) {
					a[n-1].line = h;
					a[n-1].ldel = h->line - h->offset + 1;
				}
			} else {
				// beginning of file
				if(n < HISTSZ) {
					a[n].incl = h;
					a[n].idel = h->line;
					a[n].line = 0;
				}
				n++;
			}
			continue;
		}
		n--;
		if(n > 0 && n < HISTSZ) {
			d = h->line - a[n].incl->line;
			a[n-1].ldel += d;
			a[n-1].idel += d;
		}
	}

	if(n > HISTSZ)
		n = HISTSZ;

	if(n <= 0) {
		*f = linklookup(ctxt, "??", HistVersion);
		*l = 0;
		return;
	}
	
	n--;
	if(a[n].line) {
		file = a[n].line->name;
		dlno = a[n].ldel-1;
	} else {
		file = a[n].incl->name;
		dlno = a[n].idel-1;
	}
	if((!ctxt->windows && file[0] == '/') || (ctxt->windows && file[1] == ':'))
		snprint(buf, sizeof buf, "%s", file);
	else
		snprint(buf, sizeof buf, "%s/%s", ctxt->pathname, file);
	lno -= dlno;
	*f = linklookup(ctxt, buf, HistVersion);
	*l = lno;
}
Пример #24
0
Файл: ldelf.c Проект: 8l/go
void
ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
{
	int32 base;
	uint64 add, info;
	char *name;
	int i, j, rela, is64, n, flag;
	uchar hdrbuf[64];
	uchar *p;
	ElfHdrBytes *hdr;
	ElfObj *obj;
	ElfSect *sect, *rsect;
	ElfSym sym;
	Endian *e;
	Reloc *r, *rp;
	LSym *s;
	LSym **symbols;

	symbols = nil;

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

	ctxt->version++;
	base = Boffset(f);

	if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
		goto bad;
	hdr = (ElfHdrBytes*)hdrbuf;
	if(memcmp(hdr->ident, ElfMagic, 4) != 0)
		goto bad;
	switch(hdr->ident[5]) {
	case ElfDataLsb:
		e = &le;
		break;
	case ElfDataMsb:
		e = &be;
		break;
	default:
		goto bad;
	}

	// read header
	obj = mal(sizeof *obj);
	obj->e = e;
	obj->f = f;
	obj->base = base;
	obj->len = len;
	obj->name = pn;
	
	is64 = 0;
	if(hdr->ident[4] == ElfClass64) {
		ElfHdrBytes64* hdr;

		is64 = 1;
		hdr = (ElfHdrBytes64*)hdrbuf;
		obj->type = e->e16(hdr->type);
		obj->machine = e->e16(hdr->machine);
		obj->version = e->e32(hdr->version);
		obj->phoff = e->e64(hdr->phoff);
		obj->shoff = e->e64(hdr->shoff);
		obj->flags = e->e32(hdr->flags);
		obj->ehsize = e->e16(hdr->ehsize);
		obj->phentsize = e->e16(hdr->phentsize);
		obj->phnum = e->e16(hdr->phnum);
		obj->shentsize = e->e16(hdr->shentsize);
		obj->shnum = e->e16(hdr->shnum);
		obj->shstrndx = e->e16(hdr->shstrndx);
	} else {
		obj->type = e->e16(hdr->type);
		obj->machine = e->e16(hdr->machine);
		obj->version = e->e32(hdr->version);
		obj->entry = e->e32(hdr->entry);
		obj->phoff = e->e32(hdr->phoff);
		obj->shoff = e->e32(hdr->shoff);
		obj->flags = e->e32(hdr->flags);
		obj->ehsize = e->e16(hdr->ehsize);
		obj->phentsize = e->e16(hdr->phentsize);
		obj->phnum = e->e16(hdr->phnum);
		obj->shentsize = e->e16(hdr->shentsize);
		obj->shnum = e->e16(hdr->shnum);
		obj->shstrndx = e->e16(hdr->shstrndx);
	}
	obj->is64 = is64;
	
	if(hdr->ident[6] != obj->version)
		goto bad;

	if(e->e16(hdr->type) != ElfTypeRelocatable) {
		diag("%s: elf but not elf relocatable object", pn);
		return;
	}

	switch(thechar) {
	default:
		diag("%s: elf %s unimplemented", pn, thestring);
		return;
	case '5':
		if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) {
			diag("%s: elf object but not arm", pn);
			return;
		}
		break;
	case '6':
		if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) {
			diag("%s: elf object but not amd64", pn);
			return;
		}
		break;
	case '8':
		if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) {
			diag("%s: elf object but not 386", pn);
			return;
		}
		break;
	case '9':
		if(obj->machine != ElfMachPower64 || hdr->ident[4] != ElfClass64) {
			diag("%s: elf object but not ppc64", pn);
			return;
		}
		break;
	}

	// load section list into memory.
	obj->sect = mal(obj->shnum*sizeof obj->sect[0]);
	obj->nsect = obj->shnum;
	for(i=0; i<obj->nsect; i++) {
		if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0)
			goto bad;
		sect = &obj->sect[i];
		if(is64) {
			ElfSectBytes64 b;

			werrstr("short read");
			if(Bread(f, &b, sizeof b) != sizeof b)
				goto bad;

			sect->name = (char*)(uintptr)e->e32(b.name);
			sect->type = e->e32(b.type);
			sect->flags = e->e64(b.flags);
			sect->addr = e->e64(b.addr);
			sect->off = e->e64(b.off);
			sect->size = e->e64(b.size);
			sect->link = e->e32(b.link);
			sect->info = e->e32(b.info);
			sect->align = e->e64(b.align);
			sect->entsize = e->e64(b.entsize);
		} else {
			ElfSectBytes b;

			werrstr("short read");
			if(Bread(f, &b, sizeof b) != sizeof b)
				goto bad;
		
			sect->name = (char*)(uintptr)e->e32(b.name);
			sect->type = e->e32(b.type);
			sect->flags = e->e32(b.flags);
			sect->addr = e->e32(b.addr);
			sect->off = e->e32(b.off);
			sect->size = e->e32(b.size);
			sect->link = e->e32(b.link);
			sect->info = e->e32(b.info);
			sect->align = e->e32(b.align);
			sect->entsize = e->e32(b.entsize);
		}
	}

	// read section string table and translate names
	if(obj->shstrndx >= obj->nsect) {
		werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect);
		goto bad;
	}
	sect = &obj->sect[obj->shstrndx];
	if(map(obj, sect) < 0)
		goto bad;
	for(i=0; i<obj->nsect; i++)
		if(obj->sect[i].name != nil)
			obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name;
	
	// load string table for symbols into memory.
	obj->symtab = section(obj, ".symtab");
	if(obj->symtab == nil) {
		// our work is done here - no symbols means nothing can refer to this file
		return;
	}
	if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) {
		diag("%s: elf object has symbol table with invalid string table link", pn);
		return;
	}
	obj->symstr = &obj->sect[obj->symtab->link];
	if(is64)
		obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64);
	else
		obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes);
	
	if(map(obj, obj->symtab) < 0)
		goto bad;
	if(map(obj, obj->symstr) < 0)
		goto bad;

	// load text and data segments into memory.
	// they are not as small as the section lists, but we'll need
	// the memory anyway for the symbol images, so we might
	// as well use one large chunk.
	
	// create symbols for mapped sections
	for(i=0; i<obj->nsect; i++) {
		sect = &obj->sect[i];
		if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc))
			continue;
		if(sect->type != ElfSectNobits && map(obj, sect) < 0)
			goto bad;
		
		name = smprint("%s(%s)", pkg, sect->name);
		s = linklookup(ctxt, name, ctxt->version);
		free(name);
		switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
		default:
			werrstr("unexpected flags for ELF section %s", sect->name);
			goto bad;
		case ElfSectFlagAlloc:
			s->type = SRODATA;
			break;
		case ElfSectFlagAlloc + ElfSectFlagWrite:
			if(sect->type == ElfSectNobits)
				s->type = SNOPTRBSS;
			else
				s->type = SNOPTRDATA;
			break;
		case ElfSectFlagAlloc + ElfSectFlagExec:
			s->type = STEXT;
			break;
		}
		if(strcmp(sect->name, ".got") == 0 ||
		   strcmp(sect->name, ".toc") == 0)
			s->type = SELFGOT;
		if(sect->type == ElfSectProgbits) {
			s->p = sect->base;
			s->np = sect->size;
		}
		s->size = sect->size;
		s->align = sect->align;
		sect->sym = s;
	}

	// enter sub-symbols into symbol table.
	// symbol 0 is the null symbol.
	symbols = malloc(obj->nsymtab * sizeof(symbols[0]));
	if(symbols == nil) {
		diag("out of memory");
		errorexit();
	}
	for(i=1; i<obj->nsymtab; i++) {
		if(readsym(obj, i, &sym, 1) < 0)
			goto bad;
		symbols[i] = sym.sym;
		if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone)
			continue;
		if(sym.shndx == ElfSymShnCommon) {
			s = sym.sym;
			if(s->size < sym.size)
				s->size = sym.size;
			if(s->type == 0 || s->type == SXREF)
				s->type = SNOPTRBSS;
			continue;
		}
		if(sym.shndx >= obj->nsect || sym.shndx == 0)
			continue;
		// even when we pass needSym == 1 to readsym, it might still return nil to skip some unwanted symbols
		if(sym.sym == S)
			continue;
		sect = obj->sect+sym.shndx;
		if(sect->sym == nil) {
			if(strncmp(sym.name, ".Linfo_string", 13) == 0) // clang does this
				continue;
			diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
			continue;
		}
		s = sym.sym;
		if(s->outer != S) {
			if(s->dupok)
				continue;
			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
			errorexit();
		}
		s->sub = sect->sym->sub;
		sect->sym->sub = s;
		s->type = sect->sym->type | (s->type&~SMASK) | SSUB;
		if(!(s->cgoexport & CgoExportDynamic))
			s->dynimplib = nil;  // satisfy dynimport
		s->value = sym.value;
		s->size = sym.size;
		s->outer = sect->sym;
		if(sect->sym->type == STEXT) {
			if(s->external && !s->dupok)
					diag("%s: duplicate definition of %s", pn, s->name);
			s->external = 1;
		}
		if(obj->machine == ElfMachPower64) {
			flag = sym.other >> 5;
			if(2 <= flag && flag <= 6)
				s->localentry = 1 << (flag - 2);
			else if(flag == 7)
				diag("%s: invalid sym.other 0x%x for %s", pn, sym.other, s->name);
		}
	}
Пример #25
0
void
elfdynhash(void)
{
	LSym *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 = linklookup(ctxt, ".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) {
		ctxt->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=ctxt->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->extname;
		hc = elfhash((uchar*)name);

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

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

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

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

	free(need);

	s = linklookup(ctxt, ".dynamic", 0);
	elfverneed = nfile;
	if(elfverneed) {
		elfwritedynentsym(s, DT_VERNEED, linklookup(ctxt, ".gnu.version_r", 0));
		elfwritedynent(s, DT_VERNEEDNUM, nfile);
		elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0));
	}

	if(thechar == '6') {
		sy = linklookup(ctxt, ".rela.plt", 0);
		if(sy->size > 0) {
			elfwritedynent(s, DT_PLTREL, DT_RELA);
			elfwritedynentsymsize(s, DT_PLTRELSZ, sy);
			elfwritedynentsym(s, DT_JMPREL, sy);
		}
	} else {
		sy = linklookup(ctxt, ".rel.plt", 0);
		if(sy->size > 0) {
			elfwritedynent(s, DT_PLTREL, DT_REL);
			elfwritedynentsymsize(s, DT_PLTRELSZ, sy);
			elfwritedynentsym(s, DT_JMPREL, sy);
		}
	}

	elfwritedynent(s, DT_NULL, 0);
}
Пример #26
0
Файл: pe.c Проект: rosrad/go-rep
static void
addimports(IMAGE_SECTION_HEADER *datsect)
{
	IMAGE_SECTION_HEADER *isect;
	uvlong n, oftbase, ftbase;
	vlong startoff, endoff;
	Imp *m;
	Dll *d;
	LSym* dynamic;
	
	startoff = cpos();
	dynamic = linklookup(ctxt, ".windynamic", 0);

	// skip import descriptor table (will write it later)
	n = 0;
	for(d = dr; d != nil; d = d->next)
		n++;
	cseek(startoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1));

	// write dll names
	for(d = dr; d != nil; d = d->next) {
		d->nameoff = cpos() - startoff;
		strput(d->name);
	}

	// write function names
	for(d = dr; d != nil; d = d->next) {
		for(m = d->ms; m != nil; m = m->next) {
			m->off = nextsectoff + cpos() - startoff;
			wputl(0); // hint
			strput(m->s->extname);
		}
	}
	
	// write OriginalFirstThunks
	oftbase = cpos() - startoff;
	n = cpos();
	for(d = dr; d != nil; d = d->next) {
		d->thunkoff = cpos() - n;
		for(m = d->ms; m != nil; m = m->next)
			put(m->off);
		put(0);
	}

	// add pe section and pad it at the end
	n = cpos() - startoff;
	isect = addpesection(".idata", n, n);
	isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
		IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
	chksectoff(isect, startoff);
	strnput("", isect->SizeOfRawData - n);
	endoff = cpos();

	// write FirstThunks (allocated in .data section)
	ftbase = dynamic->value - datsect->VirtualAddress - PEBASE;
	cseek(datsect->PointerToRawData + ftbase);
	for(d = dr; d != nil; d = d->next) {
		for(m = d->ms; m != nil; m = m->next)
			put(m->off);
		put(0);
	}
	
	// finally write import descriptor table
	cseek(startoff);
	for(d = dr; d != nil; d = d->next) {
		lputl(isect->VirtualAddress + oftbase + d->thunkoff);
		lputl(0);
		lputl(0);
		lputl(isect->VirtualAddress + d->nameoff);
		lputl(datsect->VirtualAddress + ftbase + d->thunkoff);
	}
	lputl(0); //end
	lputl(0);
	lputl(0);
	lputl(0);
	lputl(0);
	
	// update data directory
	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress;
	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
	dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE;
	dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;

	cseek(endoff);
}
Пример #27
0
void
adddynrel(LSym *s, Reloc *r)
{
	LSym *targ, *rela, *got;
	
	targ = r->sym;
	ctxt->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->type == SDYNIMPORT)
			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->type == SDYNIMPORT) {
			addpltsym(targ);
			r->sym = linklookup(ctxt, ".plt", 0);
			r->add += targ->plt;
		}
		return;
	
	case 256 + R_X86_64_GOTPCREL:
		if(targ->type != SDYNIMPORT) {
			// 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
		}
		addgotsym(targ);
		r->type = D_PCREL;
		r->sym = linklookup(ctxt, ".got", 0);
		r->add += 4;
		r->add += targ->got;
		return;
	
	case 256 + R_X86_64_64:
		if(targ->type == SDYNIMPORT)
			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->type == SDYNIMPORT)
			diag("unexpected reloc for dynamic symbol %s", targ->name);
		return;

	case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
		if(targ->type == SDYNIMPORT) {
			addpltsym(targ);
			r->sym = linklookup(ctxt, ".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->type == SDYNIMPORT)
			diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
		return;

	case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
		if(targ->type != SDYNIMPORT) {
			// 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->type != SDYNIMPORT)
			diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
		addgotsym(targ);
		r->type = D_PCREL;
		r->sym = linklookup(ctxt, ".got", 0);
		r->add += targ->got;
		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 = linklookup(ctxt, ".plt", 0);
		r->add = targ->plt;
		return;
	
	case D_ADDR:
		if(s->type == STEXT && iself) {
			// The code is asking for the address of an external
			// function.  We provide it with the address of the
			// correspondent GOT symbol.
			addgotsym(targ);
			r->sym = linklookup(ctxt, ".got", 0);
			r->add += targ->got;
			return;
		}
		if(s->type != SDATA)
			break;
		if(iself) {
			adddynsym(ctxt, targ);
			rela = linklookup(ctxt, ".rela", 0);
			addaddrplus(ctxt, rela, s, r->off);
			if(r->siz == 8)
				adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
			else
				adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
			adduint64(ctxt, 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(ctxt, targ);
			got = linklookup(ctxt, ".got", 0);
			s->type = got->type | SSUB;
			s->outer = got;
			s->sub = got->sub;
			got->sub = s;
			s->value = got->size;
			adduint64(ctxt, got, 0);
			adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
			r->type = 256;	// ignore during relocsym
			return;
		}
		break;
	}
	
	ctxt->cursym = s;
	diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
Пример #28
0
void
asmb(void)
{
	int32 magic;
	int i;
	vlong vl, symo, dwarfoff, machlink;
	Section *sect;
	LSym *sym;

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

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

	if(iself)
		asmbelfsetup();

	sect = segtext.sect;
	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
	codeblk(sect->vaddr, sect->len);
	for(sect = sect->next; sect != nil; sect = sect->next) {
		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
		datblk(sect->vaddr, sect->len);
	}

	if(segrodata.filelen > 0) {
		if(debug['v'])
			Bprint(&bso, "%5.2f rodatblk\n", cputime());
		Bflush(&bso);

		cseek(segrodata.fileoff);
		datblk(segrodata.vaddr, segrodata.filelen);
	}

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

	cseek(segdata.fileoff);
	datblk(segdata.vaddr, segdata.filelen);

	machlink = 0;
	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;

		machlink = domacholink();
	}

	switch(HEADTYPE) {
	default:
		diag("unknown header type %d", HEADTYPE);
	case Hplan9:
	case Helf:
		break;
	case Hdarwin:
		debug['8'] = 1;	/* 64-bit addresses */
		break;
	case Hlinux:
	case Hfreebsd:
	case Hnetbsd:
	case Hopenbsd:
	case Hdragonfly:
	case Hsolaris:
		debug['8'] = 1;	/* 64-bit addresses */
		break;
	case Hwindows:
		break;
	}

	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:
		case Hplan9:
		case Helf:
			debug['s'] = 1;
			symo = HEADR+segtext.len+segdata.filelen;
			break;
		case Hdarwin:
			symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
			break;
		case Hlinux:
		case Hfreebsd:
		case Hnetbsd:
		case Hopenbsd:
		case Hdragonfly:
		case Hsolaris:
			symo = rnd(HEADR+segtext.len, INITRND)+rnd(segrodata.len, INITRND)+segdata.filelen;
			symo = rnd(symo, INITRND);
			break;
		case Hwindows:
			symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
			symo = rnd(symo, PEFILEALIGN);
			break;
		}
		cseek(symo);
		switch(HEADTYPE) {
		default:
			if(iself) {
				cseek(symo);
				asmelfsym();
				cflush();
				cwrite(elfstrdat, elfstrsize);

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

				dwarfemitdebugsections();
				
				if(linkmode == LinkExternal)
					elfemitreloc();
			}
			break;
		case Hplan9:
			asmplan9sym();
			cflush();

			sym = linklookup(ctxt, "pclntab", 0);
			if(sym != nil) {
				lcsize = sym->np;
				for(i=0; i < lcsize; i++)
					cput(sym->p[i]);
				
				cflush();
			}
			break;
		case Hwindows:
			if(debug['v'])
			       Bprint(&bso, "%5.2f dwarf\n", cputime());

			dwarfemitdebugsections();
			break;
		case Hdarwin:
			if(linkmode == LinkExternal)
				machoemitreloc();
			break;
		}
	}

	if(debug['v'])
		Bprint(&bso, "%5.2f headr\n", cputime());
	Bflush(&bso);
	cseek(0L);
	switch(HEADTYPE) {
	default:
	case Hplan9:	/* plan9 */
		magic = 4*26*26+7;
		magic |= 0x00008000;		/* fat header */
		lputb(magic);			/* magic */
		lputb(segtext.filelen);			/* sizes */
		lputb(segdata.filelen);
		lputb(segdata.len - segdata.filelen);
		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;
	case Hdarwin:
		asmbmacho();
		break;
	case Hlinux:
	case Hfreebsd:
	case Hnetbsd:
	case Hopenbsd:
	case Hdragonfly:
	case Hsolaris:
		asmbelf(symo);
		break;
	case Hwindows:
		asmbpe();
		break;
	}
	cflush();
}
Пример #29
0
void
doelf(void)
{
	LSym *s, *shstrtab, *dynstr;

	if(!iself)
		return;

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

	addstring(shstrtab, "");
	addstring(shstrtab, ".text");
	addstring(shstrtab, ".noptrdata");
	addstring(shstrtab, ".data");
	addstring(shstrtab, ".bss");
	addstring(shstrtab, ".noptrbss");
	// generate .tbss section (except for OpenBSD where it's not supported)
	// for dynamic internal linker or external linking, so that various
	// binutils could correctly calculate PT_TLS size.
	// see http://golang.org/issue/5200.
	if(HEADTYPE != Hopenbsd)
	if(!debug['d'] || linkmode == LinkExternal)
		addstring(shstrtab, ".tbss");
	if(HEADTYPE == Hnetbsd)
		addstring(shstrtab, ".note.netbsd.ident");
	if(HEADTYPE == Hopenbsd)
		addstring(shstrtab, ".note.openbsd.ident");
	if(buildinfolen > 0)
		addstring(shstrtab, ".note.gnu.build-id");
	addstring(shstrtab, ".elfdata");
	addstring(shstrtab, ".rodata");
	addstring(shstrtab, ".typelink");
	addstring(shstrtab, ".gosymtab");
	addstring(shstrtab, ".gopclntab");
	
	if(linkmode == LinkExternal) {
		debug_s = debug['s'];
		debug['s'] = 0;
		debug['d'] = 1;

		if(thechar == '6') {
			addstring(shstrtab, ".rela.text");
			addstring(shstrtab, ".rela.rodata");
			addstring(shstrtab, ".rela.typelink");
			addstring(shstrtab, ".rela.gosymtab");
			addstring(shstrtab, ".rela.gopclntab");
			addstring(shstrtab, ".rela.noptrdata");
			addstring(shstrtab, ".rela.data");
		} else {
			addstring(shstrtab, ".rel.text");
			addstring(shstrtab, ".rel.rodata");
			addstring(shstrtab, ".rel.typelink");
			addstring(shstrtab, ".rel.gosymtab");
			addstring(shstrtab, ".rel.gopclntab");
			addstring(shstrtab, ".rel.noptrdata");
			addstring(shstrtab, ".rel.data");
		}
		// add a .note.GNU-stack section to mark the stack as non-executable
		addstring(shstrtab, ".note.GNU-stack");
	}

	if(flag_shared) {
		addstring(shstrtab, ".init_array");
		if(thechar == '6')
			addstring(shstrtab, ".rela.init_array");
		else
			addstring(shstrtab, ".rel.init_array");
	}

	if(!debug['s']) {
		addstring(shstrtab, ".symtab");
		addstring(shstrtab, ".strtab");
		dwarfaddshstrings(shstrtab);
	}
	addstring(shstrtab, ".shstrtab");

	if(!debug['d']) {	/* -d suppresses dynamic loader format */
		addstring(shstrtab, ".interp");
		addstring(shstrtab, ".hash");
		addstring(shstrtab, ".got");
		addstring(shstrtab, ".got.plt");
		addstring(shstrtab, ".dynamic");
		addstring(shstrtab, ".dynsym");
		addstring(shstrtab, ".dynstr");
		if(thechar == '6') {
			addstring(shstrtab, ".rela");
			addstring(shstrtab, ".rela.plt");
		} else {
			addstring(shstrtab, ".rel");
			addstring(shstrtab, ".rel.plt");
		}
		addstring(shstrtab, ".plt");
		addstring(shstrtab, ".gnu.version");
		addstring(shstrtab, ".gnu.version_r");

		/* dynamic symbol table - first entry all zeros */
		s = linklookup(ctxt, ".dynsym", 0);
		s->type = SELFROSECT;
		s->reachable = 1;
		if(thechar == '6')
			s->size += ELF64SYMSIZE;
		else
			s->size += ELF32SYMSIZE;

		/* dynamic string table */
		s = linklookup(ctxt, ".dynstr", 0);
		s->type = SELFROSECT;
		s->reachable = 1;
		if(s->size == 0)
			addstring(s, "");
		dynstr = s;

		/* relocation table */
		if(thechar == '6')
			s = linklookup(ctxt, ".rela", 0);
		else
			s = linklookup(ctxt, ".rel", 0);
		s->reachable = 1;
		s->type = SELFROSECT;

		/* global offset table */
		s = linklookup(ctxt, ".got", 0);
		s->reachable = 1;
		s->type = SELFSECT; // writable

		/* hash */
		s = linklookup(ctxt, ".hash", 0);
		s->reachable = 1;
		s->type = SELFROSECT;

		s = linklookup(ctxt, ".got.plt", 0);
		s->reachable = 1;
		s->type = SELFSECT; // writable

		s = linklookup(ctxt, ".plt", 0);
		s->reachable = 1;
		s->type = SELFRXSECT;
		
		elfsetupplt();
		
		if(thechar == '6')
			s = linklookup(ctxt, ".rela.plt", 0);
		else
			s = linklookup(ctxt, ".rel.plt", 0);
		s->reachable = 1;
		s->type = SELFROSECT;
		
		s = linklookup(ctxt, ".gnu.version", 0);
		s->reachable = 1;
		s->type = SELFROSECT;
		
		s = linklookup(ctxt, ".gnu.version_r", 0);
		s->reachable = 1;
		s->type = SELFROSECT;

		/* define dynamic elf table */
		s = linklookup(ctxt, ".dynamic", 0);
		s->reachable = 1;
		s->type = SELFSECT; // writable

		/*
		 * .dynamic table
		 */
		elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0));
		elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0));
		if(thechar == '6')
			elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
		else
			elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
		elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0));
		elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0));
		if(thechar == '6') {
			elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0));
			elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0));
			elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
		} else {
			elfwritedynentsym(s, DT_REL, linklookup(ctxt, ".rel", 0));
			elfwritedynentsymsize(s, DT_RELSZ, linklookup(ctxt, ".rel", 0));
			elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
		}
		if(rpath)
			elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
		
		elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0));

		// Solaris dynamic linker can't handle an empty .rela.plt if
		// DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
		// DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
		// size of .rel(a).plt section.
		elfwritedynent(s, DT_DEBUG, 0);

		// Do not write DT_NULL.  elfdynhash will finish it.
	}
}
Пример #30
0
Файл: ldelf.c Проект: 8l/golang
void
ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
{
	int32 base;
	uint64 add, info;
	char *name;
	int i, j, rela, is64, n;
	uchar hdrbuf[64];
	uchar *p;
	ElfHdrBytes *hdr;
	ElfObj *obj;
	ElfSect *sect, *rsect;
	ElfSym sym;
	Endian *e;
	Reloc *r, *rp;
	LSym *s;
	LSym **symbols;

	symbols = nil;

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

	ctxt->version++;
	base = Boffset(f);

	if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
		goto bad;
	hdr = (ElfHdrBytes*)hdrbuf;
	if(memcmp(hdr->ident, ElfMagic, 4) != 0)
		goto bad;
	switch(hdr->ident[5]) {
	case ElfDataLsb:
		e = &le;
		break;
	case ElfDataMsb:
		e = &be;
		break;
	default:
		goto bad;
	}

	// read header
	obj = mal(sizeof *obj);
	obj->e = e;
	obj->f = f;
	obj->base = base;
	obj->len = len;
	obj->name = pn;
	
	is64 = 0;
	if(hdr->ident[4] == ElfClass64) {
		ElfHdrBytes64* hdr;

		is64 = 1;
		hdr = (ElfHdrBytes64*)hdrbuf;
		obj->type = e->e16(hdr->type);
		obj->machine = e->e16(hdr->machine);
		obj->version = e->e32(hdr->version);
		obj->phoff = e->e64(hdr->phoff);
		obj->shoff = e->e64(hdr->shoff);
		obj->flags = e->e32(hdr->flags);
		obj->ehsize = e->e16(hdr->ehsize);
		obj->phentsize = e->e16(hdr->phentsize);
		obj->phnum = e->e16(hdr->phnum);
		obj->shentsize = e->e16(hdr->shentsize);
		obj->shnum = e->e16(hdr->shnum);
		obj->shstrndx = e->e16(hdr->shstrndx);
	} else {
		obj->type = e->e16(hdr->type);
		obj->machine = e->e16(hdr->machine);
		obj->version = e->e32(hdr->version);
		obj->entry = e->e32(hdr->entry);
		obj->phoff = e->e32(hdr->phoff);
		obj->shoff = e->e32(hdr->shoff);
		obj->flags = e->e32(hdr->flags);
		obj->ehsize = e->e16(hdr->ehsize);
		obj->phentsize = e->e16(hdr->phentsize);
		obj->phnum = e->e16(hdr->phnum);
		obj->shentsize = e->e16(hdr->shentsize);
		obj->shnum = e->e16(hdr->shnum);
		obj->shstrndx = e->e16(hdr->shstrndx);
	}
	obj->is64 = is64;
	
	if(hdr->ident[6] != obj->version)
		goto bad;

	if(e->e16(hdr->type) != ElfTypeRelocatable) {
		diag("%s: elf but not elf relocatable object", pn);
		return;
	}

	switch(thechar) {
	default:
		diag("%s: elf %s unimplemented", pn, thestring);
		return;
	case '5':
		if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) {
			diag("%s: elf object but not arm", pn);
			return;
		}
		break;
	case '6':
		if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) {
			diag("%s: elf object but not amd64", pn);
			return;
		}
		break;
	case '8':
		if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) {
			diag("%s: elf object but not 386", pn);
			return;
		}
		break;
	}

	// load section list into memory.
	obj->sect = mal(obj->shnum*sizeof obj->sect[0]);
	obj->nsect = obj->shnum;
	for(i=0; i<obj->nsect; i++) {
		if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0)
			goto bad;
		sect = &obj->sect[i];
		if(is64) {
			ElfSectBytes64 b;

			werrstr("short read");
			if(Bread(f, &b, sizeof b) != sizeof b)
				goto bad;

			sect->name = (char*)(uintptr)e->e32(b.name);
			sect->type = e->e32(b.type);
			sect->flags = e->e64(b.flags);
			sect->addr = e->e64(b.addr);
			sect->off = e->e64(b.off);
			sect->size = e->e64(b.size);
			sect->link = e->e32(b.link);
			sect->info = e->e32(b.info);
			sect->align = e->e64(b.align);
			sect->entsize = e->e64(b.entsize);
		} else {
			ElfSectBytes b;

			werrstr("short read");
			if(Bread(f, &b, sizeof b) != sizeof b)
				goto bad;
		
			sect->name = (char*)(uintptr)e->e32(b.name);
			sect->type = e->e32(b.type);
			sect->flags = e->e32(b.flags);
			sect->addr = e->e32(b.addr);
			sect->off = e->e32(b.off);
			sect->size = e->e32(b.size);
			sect->link = e->e32(b.link);
			sect->info = e->e32(b.info);
			sect->align = e->e32(b.align);
			sect->entsize = e->e32(b.entsize);
		}
	}

	// read section string table and translate names
	if(obj->shstrndx >= obj->nsect) {
		werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect);
		goto bad;
	}
	sect = &obj->sect[obj->shstrndx];
	if(map(obj, sect) < 0)
		goto bad;
	for(i=0; i<obj->nsect; i++)
		if(obj->sect[i].name != nil)
			obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name;
	
	// load string table for symbols into memory.
	obj->symtab = section(obj, ".symtab");
	if(obj->symtab == nil) {
		// our work is done here - no symbols means nothing can refer to this file
		return;
	}
	if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) {
		diag("%s: elf object has symbol table with invalid string table link", pn);
		return;
	}
	obj->symstr = &obj->sect[obj->symtab->link];
	if(is64)
		obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64);
	else
		obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes);
	
	if(map(obj, obj->symtab) < 0)
		goto bad;
	if(map(obj, obj->symstr) < 0)
		goto bad;

	// load text and data segments into memory.
	// they are not as small as the section lists, but we'll need
	// the memory anyway for the symbol images, so we might
	// as well use one large chunk.
	
	// create symbols for mapped sections
	for(i=0; i<obj->nsect; i++) {
		sect = &obj->sect[i];
		if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc))
			continue;
		if(sect->type != ElfSectNobits && map(obj, sect) < 0)
			goto bad;
		
		name = smprint("%s(%s)", pkg, sect->name);
		s = linklookup(ctxt, name, ctxt->version);
		free(name);
		switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
		default:
			werrstr("unexpected flags for ELF section %s", sect->name);
			goto bad;
		case ElfSectFlagAlloc:
			s->type = SRODATA;
			break;
		case ElfSectFlagAlloc + ElfSectFlagWrite:
			s->type = SNOPTRDATA;
			break;
		case ElfSectFlagAlloc + ElfSectFlagExec:
			s->type = STEXT;
			break;
		}
		if(sect->type == ElfSectProgbits) {
			s->p = sect->base;
			s->np = sect->size;
		}
		s->size = sect->size;
		s->align = sect->align;
		sect->sym = s;
	}

	// enter sub-symbols into symbol table.
	// symbol 0 is the null symbol.
	symbols = malloc(obj->nsymtab * sizeof(symbols[0]));
	if(symbols == nil) {
		diag("out of memory");
		errorexit();
	}
	for(i=1; i<obj->nsymtab; i++) {
		if(readsym(obj, i, &sym, 1) < 0)
			goto bad;
		symbols[i] = sym.sym;
		if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone)
			continue;
		if(sym.shndx == ElfSymShnCommon) {
			s = sym.sym;
			if(s->size < sym.size)
				s->size = sym.size;
			if(s->type == 0 || s->type == SXREF)
				s->type = SNOPTRBSS;
			continue;
		}
		if(sym.shndx >= obj->nsect || sym.shndx == 0)
			continue;
		// even when we pass needSym == 1 to readsym, it might still return nil to skip some unwanted symbols
		if(sym.sym == S)
			continue;
		sect = obj->sect+sym.shndx;
		if(sect->sym == nil) {
			if(strncmp(sym.name, ".Linfo_string", 13) == 0) // clang does this
				continue;
			diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
			continue;
		}
		s = sym.sym;
		if(s->outer != S) {
			if(s->dupok)
				continue;
			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
			errorexit();
		}
		s->sub = sect->sym->sub;
		sect->sym->sub = s;
		s->type = sect->sym->type | (s->type&~SMASK) | SSUB;
		if(!(s->cgoexport & CgoExportDynamic))
			s->dynimplib = nil;  // satisfy dynimport
		s->value = sym.value;
		s->size = sym.size;
		s->outer = sect->sym;
		if(sect->sym->type == STEXT) {
			if(s->external && !s->dupok)
					diag("%s: duplicate definition of %s", pn, s->name);
			s->external = 1;
		}
	}
	
	// Sort outer lists by address, adding to textp.
	// This keeps textp in increasing address order.
	for(i=0; i<obj->nsect; i++) {
		s = obj->sect[i].sym;
		if(s == S)
			continue;
		if(s->sub)
			s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
		if(s->type == STEXT) {
			if(s->onlist)
				sysfatal("symbol %s listed multiple times", s->name);
			s->onlist = 1;
			if(ctxt->etextp)
				ctxt->etextp->next = s;
			else
				ctxt->textp = s;
			ctxt->etextp = s;
			for(s = s->sub; s != S; s = s->sub) {
				if(s->onlist)
					sysfatal("symbol %s listed multiple times", s->name);
				s->onlist = 1;
				ctxt->etextp->next = s;
				ctxt->etextp = s;
			}
		}
	}

	// load relocations
	for(i=0; i<obj->nsect; i++) {
		rsect = &obj->sect[i];
		if(rsect->type != ElfSectRela && rsect->type != ElfSectRel)
			continue;
		if(rsect->info >= obj->nsect || obj->sect[rsect->info].base == nil)
			continue;
		sect = &obj->sect[rsect->info];
		if(map(obj, rsect) < 0)
			goto bad;
		rela = rsect->type == ElfSectRela;
		n = rsect->size/(4+4*is64)/(2+rela);
		r = mal(n*sizeof r[0]);
		p = rsect->base;
		for(j=0; j<n; j++) {
			add = 0;
			rp = &r[j];
			if(is64) {
				// 64-bit rel/rela
				rp->off = e->e64(p);
				p += 8;
				info = e->e64(p);
				p += 8;
				if(rela) {
					add = e->e64(p);
					p += 8;
				}
			} else {
				// 32-bit rel/rela
				rp->off = e->e32(p);
				p += 4;
				info = e->e32(p);
				info = info>>8<<32 | (info&0xff);	// convert to 64-bit info
				p += 4;
				if(rela) {
					add = e->e32(p);
					p += 4;
				}
			}
			if((info & 0xffffffff) == 0) { // skip R_*_NONE relocation
				j--;
				n--;
				continue;
			}
			if((info >> 32) == 0) { // absolute relocation, don't bother reading the null symbol
				rp->sym = S;
			} else {
				if(readsym(obj, info>>32, &sym, 0) < 0)
					goto bad;
				sym.sym = symbols[info>>32];
				if(sym.sym == nil) {
					werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
						sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
					goto bad;
				}
				rp->sym = sym.sym;
			}
			rp->type = reltype(pn, (uint32)info, &rp->siz);
			if(rela)
				rp->add = add;
			else {
				// load addend from image
				if(rp->siz == 4)
					rp->add = e->e32(sect->base+rp->off);
				else if(rp->siz == 8)
					rp->add = e->e64(sect->base+rp->off);
				else
					diag("invalid rela size %d", rp->siz);
			}
			if(rp->siz == 4)
				rp->add = (int32)rp->add;
			//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
		}