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