]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmach/obj.c
vt: implement snarf support
[plan9front.git] / sys / src / libmach / obj.c
1 /*
2  * obj.c
3  * routines universal to all object files
4  */
5 #include <u.h>
6 #include <libc.h>
7 #include <bio.h>
8 #include <ar.h>
9 #include <mach.h>
10 #include "obj.h"
11
12 #define islocal(t)      ((t)=='a' || (t)=='p')
13
14 enum
15 {
16         NNAMES  = 50,
17         MAXIS   = 8,            /* max length to determine if a file is a .? file */
18         MAXOFF  = 0x7fffffff,   /* larger than any possible local offset */
19         NHASH   = 1024,         /* must be power of two */
20         HASHMUL = 79L,
21 };
22
23 int     _is2(char*),            /* in [$OS].c */
24         _is5(char*),
25         _is6(char*),
26         _is7(char*),
27         _is8(char*),
28         _is9(char*),
29         _isk(char*),
30         _isq(char*),
31         _isv(char*),
32         _isu(char*),
33         _read2(Biobuf*, Prog*),
34         _read5(Biobuf*, Prog*),
35         _read6(Biobuf*, Prog*),
36         _read8(Biobuf*, Prog*),
37         _read9(Biobuf*, Prog*),
38         _readk(Biobuf*, Prog*),
39         _readq(Biobuf*, Prog*),
40         _readv(Biobuf*, Prog*),
41         _readu(Biobuf*, Prog*);
42
43 typedef struct Obj      Obj;
44 typedef struct Symtab   Symtab;
45
46 struct  Obj             /* functions to handle each intermediate (.$O) file */
47 {
48         char    *name;                          /* name of each $O file */
49         int     (*is)(char*);                   /* test for each type of $O file */
50         int     (*read)(Biobuf*, Prog*);        /* read for each type of $O file*/
51 };
52
53 static Obj      obj[] =
54 {                       /* functions to identify and parse each type of obj */
55         [Obj68020]      "68020 .2",     _is2, _read2,
56         [ObjAmd64]      "amd64 .6",     _is6, _read6,
57         [ObjArm]        "arm .5",       _is5, _read5,
58         [Obj386]        "386 .8",       _is8, _read8,
59         [ObjSparc]      "sparc .k",     _isk, _readk,
60         [ObjPower]      "power .q",     _isq, _readq,
61         [ObjMips]       "mips .v",      _isv, _readv,
62         [ObjSparc64]    "sparc64 .u",   _isu, _readu,
63         [ObjPower64]    "power64 .9",   _is9, _read9,
64         [Maxobjtype]    0, 0
65 };
66
67 struct  Symtab
68 {
69         struct  Sym     s;
70         struct  Symtab  *next;
71 };
72
73 static  Symtab *hash[NHASH];
74 static  Sym     *names[NNAMES]; /* working set of active names */
75
76 static  int     processprog(Prog*,int); /* decode each symbol reference */
77 static  void    objreset(void);
78 static  void    objlookup(int, char *, int, uint);
79 static  void    objupdate(int, int);
80
81 int
82 objtype(Biobuf *bp, char **name)
83 {
84         int i;
85         char buf[MAXIS];
86
87         if(Bread(bp, buf, MAXIS) < MAXIS)
88                 return -1;
89         Bseek(bp, -MAXIS, 1);
90         for (i = 0; i < Maxobjtype; i++) {
91                 if (obj[i].is && (*obj[i].is)(buf)) {
92                         if (name)
93                                 *name = obj[i].name;
94                         return i;
95                 }
96         }
97         return -1;
98 }
99
100 int
101 isar(Biobuf *bp)
102 {
103         int n;
104         char magbuf[SARMAG];
105
106         n = Bread(bp, magbuf, SARMAG);
107         if(n == SARMAG && strncmp(magbuf, ARMAG, SARMAG) == 0)
108                 return 1;
109         return 0;
110 }
111
112 /*
113  * determine what kind of object file this is and process it.
114  * return whether or not this was a recognized intermediate file.
115  */
116 int
117 readobj(Biobuf *bp, int objtype)
118 {
119         Prog p;
120
121         if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
122                 return 1;
123         objreset();
124         while ((*obj[objtype].read)(bp, &p))
125                 if (!processprog(&p, 1))
126                         return 0;
127         return 1;
128 }
129
130 int
131 readar(Biobuf *bp, int objtype, vlong end, int doautos)
132 {
133         Prog p;
134
135         if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
136                 return 1;
137         objreset();
138         while ((*obj[objtype].read)(bp, &p) && Boffset(bp) < end)
139                 if (!processprog(&p, doautos))
140                         return 0;
141         return 1;
142 }
143
144 /*
145  *      decode a symbol reference or definition
146  */
147 static  int
148 processprog(Prog *p, int doautos)
149 {
150         if(p->kind == aNone)
151                 return 1;
152         if(p->sym < 0 || p->sym >= NNAMES)
153                 return 0;
154         switch(p->kind)
155         {
156         case aName:
157                 if (!doautos)
158                 if(p->type != 'U' && p->type != 'b')
159                         break;
160                 objlookup(p->sym, p->id, p->type, p->sig);
161                 break;
162         case aText:
163                 objupdate(p->sym, 'T');
164                 break;
165         case aData:
166                 objupdate(p->sym, 'D');
167                 break;
168         default:
169                 break;
170         }
171         return 1;
172 }
173
174 /*
175  * find the entry for s in the symbol array.
176  * make a new entry if it is not already there.
177  */
178 static void
179 objlookup(int id, char *name, int type, uint sig)
180 {
181         long h;
182         char *cp;
183         Sym *s;
184         Symtab *sp;
185
186         s = names[id];
187         if(s && strcmp(s->name, name) == 0) {
188                 s->type = type;
189                 s->sig = sig;
190                 return;
191         }
192
193         h = *name;
194         for(cp = name+1; *cp; h += *cp++)
195                 h *= HASHMUL;
196         if(h < 0)
197                 h = ~h;
198         h &= (NHASH-1);
199         if (type == 'U' || type == 'b' || islocal(type)) {
200                 for(sp = hash[h]; sp; sp = sp->next)
201                         if(strcmp(sp->s.name, name) == 0) {
202                                 switch(sp->s.type) {
203                                 case 'T':
204                                 case 'D':
205                                 case 'U':
206                                         if (type == 'U') {
207                                                 names[id] = &sp->s;
208                                                 return;
209                                         }
210                                         break;
211                                 case 't':
212                                 case 'd':
213                                 case 'b':
214                                         if (type == 'b') {
215                                                 names[id] = &sp->s;
216                                                 return;
217                                         }
218                                         break;
219                                 case 'a':
220                                 case 'p':
221                                         if (islocal(type)) {
222                                                 names[id] = &sp->s;
223                                                 return;
224                                         }
225                                         break;
226                                 default:
227                                         break;
228                                 }
229                         }
230         }
231         sp = malloc(sizeof(Symtab));
232         sp->s.name = name;
233         sp->s.type = type;
234         sp->s.sig = sig;
235         sp->s.value = islocal(type) ? MAXOFF : 0;
236         names[id] = &sp->s;
237         sp->next = hash[h];
238         hash[h] = sp;
239         return;
240 }
241 /*
242  *      traverse the symbol lists
243  */
244 void
245 objtraverse(void (*fn)(Sym*, void*), void *pointer)
246 {
247         int i;
248         Symtab *s;
249
250         for(i = 0; i < NHASH; i++)
251                 for(s = hash[i]; s; s = s->next)
252                         (*fn)(&s->s, pointer);
253 }
254
255 /*
256  * update the offset information for a 'a' or 'p' symbol in an intermediate file
257  */
258 void
259 _offset(int id, vlong off)
260 {
261         Sym *s;
262
263         s = names[id];
264         if (s && s->name[0] && islocal(s->type) && s->value > off)
265                 s->value = off;
266 }
267
268 /*
269  * update the type of a global text or data symbol
270  */
271 static void 
272 objupdate(int id, int type)
273 {
274         Sym *s;
275
276         s = names[id];
277         if (s && s->name[0])
278                 if (s->type == 'U')
279                         s->type = type;
280                 else if (s->type == 'b')
281                         s->type = tolower(type);
282 }
283
284 /*
285  * look for the next file in an archive
286  */
287 int
288 nextar(Biobuf *bp, int offset, char *buf)
289 {
290         struct ar_hdr a;
291         int i, r;
292         long arsize;
293
294         if (offset&01)
295                 offset++;
296         Bseek(bp, offset, 0);
297         r = Bread(bp, &a, SAR_HDR);
298         if(r != SAR_HDR)
299                 return 0;
300         if(strncmp(a.fmag, ARFMAG, sizeof(a.fmag)))
301                 return -1;
302         for(i=0; i<sizeof(a.name) && i<SARNAME && a.name[i] != ' '; i++)
303                 buf[i] = a.name[i];
304         buf[i] = 0;
305         arsize = strtol(a.size, 0, 0);
306         if (arsize&1)
307                 arsize++;
308         return arsize + SAR_HDR;
309 }
310
311 static void
312 objreset(void)
313 {
314         int i;
315         Symtab *s, *n;
316
317         for(i = 0; i < NHASH; i++) {
318                 for(s = hash[i]; s; s = n) {
319                         n = s->next;
320                         free(s->s.name);
321                         free(s);
322                 }
323                 hash[i] = 0;
324         }
325         memset(names, 0, sizeof names);
326 }