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