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