xref: /inferno-os/utils/5cv/5cv.c (revision 2b69dba5038ffd0b59cf30a4c44bce549e5097f8)
1 #include <lib9.h>
2 #include <bio.h>
3 #include <mach.h>
4 
5 char *Cmd;
6 int Hdrtype;
7 int Strip;
8 long Txtaddr = -1;
9 
10 int Ofd;
11 int Ifd;
12 Fhdr Ihdr;
13 
14 int Debug;
15 
16 static void	get_file(char *);
17 static void	put_file(char *);
18 static void	Usage(char *);
19 static long	strxtol(char *);
20 
21 char	*fail	= "error";
22 
23 void
24 main(int argc, char	*argv[])
25 {
26 	char *ifile, *ofile;
27 
28 	Cmd = argv[0];
29 	Hdrtype = 2;
30 
31 	ARGBEGIN {
32 	/*
33 	 * Options without args
34 	 */
35 	case 's':
36 		Strip = 1;
37 		break;
38 	/*
39 	 * Options with args
40 	 */
41 	case 'T':
42 		Txtaddr = strxtol(ARGF());
43 		break;
44 	case 'H':
45 		Hdrtype = strxtol(ARGF());
46 		break;
47 	case 'D':
48 		Debug |= strxtol(ARGF());
49 		break;
50 	default:
51 		Usage("Invalid option");
52 	} ARGEND
53 
54 	if (argc != 2)
55 		Usage("Wrong number of arguments");
56 
57 	ifile = argv[0];
58 	ofile = argv[1];
59 
60 	get_file(ifile);
61 	put_file(ofile);
62 	exits(0);
63 }
64 
65 char usagemsg[] =
66 "Usage: %s  options infile outfile\n\t options (for outfile): -H[123456] -s -T<text> \n";
67 
68 static void
69 Usage(char *msg)
70 {
71 	fprint(2, "***Error: %s\n", msg);
72 	fprint(2, usagemsg, Cmd);
73 	exits("usage");
74 }
75 
76 static long
77 strxtol(char *s)
78 {
79 	char *es;
80 	int base = 0;
81 	long r;
82 
83 	if (*s == '0')
84 		if (*++s == 'x'){
85 			base = 16;
86 			s++;
87 		}
88 		else
89 			base = 8;
90 	r = strtol(s, &es, base);
91 	if (*es)
92 		Usage("bad number");
93 	return(r);
94 }
95 
96 static void
97 get_file(char *ifile)
98 {
99 	int h;
100 	int d;
101 
102 	Ifd = open(ifile, OREAD);
103 	if (Ifd < 0) {
104 		fprint(2, "5cv: open %s: %r\n", ifile);
105 		exits("open");
106 	}
107 	h = crackhdr(Ifd, &Ihdr);
108 	if (!h || Debug){
109 		fprint(2, "Crackhdr: %d, type: %d, name: %s\n", h, Ihdr.type, Ihdr.name);
110 		fprint(2, "txt %llux, ent %llux, txtsz %lux, dataddr %llux\n",
111 			Ihdr.txtaddr, Ihdr.entry, Ihdr.txtsz, Ihdr.dataddr);
112 	}
113 	if (!h)
114 		Usage("File type not recognized");
115 	machbytype(Ihdr.type);
116 	if (Debug)
117 		fprint(2, "name: <%s> pgsize:%ux\n", mach->name, mach->pgsize);
118 
119 	if (Txtaddr != -1){
120 		d = Txtaddr - Ihdr.txtaddr;
121 		Ihdr.txtaddr += d;
122 		Ihdr.dataddr = Ihdr.txtaddr + Ihdr.txtsz;
123 	}
124 }
125 
126 char Wbuf[128];
127 char *wp = Wbuf;
128 
129 void
130 lput(long l)
131 {
132 	wp[0] = l>>24;
133 	wp[1] = l>>16;
134 	wp[2] = l>>8;
135 	wp[3] = l;
136 	wp += 4;
137 }
138 
139 void
140 lputl(long l)
141 {
142 	wp[3] = l>>24;
143 	wp[2] = l>>16;
144 	wp[1] = l>>8;
145 	wp[0] = l;
146 	wp += 4;
147 }
148 
149 static void
150 copyseg(long sz)
151 {
152 	char	buf[1024];
153 
154 	while (sz > 0){
155 		long n;
156 		long r;
157 
158 		n = sz;
159 		if (n > sizeof buf)
160 			n = sizeof buf;
161 		sz -= n;
162 
163 		if ((r = read(Ifd, buf, n)) != n){
164 			fprint(2, "%ld = read(...%ld) at %ld\n", r, n, (long)seek(Ifd, 0, 1));
165 			perror("Premature eof");
166 			exits(fail);
167 		}
168 		if ((r = write(Ofd, buf, n)) != n){
169 			fprint(2, "%ld = write(...%ld)\n", r, n);
170 			perror("Write error!");
171 			exits(fail);
172 		}
173 	}
174 }
175 
176 static void
177 zero(long sz)
178 {
179 	char	buf[1024];
180 
181 	memset(buf, 0, sizeof buf);
182 	while (sz > 0){
183 		long n;
184 		long r;
185 
186 		n = sz;
187 		if (n > sizeof buf)
188 			n = sizeof buf;
189 		sz -= n;
190 
191 		if ((r = write(Ofd, buf, n)) != n){
192 			fprint(2, "%ld = write(...%ld)\n", r, n);
193 			perror("Write error!");
194 			exits(fail);
195 		}
196 	}
197 }
198 
199 static long
200 rnd(long v, long r)
201 {
202 	long c;
203 
204 	if(r <= 0)
205 		return v;
206 	v += r - 1;
207 	c = v % r;
208 	if(c < 0)
209 		c += r;
210 	v -= c;
211 	return v;
212 }
213 
214 static void
215 put_file(char *ofile)
216 {
217 	int ii;
218 	long doff;
219 	long dsize;
220 	long hlen;
221 	long pad;
222 
223 	Ofd = create(ofile, OWRITE, 0666);
224 	if (Ofd < 0) {
225 		fprint(2, "5cv: create %s: %r\n", ofile);
226 		exits("create");
227 	}
228 
229 	pad = 0;
230 
231 	switch(Hdrtype) {
232 	case 1:	/* aif for risc os */
233 		Strip = 1;
234 		hlen = 128;
235 		lputl(0xe1a00000);		/* NOP - decompress code */
236 		lputl(0xe1a00000);		/* NOP - relocation code */
237 		lputl(0xeb000000 + 12);		/* BL - zero init code */
238 		lputl(0xeb000000 +
239 			(Ihdr.entry
240 			 - Ihdr.txtaddr
241 			 + hlen
242 			 - 12
243 			 - 8) / 4);		/* BL - entry code */
244 
245 		lputl(0xef000011);		/* SWI - exit code */
246 		doff = Ihdr.txtsz+hlen;
247 		lputl(doff);			/* text size */
248 		dsize = Ihdr.datsz;
249 		lputl(dsize);			/* data size */
250 		lputl(0);			/* sym size */
251 
252 		lputl(Ihdr.bsssz);		/* bss size */
253 		lputl(0);			/* sym type */
254 		lputl(Ihdr.txtaddr-hlen);	/* text addr */
255 		lputl(0);			/* workspace - ignored */
256 
257 		lputl(32);			/* addr mode / data addr flag */
258 		lputl(0);			/* data addr */
259 		for(ii=0; ii<2; ii++)
260 			lputl(0);		/* reserved */
261 
262 		for(ii=0; ii<15; ii++)
263 			lputl(0xe1a00000);	/* NOP - zero init code */
264 		lputl(0xe1a0f00e);		/* B (R14) - zero init return */
265 		break;
266 
267 	case 2:	/* plan 9 */
268 		hlen = 32;
269 		doff = hlen + Ihdr.txtsz;
270 		dsize = Ihdr.datsz;
271 		lput(0x647);			/* magic */
272 		lput(Ihdr.txtsz);		/* sizes */
273 		lput(Ihdr.datsz);
274 		lput(Ihdr.bsssz);
275 		if (Strip)			/* nsyms */
276 			lput(0);
277 		else
278 			lput(Ihdr.symsz);
279 		lput(Ihdr.entry);		/* va of entry */
280 		lput(0L);
281 		lput(Ihdr.lnpcsz);
282 		break;
283 
284 	case 3:	/* boot for NetBSD */
285 		hlen = 32;
286 		doff = rnd(hlen+Ihdr.txtsz, 4096);
287 		dsize = rnd(Ihdr.datsz, 4096);
288 		lput((143<<16)|0413);		/* magic */
289 		lputl(doff);
290 		lputl(dsize);
291 		lputl(Ihdr.bsssz);
292 		if (Strip)			/* nsyms */
293 			lputl(0);
294 		else
295 			lputl(Ihdr.symsz);
296 		lputl(Ihdr.entry);		/* va of entry */
297 		lputl(0L);
298 		lputl(0L);
299 		break;
300 	case 4:	/* no header, stripped, padded to 2K, for serial bootstrap */
301 		hlen = 0;
302 		Strip = 1;
303 		doff = hlen + Ihdr.txtsz;
304 		dsize = Ihdr.datsz;
305 		pad = 2048;
306 		break;
307 	case 5:	/* no header, stripped, for all sorts */
308 		hlen = 0;
309 		Strip = 1;
310 		doff = hlen + Ihdr.txtsz;
311 		dsize = Ihdr.datsz;
312 		break;
313 	case 6:	/* fake EPOC IMG format header */
314 		hlen = 256;
315 		*wp++ = 'E';
316 		*wp++ = 'P';
317 		Strip = 1;
318 		doff = hlen + Ihdr.txtsz;
319 		dsize = Ihdr.datsz;
320 		break;
321 	default:
322 		Usage("Bad -Htype");
323 		return;
324 	}
325 	write(Ofd, Wbuf, hlen);
326 
327 	seek(Ifd, Ihdr.txtoff, 0);
328 	copyseg(Ihdr.txtsz);
329 
330 	seek(Ifd, Ihdr.datoff, 0);
331 	seek(Ofd, doff, 0);
332 	copyseg(Ihdr.datsz);
333 
334 	if (!Strip) {
335 		/* Write symbols */
336 		seek(Ofd, doff + dsize, 0);
337 		if (Ihdr.symsz){
338 			seek(Ifd, Ihdr.symoff, 0);
339 			copyseg(Ihdr.symsz);
340 		}
341 		if (Hdrtype == 2)
342 			copyseg(Ihdr.lnpcsz);
343 	}
344 
345 	if (pad) {
346 		if (doff + Ihdr.datsz > pad) {
347 			perror("Too big!");
348 			exits(fail);
349 		}
350 		else if (doff + Ihdr.datsz < pad)
351 			zero(pad - (doff + Ihdr.datsz));
352 	}
353 }
354