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