]> Shamusworld >> Repos - rmac/blob - mark.c
Bump version #.
[rmac] / mark.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // MARK.C - A record of things that are defined relative to any of the sections
4 // Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
7 //
8
9 #include "mark.h"
10 #include "error.h"
11 #include "object.h"
12 #include "riscasm.h"
13
14
15 MCHUNK * firstmch;              // First mark chunk
16 MCHUNK * curmch;                // Current mark chunk
17 PTR markptr;                    // Deposit point in current mark chunk
18 LONG mcalloc;                   // #bytes alloc'd to current mark chunk
19 LONG mcused;                    // #bytes used in current mark chunk
20 uint16_t curfrom;               // Current "from" section
21
22 //
23 //  Imports
24 //
25 extern int prg_flag;    // 1, write ".PRG" relocatable executable
26
27 //#define DEBUG_IMAGE_MARKING
28
29
30 //
31 // Initialize marker
32 //
33 void InitMark(void)
34 {
35         firstmch = curmch = NULL;
36         mcalloc = mcused = 0;
37         curfrom = 0;
38 }
39
40
41 //
42 // Wrap up marker (called after final mark is made)
43 //
44 void StopMark(void)
45 {
46         if (curmch)
47         {
48                 *markptr.wp = MCHEND;           // Mark end of block
49                 curmch->mcused = mcused;        // Update #used in mark block
50         }
51 }
52
53
54 //
55 // Mark a word or longword relocatable
56 //
57 int rmark(uint16_t from, uint32_t loc, uint16_t to, uint16_t size, SYM * symbol)
58 {
59 #ifdef DEBUG_IMAGE_MARKING
60 printf("rmark: from=%i, loc=$%X, to=$%X, size=$%x, symbol=$%X\n", from, loc, to, size, symbol);
61 if (symbol)
62         printf("      symbol->stype=$%02X, sattr=$%04X, sattre=$%08X, svalue=%i, sname=%s\n", symbol->stype, symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
63 #endif
64
65         if ((mcalloc - mcused) < MIN_MARK_MEM)
66                 amark();
67
68         uint16_t flags = (size | to);
69
70         if (from != curfrom)
71                 flags |= MCHFROM;
72
73         if (symbol != NULL)
74                 flags |= MSYMBOL;
75
76         //
77         //  Complain about some things are not allowed in `-p' mode:
78         //    o marks that aren't to LONGs;
79         //    o external references.
80         //
81         if (prg_flag)
82         {
83                 if ((flags & MLONG) == 0)
84                         error("illegal word relocatable (in .PRG mode)");
85
86                 if (symbol != NULL)
87                         errors("illegal external reference (in .PRG mode) to '%s'",
88                                    symbol->sname);
89         }
90
91         mcused += sizeof(WORD) + sizeof(LONG);
92         *markptr.wp++ = flags;
93         *markptr.lp++ = loc;
94
95         if (flags & MCHFROM)
96         {
97                 curfrom = from;
98                 *markptr.wp++ = from;
99                 mcused += sizeof(WORD);
100         }
101
102         if (flags & MSYMBOL)
103         {
104                 *markptr.sy++ = symbol;
105                 mcused += sizeof(SYM *);
106         }
107
108         *markptr.wp = 0x0000;
109
110         return 0;
111 }
112
113
114 //
115 // Allocate another chunk of mark space
116 //
117 int amark(void)
118 {
119 //      MCHUNK * p;
120
121         // Alloc mark block header (and data) and set it up.
122 //      p = (MCHUNK *)amem((long)(sizeof(MCHUNK)) + MARK_ALLOC_INCR);
123         MCHUNK * p = (MCHUNK *)malloc(sizeof(MCHUNK) + MARK_ALLOC_INCR);
124         p->mcnext = NULL;
125         p->mcalloc = MARK_ALLOC_INCR;
126         p->mcptr.cp = (char *)(((char *)p) + sizeof(MCHUNK));
127
128         if (curmch)
129         {
130                 // Link onto previous chunk 
131                 *markptr.wp++ = MCHEND;         // Mark end of block 
132                 curmch->mcused = mcused;
133                 curmch->mcnext = p;
134         }
135
136         if (!firstmch)
137                 firstmch = p;
138
139         curmch = p;                                             // Setup global vars 
140         markptr = p->mcptr;
141         mcalloc = MARK_ALLOC_INCR;
142         mcused = 0;
143
144         return 0;
145 }
146
147
148 /*
149  *  Table to convert from TDB to fixup triad
150  *
151  */
152 static char mark_tr[] = {
153         0,                              /* (n/a) */
154         2,                              /* TEXT relocatable */
155         1, 0,                           /* DATA relocatable */
156         3                               /* BSS relocatable */
157 };
158
159
160 /*
161  *  Make mark image for Alcyon .o file
162  *  okflag      --  1, ok to deposit reloc information
163  */
164 LONG markimg(register char * mp, LONG siz, LONG tsize, int okflag)
165 {
166         MCHUNK * mch;           /* -> mark chunk */
167         register PTR p;         /* source point from within mark chunk */
168         WORD from;                      /* section fixups are currently FROM */
169         register WORD w;        /* a word (temp) */
170         LONG loc;                       /* location (temp) */
171         LONG lastloc;           /* last location fixed up (RELMOD) */
172         SYM * symbol;           /* -> symbols (temp) */
173         char * wp;                      /* pointer into raw relocation information */
174         register char * dp;     /* deposit point for RELMOD information */
175         int firstp;                     /* 1, first relocation (RELMOD) */
176         LONG diff;                      /* difference to relocate (RELMOD) */
177
178         if (okflag)
179                 //clear(mp, siz);               /* zero relocation buffer */
180                 memset(mp, 0, siz);             /* zero relocation buffer */
181
182         from = 0;
183
184         for(mch=firstmch; mch!=NULL; mch=mch->mcnext)
185         {
186                 for(p=mch->mcptr;;)
187                 {
188                         w = *p.wp++;            /* w = next mark entry */
189
190                         if (w & MCHEND)         /* (end of mark chunk) */
191                                 break;
192
193                         /*
194                          *  Get mark record
195                          */
196                         symbol = NULL;
197                         loc = *p.lp++;          /* mark location */
198
199                         if (w & MCHFROM)        /* maybe change "from" section */
200                                 from = *p.wp++;
201
202                         if (w & MSYMBOL)        /* maybe includes a symbol */
203                                 symbol = *p.sy++;
204
205                         /*
206                          *  Compute mark position in relocation information;
207                          *  in RELMOD mode, get address of data to fix up.
208                          */
209                         if (from == DATA)
210                                 loc += tsize;
211
212                         wp = (char *)(mp + loc);
213
214                         if (okflag && (w & MLONG)) /* indicate first word of long */
215                         {
216                                 wp[1] = 5;
217                                 wp += 2;
218                         }
219
220                         if (symbol)
221                         {
222                                 /*
223                                  *  Deposit external reference
224                                  */
225                                 if (okflag)
226                                 {
227                                         if (w & MPCREL)
228                                                 w = 6;          /* pc-relative fixup */
229                                         else
230                                                 w = 4;          /* absolute fixup */
231
232                                         w |= symbol->senv << 3;
233                                         *wp++ = w >> 8;
234                                         *wp = w;
235                                 }
236                         }
237                         else
238                         {
239                                 /*
240                                  *  Deposit section-relative mark;
241                                  *  in RELMOD mode, fix it up in the chunk,
242                                  *  kind of like a sleazoid linker.
243                                  *
244                                  *  In RELMOD mode, marks to words (MWORDs) "cannot happen,"
245                                  *  checks are made when mark() is called, so we don't have
246                                  *  to check again here.
247                                  */
248                                 w &= TDB;
249
250                                 if (okflag)
251                                         wp[1] = mark_tr[w];
252                                 else if (prg_flag && (w & (DATA | BSS)))
253                                 {
254                                         dp = wp;
255                                         diff = ((LONG)(*dp++ & 0xff)) << 24;
256                                         diff |= ((LONG)(*dp++ & 0xff)) << 16;
257                                         diff |= ((LONG)(*dp++ & 0xff)) << 8;
258                                         diff |= (LONG)(*dp & 0xff);
259
260 #ifdef DO_DEBUG
261                                         DEBUG printf("diff=%lx ==> ", diff);
262 #endif
263                                         diff += sect[TEXT].sloc;
264
265                                         if (w == BSS)
266                                                 diff += sect[DATA].sloc;
267
268                                         dp = wp;
269                                         *dp++ = (char)(diff >> 24);
270                                         *dp++ = (char)(diff >> 16);
271                                         *dp++ = (char)(diff >> 8);
272                                         *dp = (char)diff;
273 #ifdef DO_DEBUG
274                                         DEBUG printf("%lx\n", diff);
275 #endif
276                                 }
277                         }
278                 }
279         }
280
281         /*
282          *  Generate ".PRG" relocation information in place in
283          *  the relocation words (the ``RELMOD'' operation).
284          */
285         if (okflag && prg_flag)
286         {
287                 firstp = 1;
288                 wp = mp;
289                 dp = mp;
290
291                 for(loc=0; loc<siz;)
292                 {
293                         if ((wp[1] & 7) == 5)
294                         {
295                                 if (firstp)
296                                 {
297                                         *dp++ = (char)(loc >> 24);
298                                         *dp++ = (char)(loc >> 16);
299                                         *dp++ = (char)(loc >> 8);
300                                         *dp++ = (char)loc;
301                                         firstp = 0;
302                                 }
303                                 else
304                                 {
305                                         for(diff=loc-lastloc; diff>254; diff-= 254)
306                                                 *dp++ = 1;
307
308                                         *dp++ = (char)diff;
309                                 }
310
311                                 wp += 4;
312                                 lastloc = loc;
313                                 loc += 4;
314                         }
315                         else 
316                         {
317                                 loc += 2;
318                                 wp += 2;
319                         }
320                 }
321
322                 /*
323                  *  Terminate relocation list with 0L (if there was no
324                  *  relocation) or 0.B (if relocation information was
325                  *  written).
326                  */
327                 if (!firstp)
328                         *dp++ = 0;
329                 else for (firstp = 0; firstp < 4; ++firstp)
330                         *dp++ = 0;
331
332                 /*
333                  *  Return size of relocation information
334                  */
335                 loc = dp - mp;
336                 return loc;
337         }
338
339         return siz;
340 }
341
342
343 //
344 // Make mark image for BSD .o file
345 //
346 uint32_t bsdmarkimg(char * mp, LONG siz, LONG tsize, int reqseg)
347 {
348         MCHUNK * mch;                           // Mark chunk
349         PTR p;                                          // Source point from within mark chunk
350         uint16_t from;                          // Section fixups are currently FROM
351         uint16_t w;                                     // A word (temp)
352         uint32_t loc;                           // Location (temp) 
353         SYM * symbol;                           // Symbols (temp)
354         uint8_t * wp;                           // Pointer into raw relocation info
355         uint8_t * dp;                           // Deposit point for RELMOD info
356         uint32_t diff;                          // Difference to relocate (RELMOD)
357         uint32_t raddr, rflag = 0;      // BSD relocation address and flags
358         uint32_t rsize;                         // Relocation size
359         int validsegment = 0;           // Valid segment being processed
360
361 #ifdef DEBUG_IMAGE_MARKING
362 printf("bsdmarkimg():\n");
363 #endif
364         // Initialise relocation size
365         rsize = 0;
366         chptr = mp;
367         from = 0;
368
369         for(mch=firstmch; mch!=NULL; mch=mch->mcnext)
370         {
371                 for(p=mch->mcptr;;)
372                 {
373                         w = *p.wp++;                    // Next mark entry
374
375                         if (w & MCHEND)
376                                 break;                          // End of mark chunk
377
378                         // Get mark record
379                         symbol = NULL;
380                         loc = *p.lp++;                  // Mark location
381
382                         if (w & MCHFROM)
383                         {
384                                 // Maybe change "from" section
385                                 from = *p.wp++;
386
387                                 if (obj_format == BSD)
388                                 {
389                                         if (reqseg == TEXT)
390                                         {
391                                                 // Requested segment is TEXT
392                                                 if (from == TEXT)
393                                                         validsegment = 1; 
394                                                 else
395                                                         validsegment = 0;
396                                         }
397                                         else
398                                         {
399                                                 // Requested segment is DATA
400                                                 if (from == DATA)
401                                                         validsegment = 1; 
402                                                 else
403                                                         validsegment = 0;
404                                         }
405                                 }
406                         }
407
408                         if (w & MSYMBOL)                        // Maybe includes a symbol
409                                 symbol = *p.sy++;
410
411                         if (obj_format == BSD)
412                         {
413                                 raddr = loc;                    // Set relocation address
414
415                                 if (validsegment)
416 #ifdef DEBUG_IMAGE_MARKING
417 {
418 printf(" validsegment: raddr = $%08X\n", raddr);
419 #endif
420                                         D_long(raddr);          // Write relocation address
421 #ifdef DEBUG_IMAGE_MARKING
422 }
423 #endif
424
425                                 if (w & MPCREL)
426                                         rflag = 0x000000A0;     // PC-relative fixup
427                                 else
428                                         rflag = 0x00000040;     // Absolute fixup
429
430 // This flag tells the linker to WORD swap the LONG when doing the fixup.
431                                 if (w & MMOVEI)
432 //{
433 //printf("bsdmarkimg: ORing $01 to rflag (MMOVEI) [symbol=%s]...\n", symbol->sname);
434                                         rflag |= 0x00000001;
435 //}
436                         }
437
438                         // Compute mark position in relocation information;
439                         // in RELMOD mode, get address of data to fix up.
440                         if (from == DATA)
441                                 loc += tsize;
442
443                         wp = (uint8_t *)(mp + loc);
444
445                         if (symbol)
446                         {
447                                 // Deposit external reference
448                                 if (obj_format == BSD)
449                                 {
450                                         rflag |= 0x00000010;                    // Set external reloc flag bit
451                                         rflag |= (symbol->senv << 8);   // Put symbol index in flags
452
453 // Looks like this is completely unnecessary (considering it does the wrong thing!)
454 #if 0
455                                         if (symbol->sattre & RISCSYM)
456 {
457 printf("bsdmarkimg: ORing $01 to rflag (RISCSYM) [symbol=%s]...\n", symbol->sname);
458                                                 rflag |= 0x00000001;
459 }
460 #endif
461
462                                         if (validsegment)
463                                         {
464 #ifdef DEBUG_IMAGE_MARKING
465 printf("  validsegment(2): rflag = $%08X\n", rflag);
466 #endif
467                                                 D_long(rflag);                          // Write relocation flags
468                                                 rsize += 8;                                     // Increment relocation size
469                                         }
470                                 }
471                         }
472                         else
473                         {
474                                 if (obj_format == BSD)
475                                 {
476 #ifdef DEBUG_IMAGE_MARKING
477 printf("  w = $%04X\n", w);
478 #endif
479                                         w &= TDB;                                               // Set reloc flags to segment
480
481                                         switch (w)
482                                         {
483                                         case TEXT: rflag |= 0x00000400; break;
484                                         case DATA: rflag |= 0x00000600; break;
485                                         case BSS:  rflag |= 0x00000800; break;
486                                         }
487
488                                         if (validsegment)
489                                         {
490 #ifdef DEBUG_IMAGE_MARKING
491 printf("  validsegment(3): rflag = $%08X\n", rflag);
492 #endif
493                                                 D_long(rflag);                          // Write relocation flags
494                                                 rsize += 8;                                     // Increment relocation size
495                                         }
496
497                                         w &= TDB;
498
499                                         if (validsegment)
500                                         {
501                                                 if (w & (DATA|BSS))
502                                                 {
503                                                         dp = objImage + BSDHDRSIZE + loc;
504                                                         diff = ((LONG)(*dp++ & 0xFF)) << 24;
505                                                         diff |= ((LONG)(*dp++ & 0xFF)) << 16;
506                                                         diff |= ((LONG)(*dp++ & 0xFF)) << 8;
507                                                         diff |= (LONG)(*dp & 0xFF);
508                                                         DEBUG printf("diff=%ux ==> ", diff);
509 #ifdef DEBUG_IMAGE_MARKING
510 printf("  validsegment(4): diff = $%08X --> ", diff);
511 #endif
512         
513                                                         if (rflag & 0x01)
514                                                                 diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000);
515
516                                                         diff += sect[TEXT].sloc;
517
518                                                         if (w == BSS)
519                                                                 diff += sect[DATA].sloc;
520
521                                                         if (rflag & 0x01)
522                                                                 diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000);
523
524                                                         dp = objImage + BSDHDRSIZE + loc;
525                                                         *dp++ = (char)(diff >> 24);
526                                                         *dp++ = (char)(diff >> 16);
527                                                         *dp++ = (char)(diff >> 8);
528                                                         *dp = (char)diff;
529                                                         DEBUG printf("%ux\n", diff);
530 #ifdef DEBUG_IMAGE_MARKING
531 printf("$%08X\n", diff);
532 #endif
533                                                 }
534                                         }
535                                 }
536                         }
537                 }
538         }
539
540         // Return relocation size
541         if (obj_format == BSD)
542 #ifdef DEBUG_IMAGE_MARKING
543 {
544 printf("  rsize = $%X\n", rsize);
545 #endif
546                 return rsize;                                        
547 #ifdef DEBUG_IMAGE_MARKING
548 }
549 #endif
550
551         return siz;
552 }
553