Example #1
0
void
cmdmap(Map *map)
{
	int i;
	char name[MAXSYM];

	extern char lastc;

	rdc();
	readsym(name);
	i = findseg(map, name);
	if (i < 0)	/* not found */
		error("Invalid map name");

	if (expr(0)) {
		if (strcmp(name, "text") == 0)
			textseg(expv, &fhdr);
		map->seg[i].b = expv;
	} else
		error("Invalid base address"); 
	if (expr(0))
		map->seg[i].e = expv;
	else
		error("Invalid end address"); 
	if (expr(0))
		map->seg[i].f = expv; 
	else
		error("Invalid file offset"); 
	if (rdc()=='?' && map == cormap) {
		if (fcor)
			close(fcor);
		fcor=fsym;
		corfil=symfil;
		cormap = symmap;
	} else if (lastc == '/' && map == symmap) {
		if (fsym)
			close(fsym);
		fsym=fcor;
		symfil=corfil;
		symmap=cormap;
	} else
		reread();
}
Example #2
0
item(int a)
{	/* name [ . local ] | number | . | ^  | <register | 'x | | */
	char	*base;
	char	savc;
	uvlong e;
	Symbol s;
	char gsym[MAXSYM], lsym[MAXSYM];

	readchar();
	if (isfileref()) {
		readfname(gsym);
		rdc();			/* skip white space */
		if (lastc == ':') {	/* it better be */
			rdc();		/* skip white space */
			if (!getnum(readchar))
				error("bad number");
			if (expv == 0)
				expv = 1;	/* file begins at line 1 */
			expv = file2pc(gsym, expv);
			if (expv == -1)
				error("%r");
			return 1;
		}
		error("bad file location");
	} else if (symchar(0)) {	
		readsym(gsym);
		if (lastc=='.') {
			readchar();	/* ugh */
			if (lastc == '.') {
				lsym[0] = '.';
				readchar();
				readsym(lsym+1);
			} else if (symchar(0)) {
				readsym(lsym);
			} else
				lsym[0] = 0;
			if (localaddr(cormap, gsym, lsym, &e, rget) < 0)
				error("%r");
			expv = e;
		}
		else {
			if (lookup(0, gsym, &s) == 0)
				error("symbol not found");
			expv = s.value;
		}
		reread();
	} else if (getnum(readchar)) {
		;
	} else if (lastc=='.') {	
		readchar();
		if (!symchar(0) && lastc != '.') {
			expv = dot;
		} else {
			if (findsym(rget(cormap, mach->pc), CTEXT, &s) == 0)
				error("no current function");
			if (lastc == '.') {
				lsym[0] = '.';
				readchar();
				readsym(lsym+1);
			} else
				readsym(lsym);
			if (localaddr(cormap, s.name, lsym, &e, rget) < 0)
				error("%r");
			expv = e;
		}	
		reread();
	} else if (lastc=='"') {
		expv=ditto;
	} else if (lastc=='+') {
		expv=inkdot(dotinc);
	} else if (lastc=='^') {
		expv=inkdot(-dotinc);
	} else if (lastc=='<') {
		savc=rdc();
		base = regname(savc);
		expv = rget(cormap, base);
	}
	else if (lastc=='\'')
		expv = ascval();
	else if (a)
		error("address expected");
	else {	
		reread();
		return(0);
	}
	return(1);
}
Example #3
0
void
ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
{
	char *name;
	int32 base;
	int i, j, l, numaux;
	PeObj *obj;
	PeSect *sect, *rsect;
	IMAGE_SECTION_HEADER sh;
	uchar symbuf[18];
	Sym *s;
	Reloc *r, *rp;
	PeSym *sym;

	USED(len);
	USED(pkg);
	if(debug['v'])
		Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
	
	sect = nil;
	version++;
	base = Boffset(f);
	
	obj = mal(sizeof *obj);
	obj->f = f;
	obj->base = base;
	obj->name = pn;
	// read header
	if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh)
		goto bad;
	// load section list
	obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]);
	obj->nsect = obj->fh.NumberOfSections;
	for(i=0; i < obj->fh.NumberOfSections; i++) {
		if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh)
			goto bad;
		obj->sect[i].size = obj->sect[i].sh.SizeOfRawData;
		obj->sect[i].name = (char*)obj->sect[i].sh.Name;
		// TODO return error if found .cormeta
	}
	// load string table
	Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
	if(Bread(f, &l, sizeof l) != sizeof l) 
		goto bad;
	obj->snames = mal(l);
	Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
	if(Bread(f, obj->snames, l) != l)
		goto bad;
	// read symbols
	obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
	obj->npesym = obj->fh.NumberOfSymbols;
	Bseek(f, base+obj->fh.PointerToSymbolTable, 0);
	for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) {
		Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0);
		if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf)
			goto bad;
		
		if((symbuf[0] == 0) && (symbuf[1] == 0) &&
			 (symbuf[2] == 0) && (symbuf[3] == 0)) {
			l = le32(&symbuf[4]);
			obj->pesym[i].name = (char*)&obj->snames[l];
		} else { // sym name length <= 8
			obj->pesym[i].name = mal(9);
			strncpy(obj->pesym[i].name, (char*)symbuf, 8);
			obj->pesym[i].name[8] = 0;
		}
		obj->pesym[i].value = le32(&symbuf[8]);
		obj->pesym[i].sectnum = le16(&symbuf[12]);
		obj->pesym[i].sclass = symbuf[16];
		obj->pesym[i].aux = symbuf[17];
		obj->pesym[i].type = le16(&symbuf[14]);
		numaux = obj->pesym[i].aux; 
		if (numaux < 0) 
			numaux = 0;
	}
	// create symbols for mapped sections
	for(i=0; i<obj->nsect; i++) {
		sect = &obj->sect[i];
		if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
			continue;
		if(map(obj, sect) < 0)
			goto bad;
		
		name = smprint("%s(%s)", pn, sect->name);
		s = lookup(name, version);
		free(name);
		switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
			IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata
				s->type = SRODATA;
				break;
			case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
				s->type = SBSS;
				break;
			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
				s->type = SDATA;
				break;
			case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text
				s->type = STEXT;
				break;
			default:
				werrstr("unexpected flags for PE section %s", sect->name);
				goto bad;
		}
		s->p = sect->base;
		s->np = sect->size;
		s->size = sect->size;
		if(s->type == STEXT) {
			if(etextp)
				etextp->next = s;
			else
				textp = s;
			etextp = s;
		}
		sect->sym = s;
		if(strcmp(sect->name, ".rsrc") == 0)
			setpersrc(sect->sym);
	}
	
	// load relocations
	for(i=0; i<obj->nsect; i++) {
		rsect = &obj->sect[i];
		if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0)
			continue;
		if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
			continue;
		r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
		Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
		for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
			rp = &r[j];
			if(Bread(f, symbuf, 10) != 10)
				goto bad;
			
			uint32 rva, symindex;
			uint16 type;
			rva = le32(&symbuf[0]);
			symindex = le32(&symbuf[4]);
			type = le16(&symbuf[8]);
			if(readsym(obj, symindex, &sym) < 0)
				goto bad;
			if(sym->sym == nil) {
				werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type);
				goto bad;
			}
			rp->sym = sym->sym;
			rp->siz = 4;
			rp->off = rva;
			switch(type) {
				default:
					diag("%s: unknown relocation type %d;", pn, type);
				case IMAGE_REL_I386_REL32:
				case IMAGE_REL_AMD64_REL32:
				case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
				case IMAGE_REL_AMD64_ADDR32NB:
					rp->type = D_PCREL;
					rp->add = le32(rsect->base+rp->off);
					break;
				case IMAGE_REL_I386_DIR32NB:
				case IMAGE_REL_I386_DIR32:
					rp->type = D_ADDR;
					// load addend from image
					rp->add = le32(rsect->base+rp->off);
					break;
				case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
					rp->siz = 8;
					rp->type = D_ADDR;
					// load addend from image
					rp->add = le64(rsect->base+rp->off);
					break;
			}
		}
		qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
		
		s = rsect->sym;
		s->r = r;
		s->nr = rsect->sh.NumberOfRelocations;
	}
	
	// enter sub-symbols into symbol table.
	for(i=0; i<obj->npesym; i++) {
		if(obj->pesym[i].name == 0)
			continue;
		if(obj->pesym[i].name[0] == '.') //skip section
			continue;
		if(obj->pesym[i].sectnum > 0) {
			sect = &obj->sect[obj->pesym[i].sectnum-1];
			if(sect->sym == 0)
				continue;
		}
		if(readsym(obj, i, &sym) < 0)
			goto bad;
	
		s = sym->sym;
		if(sym->sectnum == 0) {// extern
			if(s->type == SDYNIMPORT)
				s->plt = -2; // flag for dynimport in PE object files.
			if (s->type == SXREF && sym->value > 0) {// global data
				s->type = SDATA; 
				s->size = sym->value;
			}
			continue;
		} else if (sym->sectnum > 0) {
			sect = &obj->sect[sym->sectnum-1];
			if(sect->sym == 0)
				diag("%s: %s sym == 0!", pn, s->name);
		} else {
			diag("%s: %s sectnum < 0!", pn, s->name);
		}

		if(sect == nil) 
			return;
		s->sub = sect->sym->sub;
		sect->sym->sub = s;
		s->type = sect->sym->type | SSUB;
		s->value = sym->value;
		s->size = 4;
		s->outer = sect->sym;
		if(sect->sym->type == STEXT) {
			Prog *p;
	
			if(s->text != P)
				diag("%s: duplicate definition of %s", pn, s->name);
			// build a TEXT instruction with a unique pc
			// just to make the rest of the linker happy.
			p = prg();
			p->as = ATEXT;
			p->from.type = D_EXTERN;
			p->from.sym = s;
			p->textflag = 7;
			p->to.type = D_CONST;
			p->link = nil;
			p->pc = pc++;
			s->text = p;
	
			etextp->next = s;
			etextp = s;
		}
	}

	return;
bad:
	diag("%s: malformed pe file: %r", pn);
}
Example #4
0
File: ldelf.c Project: 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);
		}
	}
Example #5
0
File: ldelf.c Project: 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);
		}
Example #6
0
void
ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
{
	char *name;
	int32 base;
	uint32 l;
	int i, j, numaux;
	PeObj *obj;
	PeSect *sect, *rsect;
	IMAGE_SECTION_HEADER sh;
	uchar symbuf[18];
	LSym *s;
	Reloc *r, *rp;
	PeSym *sym;

	USED(len);
	if(debug['v'])
		Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
	
	sect = nil;
	ctxt->version++;
	base = Boffset(f);
	
	obj = mal(sizeof *obj);
	obj->f = f;
	obj->base = base;
	obj->name = pn;
	// read header
	if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh)
		goto bad;
	// load section list
	obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]);
	obj->nsect = obj->fh.NumberOfSections;
	for(i=0; i < obj->fh.NumberOfSections; i++) {
		if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh)
			goto bad;
		obj->sect[i].size = obj->sect[i].sh.SizeOfRawData;
		obj->sect[i].name = (char*)obj->sect[i].sh.Name;
		// TODO return error if found .cormeta
	}
	// load string table
	Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
	if(Bread(f, symbuf, 4) != 4) 
		goto bad;
	l = le32(symbuf);
	obj->snames = mal(l);
	Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
	if(Bread(f, obj->snames, l) != l)
		goto bad;
	// read symbols
	obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
	obj->npesym = obj->fh.NumberOfSymbols;
	Bseek(f, base+obj->fh.PointerToSymbolTable, 0);
	for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) {
		Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0);
		if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf)
			goto bad;
		
		if((symbuf[0] == 0) && (symbuf[1] == 0) &&
			 (symbuf[2] == 0) && (symbuf[3] == 0)) {
			l = le32(&symbuf[4]);
			obj->pesym[i].name = (char*)&obj->snames[l];
		} else { // sym name length <= 8
			obj->pesym[i].name = mal(9);
			strncpy(obj->pesym[i].name, (char*)symbuf, 8);
			obj->pesym[i].name[8] = 0;
		}
		obj->pesym[i].value = le32(&symbuf[8]);
		obj->pesym[i].sectnum = le16(&symbuf[12]);
		obj->pesym[i].sclass = symbuf[16];
		obj->pesym[i].aux = symbuf[17];
		obj->pesym[i].type = le16(&symbuf[14]);
		numaux = obj->pesym[i].aux; 
		if (numaux < 0) 
			numaux = 0;
	}
	// create symbols for mapped sections
	for(i=0; i<obj->nsect; i++) {
		sect = &obj->sect[i];
		if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
			continue;

		if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) {
			// This has been seen for .idata sections, which we
			// want to ignore.  See issues 5106 and 5273.
			continue;
		}

		if(map(obj, sect) < 0)
			goto bad;
		
		name = smprint("%s(%s)", pkg, sect->name);
		s = linklookup(ctxt, name, ctxt->version);
		free(name);
		switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
			IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata
				s->type = SRODATA;
				break;
			case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
				s->type = SBSS;
				break;
			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
				s->type = SDATA;
				break;
			case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text
				s->type = STEXT;
				break;
			default:
				werrstr("unexpected flags %#08ux for PE section %s", sect->sh.Characteristics, sect->name);
				goto bad;
		}
		s->p = sect->base;
		s->np = sect->size;
		s->size = sect->size;
		sect->sym = s;
		if(strcmp(sect->name, ".rsrc") == 0)
			setpersrc(sect->sym);
	}
	
	// load relocations
	for(i=0; i<obj->nsect; i++) {
		rsect = &obj->sect[i];
		if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0)
			continue;
		if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
			continue;
		if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) {
			// This has been seen for .idata sections, which we
			// want to ignore.  See issues 5106 and 5273.
			continue;
		}
		r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
		Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
		for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
			rp = &r[j];
			if(Bread(f, symbuf, 10) != 10)
				goto bad;
			
			uint32 rva, symindex;
			uint16 type;
			rva = le32(&symbuf[0]);
			symindex = le32(&symbuf[4]);
			type = le16(&symbuf[8]);
			if(readsym(obj, symindex, &sym) < 0)
				goto bad;
			if(sym->sym == nil) {
				werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type);
				goto bad;
			}
			rp->sym = sym->sym;
			rp->siz = 4;
			rp->off = rva;
			switch(type) {
				default:
					diag("%s: unknown relocation type %d;", pn, type);
				case IMAGE_REL_I386_REL32:
				case IMAGE_REL_AMD64_REL32:
				case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
				case IMAGE_REL_AMD64_ADDR32NB:
					rp->type = R_PCREL;
					rp->add = (int32)le32(rsect->base+rp->off);
					break;
				case IMAGE_REL_I386_DIR32NB:
				case IMAGE_REL_I386_DIR32:
					rp->type = R_ADDR;
					// load addend from image
					rp->add = (int32)le32(rsect->base+rp->off);
					break;
				case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
					rp->siz = 8;
					rp->type = R_ADDR;
					// load addend from image
					rp->add = le64(rsect->base+rp->off);
					break;
			}
			// ld -r could generate multiple section symbols for the
			// same section but with different values, we have to take
			// that into account
			if (obj->pesym[symindex].name[0] == '.')
					rp->add += obj->pesym[symindex].value;
		}
		qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
		
		s = rsect->sym;
		s->r = r;
		s->nr = rsect->sh.NumberOfRelocations;
	}
	
	// enter sub-symbols into symbol table.
	for(i=0; i<obj->npesym; i++) {
		if(obj->pesym[i].name == 0)
			continue;
		if(obj->pesym[i].name[0] == '.') //skip section
			continue;
		if(obj->pesym[i].sectnum > 0) {
			sect = &obj->sect[obj->pesym[i].sectnum-1];
			if(sect->sym == 0)
				continue;
		}
		if(readsym(obj, i, &sym) < 0)
			goto bad;
	
		s = sym->sym;
		if(sym->sectnum == 0) {// extern
			if(s->type == SDYNIMPORT)
				s->plt = -2; // flag for dynimport in PE object files.
			if (s->type == SXREF && sym->value > 0) {// global data
				s->type = SDATA; 
				s->size = sym->value;
			}
			continue;
		} else if (sym->sectnum > 0) {
			sect = &obj->sect[sym->sectnum-1];
			if(sect->sym == 0)
				diag("%s: %s sym == 0!", pn, s->name);
		} else {
			diag("%s: %s sectnum < 0!", pn, s->name);
		}

		if(sect == nil) 
			return;

		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 | SSUB;
		s->value = sym->value;
		s->size = 4;
		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;
			}
		}
	}

	return;
bad:
	diag("%s: malformed pe file: %r", pn);
}