New directive: PRGFLAGS sets GEMDOS PRG flags (such as Fastload, etc)
[rmac] / object.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // OBJECT.C - Writing Object Files
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
9 #include "object.h"
10 #include "sect.h"
11 #include "symbol.h"
12 #include "mark.h"
13 #include "error.h"
14 #include "riscasm.h"
15 #include "mark.h"
16
17 /*
18  *  Imports
19  */
20 extern int obj_format;          // object file format to write
21 extern int prg_flag;            // generate Atari ST direct executable
22
23 LONG symsize = 0;                       // Size of BSD symbol table
24 LONG strindx = 0x00000004;      // BSD string table index
25 char * strtable;                        // Pointer to the symbol string table
26 char * objImage;                        // Global object image pointer
27
28
29 //
30 // Add an entry to the BSD symbol table
31 //
32 char * constr_bsdsymtab(char * buf, SYM * sym, int globflag)
33 {
34         chptr = buf;                                            // Point to buffer for deposit longs
35         D_long(strindx);                                        // Deposit the symbol string index
36
37         WORD w1 = sym->sattr;                           // Obtain symbol attribute
38         int w2 = sym->sattre;
39         LONG z = 0;                                                     // Initialise resulting symbol flags
40
41         if (w1 & EQUATED)
42         {                                       
43                 z = 0x02000000;                                 // Set equated flag
44         }
45         else
46         {
47                 switch (w1 & TDB)
48                 {
49                 case TEXT: z = 0x04000000; break;       // Set TEXT segment flag
50                 case DATA: z = 0x06000000; break;       // Set DATA segment flag
51                 case BSS : z = 0x08000000; break;       // Set BSS segment flag
52                 }
53         }
54
55         if (globflag)
56                 z |= 0x01000000;                                // Set global flag if requested
57
58         D_long(z);                                                      // Deposit symbol attribute
59
60         z = sym->svalue;                                        // Obtain symbol value
61         w1 &= DATA | BSS;                                       // Determine DATA or BSS flag
62
63         if (w1)                                                   
64                 z += sect[TEXT].sloc;                   // If DATA or BSS add TEXT segment size
65
66         if (w1 & BSS) 
67                 z += sect[DATA].sloc;                   // If BSS add DATA segment size
68
69         D_long(z);                                                      // Deposit symbol value
70
71         strcpy(strtable + strindx, sym->sname);
72
73         strindx += strlen(sym->sname) + 1;      // Incr string index incl null terminate
74         buf += 12;                                                      // Increment buffer to next record
75         symsize += 12;                                          // Increment symbol table size
76
77         return buf;
78 }
79
80
81 /*
82  *  Alcyon symbol flags
83  */
84 #define AL_DEFINED      0x8000
85 #define AL_EQUATED      0x4000
86 #define AL_GLOBAL       0x2000
87 #define AL_EQUREG       0x1000
88 #define AL_EXTERN       0x0800
89 #define AL_DATA         0x0400
90 #define AL_TEXT         0x0200
91 #define AL_BSS          0x0100
92 #define AL_FILE         0x0080
93
94 LONG PRGFLAGS;          /* PRGFLAGS as defined in Atari Compendium Chapter 2 */
95                                         /* Definition   Bit(s)  Meaning */
96                                         /* PF_FASTLOAD  0               If set, clear only the BSS area on program load,              */
97                                         /*                                              otherwise clear the entire heap.                              */
98                                         /* PF_TTRAMLOAD 1               If set, the program may be loaded into alternative RAM,       */
99                                         /*                                              otherwise it must be loaded into standard RAM.                */
100                                         /* PF_TTRAMMEM  2               If set, the program's Malloc() requests may be satisfied      */
101                                         /*                                              from alternative RAM, otherwise they must be satisfied        */
102                                         /*                                              from standard RAM.                                            */
103                                         /* -                    3               Currently unused.                                             */
104                                         /* See left.    4 & 5   If these bits are set to 0 (PF_PRIVATE), the processes'       */
105                                         /*                                              entire memory space will be considered private                */
106                                         /*                                              (when memory protection is enabled).If these bits are         */
107                                         /*                                              set to 1 (PF_GLOBAL), the processes' entire memory space      */
108                                         /*                                              will be readable and writable by any process (i.e. global).   */
109                                         /*                                              If these bits are set to 2 (PF_SUPERVISOR), the processes'    */
110                                         /*                                              entire memory space will only be readable and writable by     */
111                                         /*                                              itself and any other process in supervisor mode.If these      */
112                                         /*                                              bits are set to 3 (PF_READABLE), the processes' entire memory */
113                                         /*                                              space will be readable by any application but only            */
114                                         /*                                              writable by itself.                                           */
115                                         /* -                    6-15    Currently unused.                                             */
116
117 static WORD tdb_tab[] = {
118         0,                              /* absolute */
119         AL_TEXT,                /* TEXT segment based */
120         AL_DATA, 0,             /* DATA segment based */
121         AL_BSS                  /* BSS segment based */
122 };
123
124
125 #define HDRSIZE 0x1C            /* size of Alcyon header */
126
127
128 /*
129  *  Add entry to symbol table;
130  *  if `globflag' is 1, make the symbol global;
131  *  if in .PRG mode, adjust symbol values for fake link.
132  *
133  */
134 char * constr_symtab(register char * buf, SYM * sym, int globflag)
135 {
136         register int i;
137         register char * s;
138         register WORD w;
139         register LONG z;
140         register WORD w1;
141
142         /*
143          *  Copy symbol name
144          */
145         s = sym->sname;
146
147         for(i=0; i<8 && *s; i++)
148                 *buf++ = *s++;
149
150         while (i++ < 8)
151                 *buf++ = '\0';
152
153         /*
154          *  Construct and deposit flag word
155          *
156          *      o  all symbols are AL_DEFINED
157          *      o  install T/D/B/A base
158          *    o  install 'equated'
159          *    o  commons (COMMON) are AL_EXTERN, but not BSS
160          *      o  exports (DEFINED) are AL_GLOBAL
161          *      o  imports (~DEFINED) are AL_EXTERN
162          *
163          */
164         w1 = sym->sattr;
165         w = AL_DEFINED | tdb_tab[w1 & TDB];
166
167         if (w1 & EQUATED)               /* equated */
168                 w |= AL_EQUATED;
169
170         if (w1 & COMMON)
171         {
172                 w |= AL_EXTERN | AL_GLOBAL;     /* common symbol */
173                 w &= ~AL_BSS;           /* they're not BSS in Alcyon object files */
174         }
175         else if (w1 & DEFINED)
176         {
177                 if (globflag)           /* export the symbol */
178                         w |= AL_GLOBAL;
179         }
180         else w |= AL_EXTERN;            /* imported symbol */
181
182         *buf++ = w >> 8;
183         *buf++ = (char)w;
184
185         z = sym->svalue;
186
187         if (prg_flag)                   /* relocate value in .PRG segment */
188         {
189                 w1 &= DATA | BSS;
190
191                 if (w1)
192                         z += sect[TEXT].sloc;
193
194                 if (w1 & BSS)
195                         z += sect[DATA].sloc;
196         }
197
198         *buf++ = z >> 24;               /* deposit symbol value */
199         *buf++ = z >> 16;
200         *buf++ = z >> 8;
201         *buf++ = z;
202
203         return buf;
204 }
205
206
207 //
208 // Write an object file to the passed in file descriptor
209 // N.B.: Return value is ignored...
210 //
211 int WriteObject(int fd)
212 {
213         LONG t;                                 // Scratch long
214         LONG tds;                               // TEXT & DATA segment size
215         int i;                                  // Temporary int
216         CHUNK * cp;                             // Chunk (for gather)
217         char * buf;                             // Scratch area
218         char * p;                               // Temporary ptr
219         LONG ssize;                             // Size of symbols
220         LONG trsize, drsize;    // Size of relocations
221         long unused;                    // For supressing 'write' warnings
222
223         // Write requested object file...
224         switch (obj_format)
225         {
226         case BSD:
227                 ssize = ((LONG)sy_assign(NULL, NULL));          // Assign index numbers to the symbols
228                 tds = sect[TEXT].sloc + sect[DATA].sloc;        // Get size of TEXT and DATA segment
229                 buf = malloc(0x600000);                                         // Allocate 6mb object file image memory
230
231                 if (buf == NULL)
232                 {
233                         error("cannot allocate object file memory (in BSD mode)");
234                         return ERROR;
235                 }
236
237                 memset(buf, 0, 0x600000);               // Reset allocated memory
238                 objImage = buf;                                 // Set global object image pointer
239                 strtable = malloc(0x200000);    // Allocate 2mb scratch buffer 
240
241                 if (strtable == NULL)
242                 {
243                         error("cannot allocate string table memory (in BSD mode)");
244                         return ERROR;
245                 }
246
247                 memset(strtable, 0, 0x200000);  // Reset allocated memory
248
249                 // Build object file header
250                 chptr = buf;                                    // Base of header
251                 D_long(0x00000107);                             // Magic number
252                 D_long(sect[TEXT].sloc);                // TEXT size 
253                 D_long(sect[DATA].sloc);                // DATA size 
254                 D_long(sect[BSS].sloc);                 // BSS size 
255                 D_long(0x00000000);                             // Symbol size
256                 D_long(0x00000000);                             // First entry (0L)
257                 D_long(0x00000000);                             // TEXT relocation size
258                 D_long(0x00000000);                             // BSD relocation size
259
260                 // Construct TEXT and DATA segments (without relocation changes)
261                 p = buf + BSDHDRSIZE;
262
263                 for(i=TEXT; i<=DATA; ++i)
264                 {
265                         for(cp=sect[i].sfcode; cp!=NULL; cp=cp->chnext)
266                         {
267                                 memcpy(p, cp->chptr, cp->ch_size);
268                                 p += cp->ch_size;
269                         }
270                 }
271
272                 // Do relocation tables (and make changes to segment data)
273                 p = buf + (BSDHDRSIZE + tds);   // Move obj image ptr to reloc info
274                 trsize = bsdmarkimg(p, tds, sect[TEXT].sloc, TEXT);// Do TEXT relocation table
275                 chptr = buf + 24;                               // Point to relocation hdr entry
276                 D_long(trsize);                                 // Write the relocation table size
277                 p = buf + (BSDHDRSIZE + tds + trsize);  // Move obj image ptr to reloc info
278                 drsize = bsdmarkimg(p, tds, sect[TEXT].sloc, DATA);// Do DATA relocation table
279                 chptr = buf + 28;                               // Point to relocation hdr entry
280                 D_long(drsize);                                 // Write the relocation table size
281
282                 p = buf + (BSDHDRSIZE + tds + trsize + drsize);// Point to start of symbol table
283                 sy_assign(p, constr_bsdsymtab); // Build symbol and string tables
284                 chptr = buf + 16;                               // Point to sym table size hdr entry
285                 D_long(symsize);                                // Write the symbol table size
286
287                 // Point to string table
288                 p = buf + (BSDHDRSIZE + tds + trsize + drsize + symsize);    
289
290                 memcpy(p, strtable, strindx);   // Copy string table to object image
291
292                 if (buf)
293                         free(strtable);                         // Free allocated memory
294
295                 chptr = p;                                              // Point to string table size long
296                 D_long(strindx);                                // Write string table size
297
298                 // Write the BSD object file from the object image buffer
299                 unused = write(fd, buf, BSDHDRSIZE + tds + trsize + drsize + symsize + strindx + 4);
300
301                 if (buf)
302                         free(buf);                                      // Free allocated memory
303
304                 break;
305
306         case ALCYON:
307                 /*
308                  *  Compute size of symbol table;
309                  *   assign numbers to the symbols...
310                  */
311                 ssize = 0;
312
313                 if (prg_flag != 1)
314                         ssize = ((LONG)sy_assign(NULL, NULL)) * 14;
315
316                 /*
317                  *  Alloc memory for header+text+data, symbol and
318                  *   relocation information construction.
319                  */
320                 t = tds = sect[TEXT].sloc + sect[DATA].sloc;
321
322                 if (t < ssize)
323                         t = ssize;
324
325                 buf = malloc(t + HDRSIZE) + HDRSIZE;
326
327                 /*
328                  *  Build object file header
329                  *   just before the text+data image
330                  */
331                 chptr = buf - HDRSIZE;  /* -> base of header */
332                 D_word(0x601a);                 /* magic number */
333                 t = sect[TEXT].sloc;    /* TEXT size */
334                 D_long(t);
335                 t = sect[DATA].sloc;    /* DATA size */
336                 D_long(t);
337                 t = sect[BSS].sloc;             /* BSS size */
338                 D_long(t);
339                 D_long(ssize);                  /* symbol table size */
340                 D_long(0);                              /* stack size (unused) */
341                 D_long(0);                              /* entry point (unused) */
342                 D_word(0);                              /* relocation information exists */
343
344                 /*
345                  *  Construct text and data segments;
346                  *  fixup relocatable longs in .PRG mode;
347                  *  finally write the header+text+data
348                  */
349                 p = buf;
350
351                 for(i=TEXT; i<=DATA; i++)
352                 {
353                         for (cp=sect[i].sfcode; cp!=NULL; cp=cp->chnext)
354                         {
355                                 memcpy(p, cp->chptr, cp->ch_size);
356                                 p += cp->ch_size;
357                         }
358                 }
359
360                 if (prg_flag)
361                         markimg(buf, tds, sect[TEXT].sloc, 0);
362
363                 write(fd, buf - HDRSIZE, tds + HDRSIZE);
364
365                 /*
366                  *  Construct and write symbol table
367                  */
368                 if (prg_flag != 1)
369                 {
370                         sy_assign(buf, constr_symtab);
371                         write(fd, buf, ssize);
372                 }
373
374                 /*
375                  *  Construct and write relocation information;
376                  *   the size of it changes if we're writing a RELMODed executable.
377                  */
378                 tds = markimg(buf, tds, sect[TEXT].sloc, 1);
379                 write(fd, buf, tds);
380                 break;
381         }
382
383         return 0;
384 }
385