xref: /plan9/sys/src/cmd/aux/8prefix.c (revision 1ee3cffaa7e3c1b699746f1d489ecd9b6a7d4d76)
1 /*
2  * Pre-resolve references inside an object file.
3  * Mark such functions static so that linking with
4  * other object files can't get at them.
5  * Also rename "main".
6  */
7 #include <u.h>
8 #include <libc.h>
9 #include <bio.h>
10 #include "/sys/src/cmd/8c/8.out.h"
11 
12 typedef struct Sym Sym;
13 struct Sym
14 {
15 	char *name;
16 	char *newname;
17 	short type;
18 	short version;
19 	Sym *link;
20 };
21 
22 typedef struct Obj Obj;
23 struct Obj
24 {
25 	int fd;
26 	int version;
27 	uchar *bp;
28 	uchar *ep;
29 	char *name;
30 };
31 
32 enum
33 {
34 	NHASH = 10007
35 };
36 
37 Sym *hash[NHASH];
38 int nsymbol;
39 int renamemain = 1;
40 Sym *xsym[256];
41 int version = 1;
42 Obj **obj;
43 int nobj;
44 Biobuf bout;
45 char *prefix;
46 int verbose;
47 
48 void *emalloc(ulong);
49 Sym *lookup(char*, int);
50 Obj *openobj(char*);
51 void walkobj(Obj*, void (*fn)(int, Sym*, uchar*, int));
52 void walkobjs(void (*fn)(int, Sym*, uchar*, int));
53 void dump(int, Sym*, uchar*, int);
54 void nop(int, Sym*, uchar*, int);
55 void owrite(int, Sym*, uchar*, int);
56 int zaddr(uchar*, Sym**);
57 void renamesyms(int, Sym*, uchar*, int);
58 
59 void
usage(void)60 usage(void)
61 {
62 	fprint(2, "usage: 8prelink [-mv] prefix file.8...\n");
63 	exits("usage");
64 }
65 
66 void
main(int argc,char ** argv)67 main(int argc, char **argv)
68 {
69 	int i;
70 	Obj *o;
71 
72 	ARGBEGIN{
73 	case 'm':
74 		renamemain = 0;
75 		break;
76 	case 'v':
77 		verbose = 1;
78 		break;
79 	default:
80 		usage();
81 	}ARGEND
82 
83 	if(argc < 2)
84 		usage();
85 
86 	prefix = argv[0];
87 	argv++;
88 	argc--;
89 
90 	nobj = argc;
91 	obj = emalloc(nobj*sizeof obj[0]);
92 	for(i=0; i<argc; i++)
93 		obj[i] = openobj(argv[i]);
94 
95 	walkobjs(nop);	/* initialize symbol table */
96 	if(verbose)
97 		walkobjs(dump);
98 	walkobjs(renamesyms);
99 
100 	for(i=0; i<nobj; i++){
101 		o = obj[i];
102 		seek(o->fd, 0, 0);
103 		Binit(&bout, o->fd, OWRITE);
104 		walkobj(o, owrite);
105 		Bflush(&bout);
106 	}
107 	exits(0);
108 }
109 
110 void
renamesyms(int op,Sym * sym,uchar *,int)111 renamesyms(int op, Sym *sym, uchar*, int)
112 {
113 	if(sym && sym->version==0 && !sym->newname)
114 	switch(op){
115 	case AGLOBL:
116 	case AINIT:
117 	case ADATA:
118 	case ATEXT:
119 		if(!renamemain && strcmp(sym->name, "main") == 0)
120 			break;
121 		sym->newname = smprint("%s%s", prefix, sym->name);
122 		break;
123 	}
124 }
125 
126 void
dump(int op,Sym * sym,uchar *,int)127 dump(int op, Sym *sym, uchar*, int)
128 {
129 	if(sym && sym->version==0)
130 	switch(op){
131 	case AGLOBL:
132 	case AINIT:
133 	case ADATA:
134 	case ATEXT:
135 		print("%s\n", sym->name);
136 		break;
137 	}
138 }
139 
140 void
nop(int,Sym *,uchar *,int)141 nop(int, Sym*, uchar*, int)
142 {
143 }
144 
145 void
owrite(int op,Sym * sym,uchar * p,int l)146 owrite(int op, Sym *sym, uchar *p, int l)
147 {
148 	switch(op){
149 	case ASIGNAME:
150 		Bwrite(&bout, p, 4);
151 		p += 4;
152 		l -= 4;
153 	case ANAME:
154 		if(sym->newname){
155 			Bwrite(&bout, p, 4);
156 			Bwrite(&bout, sym->newname, strlen(sym->newname)+1);
157 			break;
158 		}
159 	default:
160 		Bwrite(&bout, p, l);
161 		break;
162 	}
163 }
164 
165 int
zaddr(uchar * p,Sym ** symp)166 zaddr(uchar *p, Sym **symp)
167 {
168 	int c, t;
169 
170 	t = p[0];
171 	c = 1;
172 	if(t & T_INDEX)
173 		c += 2;
174 	if(t & T_OFFSET)
175 		c += 4;
176 	if(t & T_SYM){
177 		if(symp)
178 			*symp = xsym[p[c]];
179 		c++;
180 	}
181 	if(t & T_FCONST)
182 		c += 8;
183 	else if(t & T_SCONST)
184 		c += NSNAME;
185 	if(t & T_TYPE)
186 		c++;
187 	return c;
188 }
189 
190 void*
emalloc(ulong n)191 emalloc(ulong n)
192 {
193 	void *v;
194 
195 	v = mallocz(n, 1);
196 	if(v == nil)
197 		sysfatal("out of memory");
198 	return v;
199 }
200 
201 Sym*
lookup(char * symb,int v)202 lookup(char *symb, int v)
203 {
204 	Sym *s;
205 	char *p;
206 	long h;
207 	int l, c;
208 
209 	h = v;
210 	for(p=symb; c = *p; p++)
211 		h = h+h+h + c;
212 	l = (p - symb) + 1;
213 	if(h < 0)
214 		h = ~h;
215 	h %= NHASH;
216 	for(s = hash[h]; s != nil; s = s->link)
217 		if(s->version == v)
218 		if(memcmp(s->name, symb, l) == 0)
219 			return s;
220 
221 	s = emalloc(sizeof *s);
222 	s->name = emalloc(l + 1);
223 	memmove(s->name, symb, l);
224 
225 	s->link = hash[h];
226 	s->type = 0;
227 	s->version = v;
228 	hash[h] = s;
229 	nsymbol++;
230 	return s;
231 }
232 
233 Obj*
openobj(char * name)234 openobj(char *name)
235 {
236 	Dir *d;
237 	Obj *obj;
238 
239 	obj = emalloc(sizeof *obj);
240 	obj->name = name;
241 	obj->version = version++;
242 	if((obj->fd = open(name, ORDWR)) < 0)
243 		sysfatal("open %s: %r", name);
244 	if((d = dirfstat(obj->fd)) == nil)
245 		sysfatal("dirfstat: %r");
246 	obj->bp = emalloc(d->length);
247 	if(readn(obj->fd, obj->bp, d->length) != d->length)
248 		sysfatal("read %s: %r", name);
249 	obj->ep = obj->bp+d->length;
250 	return obj;
251 }
252 
253 void
walkobjs(void (* fn)(int,Sym *,uchar *,int))254 walkobjs(void (*fn)(int, Sym*, uchar*, int))
255 {
256 	int i;
257 
258 	for(i=0; i<nobj; i++)
259 		walkobj(obj[i], fn);
260 }
261 
262 void
walkobj(Obj * obj,void (* fn)(int,Sym *,uchar *,int))263 walkobj(Obj *obj, void (*fn)(int, Sym*, uchar*, int))
264 {
265 	int op, type;
266 	Sym *sym;
267 	uchar *p, *p0;
268 
269 	for(p=obj->bp; p+4<=obj->ep; ){
270 		op = p[0] | (p[1]<<8);
271 		if(op <= AXXX || op >= ALAST)
272 			sysfatal("%s: opcode out of range - probably not a .8 file", obj->name);
273 		p0 = p;
274 		switch(op){
275 		case ASIGNAME:
276 			p += 4;	/* sign */
277 		case ANAME:
278 			type = p[2];
279 			sym = lookup((char*)p+4, type==D_STATIC ? obj->version : 0);
280 			xsym[p[3]] = sym;
281 			p += 4+strlen(sym->name)+1;
282 			fn(op, sym, p0, p-p0);
283 			break;
284 
285 		default:
286 			p += 6;
287 			p += zaddr(p, &sym);
288 			p += zaddr(p, nil);
289 			fn(op, sym, p0, p-p0);
290 			break;
291 		}
292 	}
293 }
294 
295