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