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