예제 #1
0
파일: ldpe.c 프로젝트: funkygao/govtil
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);
}
예제 #2
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);
}