c33f4508559cd0eff331e792546d7f23949ecb22
[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 //#define DEBUG_IMAGE_MARKING
24
25
26 //
27 // Initialize Marker
28 //
29 void InitMark(void)
30 {
31         firstmch = curmch = NULL;
32         mcalloc = mcused = 0;
33         curfrom = 0;
34 }
35
36
37 //
38 // Wrap up marker (called after final mark is made)
39 //
40 void stopmark(void)
41 {
42         if (curmch)
43         {
44                 *markptr.wp = MCHEND;           // Mark end of block
45                 curmch->mcused = mcused;        // Update #used in mark block
46         }
47 }
48
49
50 //
51 // Mark a word or longword relocatable
52 //
53 int rmark(uint16_t from, uint32_t loc, uint16_t to, uint16_t size, SYM * symbol)
54 {
55 #ifdef DEBUG_IMAGE_MARKING
56 printf("rmark: from=%i, loc=$%X, to=$%X, size=$%x, symbol=$%X\n", from, loc, to, size, symbol);
57 #endif
58 //      uint16_t w;
59
60         if ((mcalloc - mcused) < MIN_MARK_MEM)
61                 amark();
62
63         uint16_t flags = (size | to);
64
65         if (from != curfrom)
66                 flags |= MCHFROM;
67
68         if (symbol != NULL)
69                 flags |= MSYMBOL;
70
71         mcused += sizeof(WORD) + sizeof(LONG);
72         *markptr.wp++ = flags;
73         *markptr.lp++ = loc;
74
75         if (flags & MCHFROM)
76         {
77                 curfrom = from;
78                 *markptr.wp++ = from;
79                 mcused += sizeof(WORD);
80         }
81
82         if (flags & MSYMBOL)
83         {
84                 *markptr.sy++ = symbol;
85                 mcused += sizeof(SYM *);
86         }
87
88         *markptr.wp = 0x0000;
89
90         return 0;
91 }
92
93
94 //
95 // Allocate another chunk of mark space
96 //
97 int amark(void)
98 {
99 //      MCHUNK * p;
100
101         // Alloc mark block header (and data) and set it up.
102 //      p = (MCHUNK *)amem((long)(sizeof(MCHUNK)) + MARK_ALLOC_INCR);
103         MCHUNK * p = (MCHUNK *)malloc(sizeof(MCHUNK) + MARK_ALLOC_INCR);
104         p->mcnext = NULL;
105         p->mcalloc = MARK_ALLOC_INCR;
106         p->mcptr.cp = (char *)(((char *)p) + sizeof(MCHUNK));
107
108         if (curmch)
109         {
110                 // Link onto previous chunk 
111                 *markptr.wp++ = MCHEND;         // Mark end of block 
112                 curmch->mcused = mcused;
113                 curmch->mcnext = p;
114         }
115
116         if (!firstmch)
117                 firstmch = p;
118
119         curmch = p;                                             // Setup global vars 
120         markptr = p->mcptr;
121         mcalloc = MARK_ALLOC_INCR;
122         mcused = 0;
123
124         return 0;
125 }
126
127
128 //
129 // Make mark image for BSD .o file
130 //
131 uint32_t bsdmarkimg(char * mp, LONG siz, LONG tsize, int reqseg)
132 {
133         MCHUNK * mch;                           // Mark chunk
134         PTR p;                                          // Source point from within mark chunk
135         uint16_t from;                          // Section fixups are currently FROM
136         uint16_t w;                                     // A word (temp)
137         uint32_t loc;                           // Location (temp) 
138         SYM * symbol;                           // Symbols (temp)
139         uint8_t * wp;                           // Pointer into raw relocation info
140         uint8_t * dp;                           // Deposit point for RELMOD info
141         uint32_t diff;                          // Difference to relocate (RELMOD)
142         uint32_t raddr, rflag = 0;      // BSD relocation address and flags
143         uint32_t rsize;                         // Relocation size
144         int validsegment = 0;           // Valid segment being processed
145
146 #ifdef DEBUG_IMAGE_MARKING
147 printf("bsdmarkimg():\n");
148 #endif
149         // Initialise relocation size
150         rsize = 0;
151         chptr = mp;
152         from = 0;
153
154         for(mch=firstmch; mch!=NULL; mch=mch->mcnext)
155         {
156                 for(p=mch->mcptr;;)
157                 {
158                         w = *p.wp++;                    // Next mark entry
159
160                         if (w & MCHEND)
161                                 break;                          // End of mark chunk
162
163                         // Get mark record
164                         symbol = NULL;
165                         loc = *p.lp++;                  // Mark location
166
167                         if (w & MCHFROM)
168                         {
169                                 // Maybe change "from" section
170                                 from = *p.wp++;
171
172                                 if (obj_format == BSD)
173                                 {
174                                         if (reqseg == TEXT)
175                                         {
176                                                 // Requested segment is TEXT
177                                                 if (from == TEXT)
178                                                         validsegment = 1; 
179                                                 else
180                                                         validsegment = 0;
181                                         }
182                                         else
183                                         {
184                                                 // Requested segment is DATA
185                                                 if (from == DATA)
186                                                         validsegment = 1; 
187                                                 else
188                                                         validsegment = 0;
189                                         }
190                                 }
191                         }
192
193                         if (w & MSYMBOL)                        // Maybe includes a symbol
194                                 symbol = *p.sy++;
195
196                         if (obj_format == BSD)
197                         {
198                                 raddr = loc;                    // Set relocation address
199
200                                 if (validsegment)
201 #ifdef DEBUG_IMAGE_MARKING
202 {
203 printf(" validsegment: raddr = $%08X\n", raddr);
204 #endif
205                                         D_long(raddr);          // Write relocation address
206 #ifdef DEBUG_IMAGE_MARKING
207 }
208 #endif
209
210                                 if (w & MPCREL)
211                                         rflag = 0x000000A0;     // PC-relative fixup
212                                 else
213                                         rflag = 0x00000040;     // Absolute fixup
214
215                                 if (w & MMOVEI)
216                                         rflag |= 0x00000001;
217                         }
218
219                         // Compute mark position in relocation information;
220                         // in RELMOD mode, get address of data to fix up.
221                         if (from == DATA)
222                                 loc += tsize;
223
224                         wp = (uint8_t *)(mp + loc);
225
226                         if (symbol)
227                         {
228                                 // Deposit external reference
229                                 if (obj_format == BSD)
230                                 {
231                                         rflag |= 0x00000010;                    // Set external reloc flag bit
232                                         rflag |= (symbol->senv << 8);   // Put symbol index in flags
233
234                                         if (symbol->sattre & RISCSYM)
235                                                 rflag |= 0x00000001;
236
237                                         if (validsegment)
238                                         {
239 #ifdef DEBUG_IMAGE_MARKING
240 printf("  validsegment(2): rflag = $%08X\n", rflag);
241 #endif
242                                                 D_long(rflag);                          // Write relocation flags
243                                                 rsize += 8;                                     // Increment relocation size
244                                         }
245                                 }
246                         }
247                         else
248                         {
249                                 if (obj_format == BSD)
250                                 {
251 #ifdef DEBUG_IMAGE_MARKING
252 printf("  w = $%04X\n", w);
253 #endif
254                                         w &= TDB;                                               // Set reloc flags to segment
255
256                                         switch (w)
257                                         {
258                                         case TEXT: rflag |= 0x00000400; break;
259                                         case DATA: rflag |= 0x00000600; break;
260                                         case BSS:  rflag |= 0x00000800; break;
261                                         }
262
263                                         if (validsegment)
264                                         {
265 #ifdef DEBUG_IMAGE_MARKING
266 printf("  validsegment(3): rflag = $%08X\n", rflag);
267 #endif
268                                                 D_long(rflag);                          // Write relocation flags
269                                                 rsize += 8;                                     // Increment relocation size
270                                         }
271
272                                         w &= TDB;
273
274                                         if (validsegment)
275                                         {
276                                                 if (w & (DATA|BSS))
277                                                 {
278                                                         dp = objimage + BSDHDRSIZE + loc;
279                                                         diff = ((LONG)(*dp++ & 0xFF)) << 24;
280                                                         diff |= ((LONG)(*dp++ & 0xFF)) << 16;
281                                                         diff |= ((LONG)(*dp++ & 0xFF)) << 8;
282                                                         diff |= (LONG)(*dp & 0xFF);
283                                                         DEBUG printf("diff=%ux ==> ", diff);
284 #ifdef DEBUG_IMAGE_MARKING
285 printf("  validsegment(4): diff = $%08X --> ", diff);
286 #endif
287         
288                                                         if (rflag & 0x01)
289                                                                 diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000);
290
291                                                         diff += sect[TEXT].sloc;
292
293                                                         if (w == BSS)
294                                                                 diff += sect[DATA].sloc;
295
296                                                         if (rflag & 0x01)
297                                                                 diff = ((diff >> 16) & 0x0000FFFF) | ((diff << 16) & 0xFFFF0000);
298
299                                                         dp = objimage + BSDHDRSIZE + loc;
300                                                         *dp++ = (char)(diff >> 24);
301                                                         *dp++ = (char)(diff >> 16);
302                                                         *dp++ = (char)(diff >> 8);
303                                                         *dp = (char)diff;
304                                                         DEBUG printf("%ux\n", diff);
305 #ifdef DEBUG_IMAGE_MARKING
306 printf("$%08X\n", diff);
307 #endif
308                                                 }
309                                         }
310                                 }
311                         }
312                 }
313         }
314
315         // Return relocation size
316         if (obj_format == BSD)
317 #ifdef DEBUG_IMAGE_MARKING
318 {
319 printf("  rsize = $%X\n", rsize);
320 #endif
321                 return rsize;                                        
322 #ifdef DEBUG_IMAGE_MARKING
323 }
324 #endif
325
326         return siz;
327 }