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