xref: /plan9-contrib/sys/src/libdynld/dynld.c (revision 50f1557124e7462c91000f47378638e1dd5a6016)
1*50f15571SDavid du Colombier #include	<u.h>
2*50f15571SDavid du Colombier #include	<libc.h>
3*50f15571SDavid du Colombier #include	<a.out.h>
4*50f15571SDavid du Colombier #include	<dynld.h>
5*50f15571SDavid du Colombier 
6*50f15571SDavid du Colombier static ulong
get2(uchar * b)7*50f15571SDavid du Colombier get2(uchar *b)
8*50f15571SDavid du Colombier {
9*50f15571SDavid du Colombier 	return (b[0] << 8) | b[1];
10*50f15571SDavid du Colombier }
11*50f15571SDavid du Colombier 
12*50f15571SDavid du Colombier static ulong
get4(uchar * b)13*50f15571SDavid du Colombier get4(uchar *b)
14*50f15571SDavid du Colombier {
15*50f15571SDavid du Colombier 	return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
16*50f15571SDavid du Colombier }
17*50f15571SDavid du Colombier 
18*50f15571SDavid du Colombier static ulong
lgetbe(ulong l)19*50f15571SDavid du Colombier lgetbe(ulong l)
20*50f15571SDavid du Colombier {
21*50f15571SDavid du Colombier 	union {
22*50f15571SDavid du Colombier 		ulong	 l;
23*50f15571SDavid du Colombier 		uchar	c[4];
24*50f15571SDavid du Colombier 	} u;
25*50f15571SDavid du Colombier 	u.l = l;
26*50f15571SDavid du Colombier 	return get4(u.c);
27*50f15571SDavid du Colombier }
28*50f15571SDavid du Colombier 
29*50f15571SDavid du Colombier Dynsym*
dynfindsym(char * s,Dynsym * tab,int ntab)30*50f15571SDavid du Colombier dynfindsym(char *s, Dynsym *tab, int ntab)
31*50f15571SDavid du Colombier {
32*50f15571SDavid du Colombier 	int n, n2, d;
33*50f15571SDavid du Colombier 	Dynsym *t, *m;
34*50f15571SDavid du Colombier 
35*50f15571SDavid du Colombier 	t = tab;
36*50f15571SDavid du Colombier 	n = ntab;
37*50f15571SDavid du Colombier 	while(n > 0){
38*50f15571SDavid du Colombier 		n2 = n>>1;
39*50f15571SDavid du Colombier 		m = t+n2;
40*50f15571SDavid du Colombier 		d = strcmp(s, m->name);
41*50f15571SDavid du Colombier 		if(d < 0){
42*50f15571SDavid du Colombier 			n = n2;
43*50f15571SDavid du Colombier 			continue;
44*50f15571SDavid du Colombier 		}
45*50f15571SDavid du Colombier 		if(d > 0){
46*50f15571SDavid du Colombier 			t = m+1;
47*50f15571SDavid du Colombier 			n -= n2+1;
48*50f15571SDavid du Colombier 			continue;
49*50f15571SDavid du Colombier 		}
50*50f15571SDavid du Colombier 		return m;
51*50f15571SDavid du Colombier 	}
52*50f15571SDavid du Colombier 	return nil;
53*50f15571SDavid du Colombier }
54*50f15571SDavid du Colombier 
55*50f15571SDavid du Colombier void*
dynimport(Dynobj * o,char * name,ulong sig)56*50f15571SDavid du Colombier dynimport(Dynobj *o, char *name, ulong sig)
57*50f15571SDavid du Colombier {
58*50f15571SDavid du Colombier 	Dynsym *t;
59*50f15571SDavid du Colombier 
60*50f15571SDavid du Colombier 	t = dynfindsym(name, o->export, o->nexport);
61*50f15571SDavid du Colombier 	if(t == nil || sig != 0 && t->sig != 0 && t->sig != sig)
62*50f15571SDavid du Colombier 		return nil;
63*50f15571SDavid du Colombier 	return (void*)t->addr;
64*50f15571SDavid du Colombier }
65*50f15571SDavid du Colombier 
66*50f15571SDavid du Colombier int
dyntabsize(Dynsym * t)67*50f15571SDavid du Colombier dyntabsize(Dynsym *t)
68*50f15571SDavid du Colombier {
69*50f15571SDavid du Colombier 	int n;
70*50f15571SDavid du Colombier 
71*50f15571SDavid du Colombier 	for(n = 0; t->name != nil; t++)
72*50f15571SDavid du Colombier 		n++;
73*50f15571SDavid du Colombier 	return n;
74*50f15571SDavid du Colombier }
75*50f15571SDavid du Colombier 
76*50f15571SDavid du Colombier void
dynobjfree(Dynobj * o)77*50f15571SDavid du Colombier dynobjfree(Dynobj *o)
78*50f15571SDavid du Colombier {
79*50f15571SDavid du Colombier 	if(o != nil){
80*50f15571SDavid du Colombier 		free(o->base);
81*50f15571SDavid du Colombier 		free(o->import);
82*50f15571SDavid du Colombier 		free(o);
83*50f15571SDavid du Colombier 	}
84*50f15571SDavid du Colombier }
85*50f15571SDavid du Colombier 
86*50f15571SDavid du Colombier void
dynfreeimport(Dynobj * o)87*50f15571SDavid du Colombier dynfreeimport(Dynobj *o)
88*50f15571SDavid du Colombier {
89*50f15571SDavid du Colombier 	free(o->import);
90*50f15571SDavid du Colombier 	o->import = nil;
91*50f15571SDavid du Colombier 	o->nimport = 0;
92*50f15571SDavid du Colombier }
93*50f15571SDavid du Colombier 
94*50f15571SDavid du Colombier static char Ereloc[] = "error reading object file";
95*50f15571SDavid du Colombier 
96*50f15571SDavid du Colombier Dynobj*
dynloadgen(void * file,long (* rd)(void *,void *,long),vlong (* sk)(void *,vlong,int),void (* werr)(char *),Dynsym * tab,int ntab,ulong maxsize)97*50f15571SDavid du Colombier dynloadgen(void *file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int), void (*werr)(char*), Dynsym *tab, int ntab, ulong maxsize)
98*50f15571SDavid du Colombier {
99*50f15571SDavid du Colombier 	int i, m, n, ni, nr, relsize;
100*50f15571SDavid du Colombier 	ulong syms, entry, sig, p, a;
101*50f15571SDavid du Colombier 	uchar *base;
102*50f15571SDavid du Colombier 	Exec e;
103*50f15571SDavid du Colombier 	Dynsym *t;
104*50f15571SDavid du Colombier 	Dynobj *l;
105*50f15571SDavid du Colombier 	char *s, *err, buf[64];
106*50f15571SDavid du Colombier 	uchar *reldata, *rp, *ep;
107*50f15571SDavid du Colombier 	vlong off;
108*50f15571SDavid du Colombier 
109*50f15571SDavid du Colombier 	err = Ereloc;	/* default */
110*50f15571SDavid du Colombier 	off = (*sk)(file, 0, 1);
111*50f15571SDavid du Colombier 	l = mallocz(sizeof(Dynobj), 1);
112*50f15571SDavid du Colombier 	if(l == nil){
113*50f15571SDavid du Colombier 		err = "can't allocate Dynobj";
114*50f15571SDavid du Colombier 		goto Error;
115*50f15571SDavid du Colombier 	}
116*50f15571SDavid du Colombier 	if((*rd)(file, &e, sizeof(Exec)) != sizeof(Exec))
117*50f15571SDavid du Colombier 		goto Error;
118*50f15571SDavid du Colombier 	if(lgetbe(e.magic) != dynmagic()){
119*50f15571SDavid du Colombier 		err = "not dynamic object file or wrong platform";
120*50f15571SDavid du Colombier 		goto Error;
121*50f15571SDavid du Colombier 	}
122*50f15571SDavid du Colombier 	l->text = lgetbe(e.text);
123*50f15571SDavid du Colombier 	l->data = lgetbe(e.data);
124*50f15571SDavid du Colombier 	l->bss = lgetbe(e.bss);
125*50f15571SDavid du Colombier 	syms = lgetbe(e.syms)+lgetbe(e.spsz)+lgetbe(e.pcsz);
126*50f15571SDavid du Colombier 	entry = lgetbe(e.entry);
127*50f15571SDavid du Colombier 	l->size = l->text + l->data + l->bss;
128*50f15571SDavid du Colombier 	if(entry < 0 || entry >= l->size || entry & 3){
129*50f15571SDavid du Colombier 		err = "invalid export table pointer (entry point)";
130*50f15571SDavid du Colombier 		goto Error;
131*50f15571SDavid du Colombier 	}
132*50f15571SDavid du Colombier 	if(maxsize && l->size >= maxsize){
133*50f15571SDavid du Colombier 		snprint(buf, sizeof(buf), "%lud: object too big", l->size);
134*50f15571SDavid du Colombier 		err = buf;
135*50f15571SDavid du Colombier 		goto Error;
136*50f15571SDavid du Colombier 	}
137*50f15571SDavid du Colombier 
138*50f15571SDavid du Colombier 	l->base = base = malloc(l->size);
139*50f15571SDavid du Colombier 	if(base == nil){
140*50f15571SDavid du Colombier 		err = "out of memory: loading object file";
141*50f15571SDavid du Colombier 		goto Error;
142*50f15571SDavid du Colombier 	}
143*50f15571SDavid du Colombier 	l->export = (Dynsym*)(base+entry);
144*50f15571SDavid du Colombier 	if((*rd)(file, base, l->text+l->data) != l->text+l->data)
145*50f15571SDavid du Colombier 		goto Error;
146*50f15571SDavid du Colombier 	memset(base+l->text+l->data, 0, l->bss);
147*50f15571SDavid du Colombier 	if((*sk)(file, syms, 1) < 0)
148*50f15571SDavid du Colombier 		goto Error;
149*50f15571SDavid du Colombier 	if((*rd)(file, buf, 4) != 4)
150*50f15571SDavid du Colombier 		goto Error;
151*50f15571SDavid du Colombier 	relsize = get4((uchar*)buf);	/* always contains at least an import count (might be zero) */
152*50f15571SDavid du Colombier 	if(relsize < 4)
153*50f15571SDavid du Colombier 		goto Error;
154*50f15571SDavid du Colombier 	reldata = malloc(relsize);
155*50f15571SDavid du Colombier 	if(reldata == nil){
156*50f15571SDavid du Colombier 		err = "out of memory: relocation data";
157*50f15571SDavid du Colombier 		goto Error;
158*50f15571SDavid du Colombier 	}
159*50f15571SDavid du Colombier 	if((*rd)(file, reldata, relsize) != relsize)
160*50f15571SDavid du Colombier 		goto Error;
161*50f15571SDavid du Colombier 	rp = reldata;
162*50f15571SDavid du Colombier 	ep = reldata+relsize;
163*50f15571SDavid du Colombier 	ni = get4(rp);
164*50f15571SDavid du Colombier 	rp += 4;
165*50f15571SDavid du Colombier 	if(ni < 0 || ni > 8000)
166*50f15571SDavid du Colombier 		goto Error;	/* implausible size */
167*50f15571SDavid du Colombier 	l->nimport = ni;
168*50f15571SDavid du Colombier 	l->import = malloc(ni*sizeof(Dynsym*));
169*50f15571SDavid du Colombier 	if(l->import == nil){
170*50f15571SDavid du Colombier 		err = "out of memory: symbol table";
171*50f15571SDavid du Colombier 		goto Error;
172*50f15571SDavid du Colombier 	}
173*50f15571SDavid du Colombier 	for(i = 0; i < ni; i++){
174*50f15571SDavid du Colombier 		if(rp+5 > ep)
175*50f15571SDavid du Colombier 			goto Error;
176*50f15571SDavid du Colombier 		sig = get4(rp);
177*50f15571SDavid du Colombier 		rp += 4;
178*50f15571SDavid du Colombier 		s = (char*)rp;
179*50f15571SDavid du Colombier 		while(*rp++)
180*50f15571SDavid du Colombier 			if(rp >= ep)
181*50f15571SDavid du Colombier 				goto Error;
182*50f15571SDavid du Colombier 		t = dynfindsym(s, tab, ntab);
183*50f15571SDavid du Colombier 		if(t == nil){
184*50f15571SDavid du Colombier 			snprint(buf, sizeof(buf), "undefined symbol: %s", s);
185*50f15571SDavid du Colombier 			err = buf;
186*50f15571SDavid du Colombier 			goto Error;
187*50f15571SDavid du Colombier 		}
188*50f15571SDavid du Colombier 		if(sig != 0 && t->sig != 0 && t->sig != sig){
189*50f15571SDavid du Colombier 			snprint(buf, sizeof(buf), "signature mismatch: %s (%lux != %lux)", s, sig, t->sig);
190*50f15571SDavid du Colombier 			err = buf;
191*50f15571SDavid du Colombier 			goto Error;
192*50f15571SDavid du Colombier 		}
193*50f15571SDavid du Colombier 		l->import[i] = t;
194*50f15571SDavid du Colombier 	}
195*50f15571SDavid du Colombier 
196*50f15571SDavid du Colombier 	a = 0;
197*50f15571SDavid du Colombier 	if(rp+4 > ep)
198*50f15571SDavid du Colombier 		goto Error;
199*50f15571SDavid du Colombier 	nr = get4(rp);
200*50f15571SDavid du Colombier 	rp += 4;
201*50f15571SDavid du Colombier 	for(i = 0; i < nr; i++){
202*50f15571SDavid du Colombier 		if(rp >= ep)
203*50f15571SDavid du Colombier 			goto Error;
204*50f15571SDavid du Colombier 		m = *rp++;
205*50f15571SDavid du Colombier 		n = m>>6;
206*50f15571SDavid du Colombier 		if(rp+(1<<n) > ep)
207*50f15571SDavid du Colombier 			goto Error;
208*50f15571SDavid du Colombier 		switch(n){
209*50f15571SDavid du Colombier 		case 0:
210*50f15571SDavid du Colombier 			p = *rp++;
211*50f15571SDavid du Colombier 			break;
212*50f15571SDavid du Colombier 		case 1:
213*50f15571SDavid du Colombier 			p = get2(rp);
214*50f15571SDavid du Colombier 			rp += 2;
215*50f15571SDavid du Colombier 			break;
216*50f15571SDavid du Colombier 		case 2:
217*50f15571SDavid du Colombier 			p = get4(rp);
218*50f15571SDavid du Colombier 			rp += 4;
219*50f15571SDavid du Colombier 			break;
220*50f15571SDavid du Colombier 		default:
221*50f15571SDavid du Colombier 			goto Error;
222*50f15571SDavid du Colombier 		}
223*50f15571SDavid du Colombier 		a += p;
224*50f15571SDavid du Colombier 		err = dynreloc(base, a, m&0xf, l->import, ni);
225*50f15571SDavid du Colombier 		if(err != nil){
226*50f15571SDavid du Colombier 			snprint(buf, sizeof(buf), "dynamic object: %s", err);
227*50f15571SDavid du Colombier 			err = buf;
228*50f15571SDavid du Colombier 			goto Error;
229*50f15571SDavid du Colombier 		}
230*50f15571SDavid du Colombier 	}
231*50f15571SDavid du Colombier 	free(reldata);
232*50f15571SDavid du Colombier 
233*50f15571SDavid du Colombier 	/* could check relocated export table here */
234*50f15571SDavid du Colombier 	l->nexport = dyntabsize(l->export);
235*50f15571SDavid du Colombier 
236*50f15571SDavid du Colombier 	segflush(base, l->text);
237*50f15571SDavid du Colombier 
238*50f15571SDavid du Colombier 	return l;
239*50f15571SDavid du Colombier 
240*50f15571SDavid du Colombier Error:
241*50f15571SDavid du Colombier 	if(off >= 0)
242*50f15571SDavid du Colombier 		(*sk)(file, off, 0);	/* restore original file offset */
243*50f15571SDavid du Colombier 	(*werr)(err);
244*50f15571SDavid du Colombier 	dynobjfree(l);
245*50f15571SDavid du Colombier 	return nil;
246*50f15571SDavid du Colombier }
247*50f15571SDavid du Colombier 
248*50f15571SDavid du Colombier int
dynloadable(void * file,long (* rd)(void *,void *,long),vlong (* sk)(void *,vlong,int))249*50f15571SDavid du Colombier dynloadable(void* file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int))
250*50f15571SDavid du Colombier {
251*50f15571SDavid du Colombier 	long magic;
252*50f15571SDavid du Colombier 
253*50f15571SDavid du Colombier 	if((*rd)(file, &magic, sizeof(magic)) != sizeof(magic)){
254*50f15571SDavid du Colombier 		(*sk)(file, -(signed int)sizeof(magic), 1);
255*50f15571SDavid du Colombier 		return 0;
256*50f15571SDavid du Colombier 	}
257*50f15571SDavid du Colombier 	(*sk)(file, -(signed int)sizeof(magic), 1);
258*50f15571SDavid du Colombier 	return lgetbe(magic) == dynmagic();
259*50f15571SDavid du Colombier }
260