Pristine Ack-5.5
[Ack-5.5.git] / mach / minixST / cv / cv.c
1 /* $Id: cv.c,v 1.3 1994/06/24 13:09:18 ceriel Exp $ */
2 /*
3  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4  * See the copyright notice in the ACK home directory, in the file "Copyright".
5  *
6  */
7
8 /*
9  * Convert ACK a.out file to ST-Minix object format.
10  */
11
12 #include <stdio.h>
13 #include <out.h>
14 #include <assert.h>
15
16 struct outhead  outhead;
17 struct outsect  outsect[S_MAX];
18
19 #define TEXTSG  0
20 #define ROMSG   1
21 #define DATASG  2
22 #define BSSSG   3
23 #define LSECT   BSSSG+1
24 #define NSECT   LSECT+1
25
26 char    *output_file;
27 int     outputfile_created;
28
29 char *program ;
30
31 /* Output file definitions and such */
32
33 int             output;
34
35 int unresolved;
36 long    textsize ; 
37 long    datasize ;
38 long    bsssize;
39
40 char *chmemstr;
41
42 minixhead()
43 {
44         long            mh[8];
45         long            stack;
46         long            chmem();
47         int             i;
48
49         mh[0] = 0x04100301L;
50         mh[1] = 0x00000020L;
51         mh[2] = textsize;
52         mh[3] = datasize;
53         mh[4] = bsssize;
54         mh[5] = 0;
55         stack = 0x00010000L - (mh[3] + mh[4]);
56         if ((mh[0] & 0x00200000L) == 0)         /* not SEPARATE */
57                 stack -= mh[2];
58         while (stack < 0)
59                 stack += 0x00010000L;
60         if (chmemstr)
61                 stack = chmem(chmemstr, stack);
62         printf("%ld bytes assigned to stack+malloc area\n", stack);
63         mh[6] = stack + (mh[3] + mh[4]);
64         if ((mh[0] & 0x00200000L) == 0)         /* not SEPARATE */
65                 mh[6] += mh[2];
66         mh[7] = 0;
67         for (i = 0; i < 8; i++) {
68                 cvlong(&mh[i]);
69         }
70
71         if (write(output, (char *) mh, sizeof(mh)) != sizeof(mh))
72                 fatal("write error\n");
73 }
74
75 long align(a,b)
76         long a,b;
77 {
78         if (b == 0) return a;
79         a += b - 1;
80         return a - a % b;
81 }
82
83 int
84 follows(pa, pb)
85         register struct outsect *pa, *pb;
86 {
87         /* return 1 if pa follows pb */
88
89         return pa->os_base == align(pb->os_base+pb->os_size, pa->os_lign);
90 }
91
92 main(argc, argv)
93         int     argc;
94         char    *argv[];
95 {
96
97         program= argv[0] ;
98         if (argc > 1) {
99                 switch (argv[1][0]) { 
100                 case '-':
101                 case '+':
102                 case '=':
103                         chmemstr = argv[1];
104                         argc--;
105                         argv++;
106                 }
107         }
108         switch (argc) {
109         case 3: if ((output = creat(argv[2], 0644)) < 0)
110                         fatal("Can't write %s.\n", argv[2]);
111                 output_file = argv[2];
112                 outputfile_created = 1;
113                 if (! rd_open(argv[1]))
114                         fatal("Can't read %s.\n", argv[1]);
115                 break;
116         default:fatal("Usage: %s [+-= amount] <ACK object> <ST-MINIX object>.\n", argv[0]);
117         }
118         rd_ohead(&outhead);
119         if (BADMAGIC(outhead))
120                 fatal("Not an ack object file.\n");
121         if (outhead.oh_flags & HF_LINK) {
122                 unresolved++;
123                 fatal("Contains unresolved references.\n");
124         }
125         if ( outhead.oh_nsect!=LSECT && outhead.oh_nsect!=NSECT )
126                 fatal("Input file must have %d sections, not %ld\n",
127                         NSECT,outhead.oh_nsect) ;
128         rd_sect(outsect, outhead.oh_nsect);
129         /* A few checks */
130         if ( outsect[BSSSG].os_flen != 0 )
131                 fatal("bss space contains initialized data\n") ;
132         if (! follows(&outsect[BSSSG], &outsect[DATASG]))
133                 fatal("bss segment must follow data segment\n") ;
134         textsize= (outsect[DATASG].os_base - outsect[TEXTSG].os_base);
135         if (! follows(&outsect[ROMSG],&outsect[TEXTSG]))
136                 fatal("rom segment must follow text\n") ;
137         if (! follows(&outsect[DATASG],&outsect[ROMSG]))
138                 fatal("data segment must follow rom\n") ;
139         outsect[TEXTSG].os_size = outsect[ROMSG].os_base - outsect[TEXTSG].os_base;
140         outsect[ROMSG].os_size = outsect[DATASG].os_base - outsect[ROMSG].os_base;
141         outsect[DATASG].os_size = outsect[BSSSG].os_base - outsect[DATASG].os_base;
142         datasize= outsect[DATASG].os_size ;
143         bsssize = outsect[BSSSG].os_size;
144         if ( outhead.oh_nsect==NSECT ) {
145                 if (! follows(&outsect[LSECT],&outsect[BSSSG]))
146                         fatal("end segment must follow bss\n") ;
147                 if ( outsect[LSECT].os_size != 0 )
148                         fatal("end segment must be empty\n") ;
149         }
150
151         minixhead();
152         emits(&outsect[TEXTSG]) ;
153         emits(&outsect[ROMSG]) ;
154         emits(&outsect[DATASG]) ;
155         emit_relo();
156         if ( outputfile_created) chmod(argv[2],0755);
157         return 0;
158 }
159
160 /*
161  * Transfer the emitted byted from one file to another.
162  */
163 emits(section) struct outsect *section ; {
164         char            *p;
165         char            *calloc(), *malloc();
166         long sz = section->os_flen;
167
168         rd_outsect(section - outsect);
169         while (sz) {
170                 unsigned int i = (sz >= 0x4000 ? 0x4000 : sz);
171                 if (!(p = malloc(0x4000))) {
172                         fatal("No memory.\n");
173                 }
174                 rd_emit(p, (long) i);
175                 if (write(output, p, (int)i) < i) {
176                         fatal("write error.\n");
177                 }
178                 free(p);
179                 sz -= i;
180         }
181
182         sz = section->os_size - section->os_flen;
183         if (sz) {
184                 if (!(p = calloc(0x4000, 1))) {
185                         fatal("No memory.\n");
186                 }
187                 while (sz) {
188                         unsigned int i = (sz >= 0x4000 ? 0x4000 : sz);
189                         if (write(output, p, (int)i) < i) {
190                                 fatal("write error.\n");
191                         }
192                         sz -= i;
193                 }
194                 free(p);
195         }
196 }
197
198 int
199 compare(a,b)
200         register struct outrelo *a, *b;
201 {
202         if (a->or_sect < b->or_sect) return -1;
203         if (a->or_sect > b->or_sect) return 1;
204         if (a->or_addr < b->or_addr) return -1;
205         if (a->or_addr > b->or_addr) return 1;
206         return 0;
207 }
208
209 emit_relo()
210 {
211         struct outrelo *ACKrelo;
212         register struct outrelo *ap;
213         unsigned int cnt = outhead.oh_nrelo;
214         long last, curr, base;
215         int sect;
216         char *bp;
217         register char *b;
218
219         ACKrelo = ap = (struct outrelo *) calloc(cnt, sizeof(struct outrelo));
220         bp = b = malloc(4 + cnt);
221         if (!ap || !bp) {
222                 fatal("No memory.\n");
223         }
224         rd_relo(ap, cnt);
225         qsort((char *) ap, (int) cnt, sizeof(struct outrelo), compare);
226         /*
227          * read relocation, modify to GEMDOS format, and write.
228          * Only longs can be relocated.
229          *
230          * The GEMDOS format starts with a long L: the offset to the
231          * beginning of text for the first long to be relocated.
232          * If L==0 then no relocations have to be made.
233          *
234          * The long is followed by zero or more bytes. Each byte B is
235          * processed separately, in one of the following ways:
236          *
237          * B==0:
238          *      end of relocation
239          * B==1:
240          *      no relocation, but add 254 to the current offset
241          * B==0bWWWWWWW0:
242          *      B is added to the current offset and the long addressed
243          *      is relocated. Note that 00000010 means 1 word distance.
244          * B==0bXXXXXXX1:
245          *      illegal
246          */
247
248         last = 0;
249         curr = 0;
250         for (sect = S_MIN; sect <= S_MIN+2; sect++) {
251                 base = outsect[sect-S_MIN].os_base;
252                 for (;cnt > 0 && ap->or_sect == sect; ap++, cnt--) {
253                         if (ap->or_type & RELPC ||
254                             ap->or_nami == outhead.oh_nname) {
255                                 continue;
256                         }
257                         assert(ap->or_type & RELO4);
258                         curr = base + ap->or_addr;
259                         if (last == 0) {
260                                 last = curr;
261                                 cvlong(&curr);
262                                 *((long *) b) = curr;
263                                 b += 4;
264                         }
265                         else {
266                                 while (curr - last > 255) {
267                                         *b++ = 1;
268                                         last += 254;
269                                 }
270                                 *b++ = curr - last;
271                                 last = curr;
272                         }
273                 }
274                 assert(cnt == 0 || ap->or_sect > sect);
275         }
276         assert(cnt == 0);
277         if (cnt = (b - bp)) {
278                 *b++ = '\0';
279                 write(output, bp, (int) cnt+1);
280         }
281         else write(output, "\0\0\0", 4);
282         free((char *) ACKrelo);
283         free(bp);
284 }
285
286 long
287 chmem(str, old)
288 char *str;
289 long old;
290 {
291         register long num, new;
292         long atol();
293
294         num = atol(str+1);
295         if (num == 0)
296                 fatal("bad chmem amount %s\n", str+1);
297         switch (str[0]) {
298         case '-':
299                 new = old - num; break;
300         case '+':
301                 new = old + num; break;
302         case '=':
303                 new = num; break;
304         }
305         return(new);
306 }
307
308 cvlong(l)
309         long *l;
310 {
311         long x = *l;
312         char *p = (char *) l;
313
314         *p++ = x >> 24;
315         *p++ = x >> 16;
316         *p++ = x >> 8;
317         *p = x;
318 }
319
320 /* VARARGS1 */
321 fatal(s, a1, a2)
322         char    *s;
323 {
324         fprintf(stderr,"%s: ",program) ;
325         fprintf(stderr, s, a1, a2);
326         if (outputfile_created)
327                 unlink(output_file);
328         exit(-1);
329 }
330
331 rd_fatal() { fatal("read error.\n"); }