Charles.Forsyth20060303a828770d19 years agoHistory
258 lines · 4.6 KB · C
RawDownload
#include	"lib9.h"#include	<a.out.h>#include	<dynld.h> static ulongget2(uchar *b){	return (b[0] << 8) | b[1];} static ulongget4(uchar *b){	return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];} static ulonglgetbe(ulong l){	union {		ulong	 l;		uchar	c[4];	} u;	u.l = l;	return get4(u.c);} Dynsym*dynfindsym(char *s, Dynsym *tab, int ntab){	int n, n2, d;	Dynsym *t, *m; 	t = tab;	n = ntab;	while(n > 0){		n2 = n>>1;		m = t+n2;		d = strcmp(s, m->name);		if(d < 0){			n = n2;			continue;		}		if(d > 0){			t = m+1;			n -= n2+1;			continue;		}		return m;	}	return nil;} void*dynimport(Dynobj *o, char *name, ulong sig){	Dynsym *t; 	t = dynfindsym(name, o->export, o->nexport);	if(t == nil || sig != 0 && t->sig != 0 && t->sig != sig)		return nil;	return (void*)t->addr;} intdyntabsize(Dynsym *t){	int n; 	for(n = 0; t->name != nil; t++)		n++;	return n;} voiddynobjfree(Dynobj *o){	if(o != nil){		free(o->base);		free(o->import);		free(o);	}} voiddynfreeimport(Dynobj *o){	free(o->import);	o->import = nil;	o->nimport = 0;} static char Ereloc[] = "error reading object file"; Dynobj*dynloadgen(void *file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int), void (*werr)(char*), Dynsym *tab, int ntab, ulong maxsize){	int i, m, n, ni, nr, relsize;	ulong syms, entry, sig, p, a;	uchar *base;	Exec e;	Dynsym *t;	Dynobj *l;	char *s, *err, buf[64];	uchar *reldata, *rp, *ep;	vlong off; 	err = Ereloc;	/* default */	off = (*sk)(file, 0, 1);	l = mallocz(sizeof(Dynobj), 1);	if(l == nil){		err = "can't allocate Dynobj";		goto Error;	}	if((*rd)(file, &e, sizeof(Exec)) != sizeof(Exec))		goto Error;	if(lgetbe(e.magic) != dynmagic()){		err = "not dynamic object file or wrong platform";		goto Error;	}	l->text = lgetbe(e.text);	l->data = lgetbe(e.data);	l->bss = lgetbe(e.bss);	syms = lgetbe(e.syms)+lgetbe(e.spsz)+lgetbe(e.pcsz);	entry = lgetbe(e.entry);	l->size = l->text + l->data + l->bss;	if(entry < 0 || entry >= l->size || entry & 3){		err = "invalid export table pointer (entry point)";		goto Error;	}	if(maxsize && l->size >= maxsize){		snprint(buf, sizeof(buf), "%lud: object too big", l->size);		err = buf;		goto Error;	} 	l->base = base = malloc(l->size);	if(base == nil){		err = "out of memory: loading object file";		goto Error;	}	l->export = (Dynsym*)(base+entry);	if((*rd)(file, base, l->text+l->data) != l->text+l->data)		goto Error;	memset(base+l->text+l->data, 0, l->bss);	if((*sk)(file, syms, 1) < 0)		goto Error;	if((*rd)(file, buf, 4) != 4)		goto Error;	relsize = get4((uchar*)buf);	/* always contains at least an import count (might be zero) */	if(relsize < 4)		goto Error;	reldata = malloc(relsize);	if(reldata == nil){		err = "out of memory: relocation data";		goto Error;	}	if((*rd)(file, reldata, relsize) != relsize)		goto Error;	rp = reldata;	ep = reldata+relsize;	ni = get4(rp);	rp += 4;	if(ni < 0 || ni > 8000)		goto Error;	/* implausible size */	l->nimport = ni;	l->import = malloc(ni*sizeof(Dynsym*));	if(l->import == nil){		err = "out of memory: symbol table";		goto Error;	}	for(i = 0; i < ni; i++){		if(rp+5 > ep)			goto Error;		sig = get4(rp);		rp += 4;		s = (char*)rp;		while(*rp++)			if(rp >= ep)				goto Error;		t = dynfindsym(s, tab, ntab);		if(t == nil){			snprint(buf, sizeof(buf), "undefined symbol: %s", s);			err = buf;			goto Error;		}		if(sig != 0 && t->sig != 0 && t->sig != sig){			snprint(buf, sizeof(buf), "signature mismatch: %s (%lux != %lux)", s, sig, t->sig);			err = buf;			goto Error;		}		l->import[i] = t;	} 	a = 0;	if(rp+4 > ep)		goto Error;	nr = get4(rp);	rp += 4;	for(i = 0; i < nr; i++){		if(rp >= ep)			goto Error;		m = *rp++;		n = m>>6;		if(rp+(1<<n) > ep)			goto Error;		switch(n){		case 0:			p = *rp++;			break;		case 1:			p = get2(rp);			rp += 2;			break;		case 2:			p = get4(rp);			rp += 4;			break;		default:			goto Error;		}		a += p;		err = dynreloc(base, a, m&0xf, l->import, ni);		if(err != nil){			snprint(buf, sizeof(buf), "dynamic object: %s", err);			err = buf;			goto Error;		}	}	free(reldata); 	/* could check relocated export table here */	l->nexport = dyntabsize(l->export); 	segflush(base, l->text); 	return l; Error:	if(off >= 0)		(*sk)(file, off, 0);	/* restore original file offset */	(*werr)(err);	dynobjfree(l);	return nil;} intdynloadable(void* file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int)){	long magic; 	if((*rd)(file, &magic, sizeof(magic)) != sizeof(magic)){		(*sk)(file, -(signed int)sizeof(magic), 1);		return 0;	}	(*sk)(file, -(signed int)sizeof(magic), 1);	return lgetbe(magic) == dynmagic();}