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