Initial commit.
[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 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 #include "mark.h"
9 #include "error.h"
10 #include "object.h"
11 #include "risca.h"
12
13 MCHUNK *firstmch;                                           // First mark chunk
14 MCHUNK *curmch;                                             // Current mark chunk
15 PTR markptr;                                                // Deposit point in current mark chunk
16 LONG mcalloc;                                               // #bytes alloc'd to current mark chunk
17 LONG mcused;                                                // #bytes used in current mark chunk
18 WORD curfrom;                                               // Current "from" section
19
20 //
21 // --- Initialize Marker ---------------------------------------------------------------------------
22 //
23
24 void init_mark(void) {
25    firstmch = curmch = NULL;
26    mcalloc = mcused = 0;
27    curfrom = 0;
28 }
29
30 //
31 // --- Wrap up marker (called after final mark is made) --------------------------------------------
32 //
33
34 void stopmark(void) {
35    if(curmch) {
36       *markptr.wp = MCHEND;                                 // Mark end of block
37       curmch->mcused = mcused;                              // Update #used in mark block
38    }
39 }
40
41 //
42 // --- Mark a word or longword relocatable ---------------------------------------------------------
43 //
44
45 int rmark(int from, LONG loc, int to, int size, SYM *symbol) {
46    WORD w;
47
48    if((mcalloc - mcused) < MIN_MARK_MEM)
49       amark();
50
51    w = (WORD)(size | to);
52    if(from != curfrom)
53       w |= MCHFROM;
54    if(symbol != NULL)
55       w |= MSYMBOL;
56
57    mcused += sizeof(WORD) + sizeof(LONG);
58    *markptr.wp++ = w;
59    *markptr.lp++ = loc;
60
61    if(w & MCHFROM) {
62       *markptr.wp++ = (WORD)from;
63       curfrom = (WORD)from;
64       mcused += sizeof(WORD);
65    }
66
67    if(w & MSYMBOL) {
68       *markptr.sy++ = symbol;
69       mcused += sizeof(LONG);
70    }
71
72    *markptr.wp = 0x0000;
73
74    return(0);
75 }
76
77 //
78 // --- Allocate another chunk of mark space --------------------------------------------------------
79 //
80
81 int amark(void) {
82    MCHUNK *p;
83
84    // Alloc mark block header (and data) and set it up.
85    p = (MCHUNK *)amem((long)(sizeof(MCHUNK)) + MARK_ALLOC_INCR);
86    p->mcnext = NULL;
87    p->mcalloc = MARK_ALLOC_INCR;
88    p->mcptr.cp = (char *)(((char *)p) + sizeof(MCHUNK));
89
90    if(curmch) {                                             // Link onto previous chunk 
91       *markptr.wp++ = MCHEND;                               // Mark end of block 
92       curmch->mcused = mcused;
93       curmch->mcnext = p;
94    }
95    if(!firstmch)
96       firstmch = p;
97
98    curmch = p;                                              // Setup global vars 
99    markptr = p->mcptr;
100    mcalloc = MARK_ALLOC_INCR;
101    mcused = 0;
102
103    return(0);
104 }
105
106 //
107 // --- Make mark image for BSD .o file -------------------------------------------------------------
108 //
109
110 LONG bsdmarkimg(char *mp, LONG siz, LONG tsize, int reqseg) {
111    MCHUNK *mch;                                             // Mark chunk
112    PTR p;                                                   // Source point from within mark chunk
113    WORD from;                                               // Section fixups are currently FROM
114    WORD w;                                                  // A word (temp)
115    LONG loc;                                                // Location (temp) 
116    SYM *symbol;                                             // Symbols (temp)
117    char *wp;                                                // Pointer into raw relocation info
118    char *dp;                                                // Deposit point for RELMOD info
119    LONG diff;                                               // Difference to relocate (RELMOD)
120    LONG raddr, rflag = 0;                                   // BSD relocation address and flags
121    LONG rsize;                                              // Relocation size
122    int validsegment = 0;                                    // Valid segment being processed
123
124    rsize = 0;                                               // Initialise relocation size
125    chptr = mp;
126
127    from = 0;
128    for(mch = firstmch; mch != NULL; mch = mch->mcnext)
129       for(p = mch->mcptr;;) {
130          w = *p.wp++;                                       // Next mark entry
131
132          if(w & MCHEND) break;                              // End of mark chunk
133
134          // Get mark record
135          symbol = NULL;
136          loc = *p.lp++;                                     // Mark location
137          if(w & MCHFROM) {                                  // Maybe change "from" section
138             from = *p.wp++;
139             if(obj_format == BSD) {
140                if(reqseg == TEXT) {                         // Requested segment is TEXT
141                   if(from == TEXT) validsegment = 1; 
142                   else validsegment = 0;
143                } else {                                     // Requested segment is DATA
144                   if(from == DATA) validsegment = 1; 
145                   else validsegment = 0;
146                }
147             }
148          }
149
150          if(w & MSYMBOL)                                    // Maybe includes a symbol
151             symbol = *p.sy++;
152
153          if(obj_format == BSD) {
154             raddr = loc;                                    // Set relocation address
155             if(validsegment)
156                D_long(raddr);                               // Write relocation address
157             if(w & MPCREL)
158                rflag = 0x000000A0;                          // PC-relative fixup
159             else
160                rflag = 0x00000040;                          // Absolute fixup
161             if(w & MMOVEI)
162                rflag |= 0x00000001;
163          }
164
165          // Compute mark position in relocation information;
166          // in RELMOD mode, get address of data to fix up.
167          if(from == DATA)
168             loc += tsize;
169          wp = (char *)(mp + loc);
170
171          if(symbol) {
172             // Deposit external reference
173             if(obj_format == BSD) {
174                rflag |= 0x00000010;                         // Set external reloc flag bit
175                rflag |= (symbol->senv << 8);                // Put symbol index in flags
176                if(symbol->sattre & RISCSYM) rflag |= 0x00000001;
177                if(validsegment) {
178                   D_long(rflag);                            // Write relocation flags
179                   rsize += 8;                               // Increment relocation size
180                }
181             }
182
183          } else {
184
185             if(obj_format == BSD) {
186                w &= TDB;                                    // Set reloc flags to segment
187                switch(w) {
188                   case TEXT: rflag |= 0x00000400; break;
189                   case DATA: rflag |= 0x00000600; break;
190                   case BSS:  rflag |= 0x00000800; break;
191                }
192                if(validsegment) {
193                   D_long(rflag);                            // Write relocation flags
194                   rsize += 8;                               // Increment relocation size
195                }
196                w &= TDB;
197                if(validsegment) {
198                   if(w & (DATA|BSS)) {
199                      dp = objimage + BSDHDRSIZE + loc;
200                      diff = ((LONG)(*dp++ & 0xff)) << 24;
201                      diff |= ((LONG)(*dp++ & 0xff)) << 16;
202                      diff |= ((LONG)(*dp++ & 0xff)) << 8;
203                      diff |= (LONG)(*dp & 0xff);
204                      DEBUG printf("diff=%lx ==> ", diff);
205                      if(rflag & 0x01)
206                         diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000);
207                      diff += sect[TEXT].sloc;
208                      if(w == BSS)
209                         diff += sect[DATA].sloc;
210                      if(rflag & 0x01)
211                         diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000);
212                      dp = objimage + BSDHDRSIZE + loc;
213                      *dp++ = (char)(diff >> 24);
214                      *dp++ = (char)(diff >> 16);
215                      *dp++ = (char)(diff >> 8);
216                      *dp = (char)diff;
217                      DEBUG printf("%lx\n", diff);
218                   }
219                }
220             }
221          }
222       }
223
224    if(obj_format == BSD)                                    // Return relocation size
225       return(rsize);                                        
226    else
227       return(siz);
228 }