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