The rest of the .PRGFLAGS patch. Sorry!
[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         if (verb_flag)
224         {
225                 printf("TEXT segment: %d bytes\n", sect[TEXT].sloc);
226                 printf("DATA segment: %d bytes\n", sect[DATA].sloc);
227                 printf("BSS  segment: %d bytes\n", sect[BSS].sloc);
228         }
229
230         // Write requested object file...
231         switch (obj_format)
232         {
233         case BSD:
234                 if (verb_flag)
235                 {
236                         printf("Total       : %d bytes\n", sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc);
237                 }
238                 ssize = ((LONG)sy_assign(NULL, NULL));          // Assign index numbers to the symbols
239                 tds = sect[TEXT].sloc + sect[DATA].sloc;        // Get size of TEXT and DATA segment
240                 buf = malloc(0x600000);                                         // Allocate 6mb object file image memory
241
242                 if (buf == NULL)
243                 {
244                         error("cannot allocate object file memory (in BSD mode)");
245                         return ERROR;
246                 }
247
248                 memset(buf, 0, 0x600000);               // Reset allocated memory
249                 objImage = buf;                                 // Set global object image pointer
250                 strtable = malloc(0x200000);    // Allocate 2mb scratch buffer 
251
252                 if (strtable == NULL)
253                 {
254                         error("cannot allocate string table memory (in BSD mode)");
255                         return ERROR;
256                 }
257
258                 memset(strtable, 0, 0x200000);  // Reset allocated memory
259
260                 // Build object file header
261                 chptr = buf;                                    // Base of header
262                 D_long(0x00000107);                             // Magic number
263                 D_long(sect[TEXT].sloc);                // TEXT size 
264                 D_long(sect[DATA].sloc);                // DATA size 
265                 D_long(sect[BSS].sloc);                 // BSS size 
266                 D_long(0x00000000);                             // Symbol size
267                 D_long(0x00000000);                             // First entry (0L)
268                 D_long(0x00000000);                             // TEXT relocation size
269                 D_long(0x00000000);                             // BSD relocation size
270
271                 // Construct TEXT and DATA segments (without relocation changes)
272                 p = buf + BSDHDRSIZE;
273
274                 for(i=TEXT; i<=DATA; ++i)
275                 {
276                         for(cp=sect[i].sfcode; cp!=NULL; cp=cp->chnext)
277                         {
278                                 memcpy(p, cp->chptr, cp->ch_size);
279                                 p += cp->ch_size;
280                         }
281                 }
282
283                 // Do relocation tables (and make changes to segment data)
284                 p = buf + (BSDHDRSIZE + tds);   // Move obj image ptr to reloc info
285                 trsize = bsdmarkimg(p, tds, sect[TEXT].sloc, TEXT);// Do TEXT relocation table
286                 chptr = buf + 24;                               // Point to relocation hdr entry
287                 D_long(trsize);                                 // Write the relocation table size
288                 p = buf + (BSDHDRSIZE + tds + trsize);  // Move obj image ptr to reloc info
289                 drsize = bsdmarkimg(p, tds, sect[TEXT].sloc, DATA);// Do DATA relocation table
290                 chptr = buf + 28;                               // Point to relocation hdr entry
291                 D_long(drsize);                                 // Write the relocation table size
292
293                 p = buf + (BSDHDRSIZE + tds + trsize + drsize);// Point to start of symbol table
294                 sy_assign(p, constr_bsdsymtab); // Build symbol and string tables
295                 chptr = buf + 16;                               // Point to sym table size hdr entry
296                 D_long(symsize);                                // Write the symbol table size
297
298                 // Point to string table
299                 p = buf + (BSDHDRSIZE + tds + trsize + drsize + symsize);    
300
301                 memcpy(p, strtable, strindx);   // Copy string table to object image
302
303                 if (buf)
304                         free(strtable);                         // Free allocated memory
305
306                 chptr = p;                                              // Point to string table size long
307                 D_long(strindx);                                // Write string table size
308
309                 // Write the BSD object file from the object image buffer
310                 unused = write(fd, buf, BSDHDRSIZE + tds + trsize + drsize + symsize + strindx + 4);
311
312                 if (buf)
313                         free(buf);                                      // Free allocated memory
314
315                 break;
316
317         case ALCYON:
318                 if (verb_flag)
319                 {
320                         if (prg_flag)
321                         {
322                                 printf("TOS header  : 28 bytes\n");
323                                 printf("Total       : %d bytes\n", 28 + sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc);
324                         }
325                         else
326                         {
327                                 printf("Total       : %d bytes\n", sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc);
328                         }
329                 }
330                 /*
331                  *  Compute size of symbol table;
332                  *   assign numbers to the symbols...
333                  */
334                 ssize = 0;
335
336                 if (prg_flag != 1)
337                         ssize = ((LONG)sy_assign(NULL, NULL)) * 14;
338
339                 /*
340                  *  Alloc memory for header+text+data, symbol and
341                  *   relocation information construction.
342                  */
343                 t = tds = sect[TEXT].sloc + sect[DATA].sloc;
344
345                 if (t < ssize)
346                         t = ssize;
347
348                 buf = (char *)((int)malloc(t + HDRSIZE) + HDRSIZE);
349
350                 /*
351                  *  Build object file header
352                  *   just before the text+data image
353                  */
354                 chptr = buf - HDRSIZE;  /* -> base of header */
355                 D_word(0x601a);                 /* 00 - magic number */
356                 t = sect[TEXT].sloc;    /* 02 - TEXT size */
357                 D_long(t);
358                 t = sect[DATA].sloc;    /* 06 - DATA size */
359                 D_long(t);
360                 t = sect[BSS].sloc;             /* 0a - BSS size */
361                 D_long(t);
362                 D_long(ssize);                  /* 0e - symbol table size */
363                 D_long(0);                              /* 12 - stack size (unused) */
364                 D_long(PRGFLAGS);               /* 16 - PRGFLAGS */
365                 D_word(0);                              /* 1a - relocation information exists */
366
367                 /*
368                  *  Construct text and data segments;
369                  *  fixup relocatable longs in .PRG mode;
370                  *  finally write the header+text+data
371                  */
372                 p = buf;
373
374                 for(i=TEXT; i<=DATA; i++)
375                 {
376                         for (cp=sect[i].sfcode; cp!=NULL; cp=cp->chnext)
377                         {
378                                 memcpy(p, cp->chptr, cp->ch_size);
379                                 p += cp->ch_size;
380                         }
381                 }
382
383                 if (prg_flag)
384                         markimg(buf, tds, sect[TEXT].sloc, 0);
385
386                 write(fd, buf - HDRSIZE, tds + HDRSIZE);
387
388                 /*
389                  *  Construct and write symbol table
390                  */
391                 if (prg_flag != 1)
392                 {
393                         sy_assign(buf, constr_symtab);
394                         write(fd, buf, ssize);
395                 }
396
397                 /*
398                  *  Construct and write relocation information;
399                  *   the size of it changes if we're writing a RELMODed executable.
400                  */
401                 tds = markimg(buf, tds, sect[TEXT].sloc, 1);
402                 write(fd, buf, tds);
403                 break;
404         }
405
406         return 0;
407 }
408