]> Shamusworld >> Repos - rmac/blob - object.c
Forgot to update the copyright in rmac.c. D'oh! :-P
[rmac] / object.c
1 //
2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // OBJECT.C - Writing Object Files
4 // Copyright (C) 199x Landon Dyer, 2011-2019 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 "6502.h"
11 #include "direct.h"
12 #include "dsp56k.h"
13 #include "error.h"
14 #include "mark.h"
15 #include "riscasm.h"
16 #include "sect.h"
17 #include "symbol.h"
18 #include "version.h"
19
20 //#define DEBUG_ELF
21
22 uint32_t symsize = 0;                   // Size of BSD/ELF symbol table
23 uint32_t strindx = 0x00000004;  // BSD/ELF string table index
24 uint8_t * strtable;                             // Pointer to the symbol string table
25 uint8_t * objImage;                             // Global object image pointer
26 int elfHdrNum[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
27 uint32_t extraSyms;
28
29 static uint16_t tdb_tab[] = {
30         0,                              // absolute
31         AL_TEXT,                // TEXT segment based
32         AL_DATA, 0,             // DATA segment based
33         AL_BSS                  // BSS segment based
34 };
35
36 uint32_t PRGFLAGS;      /* PRGFLAGS as defined in Atari Compendium Chapter 2
37 Definition              Bit(s)  Meaning
38 --------------- ------- --------------------------------------------------------
39 PF_FASTLOAD             0               If set, clear only the BSS area on program load,
40                                                 otherwise clear the entire heap.
41 PF_TTRAMLOAD    1               If set, the program may be loaded into alternative RAM,
42                                                 otherwise it must be loaded into standard RAM.
43 PF_TTRAMMEM             2               If set, the program's Malloc() requests may be satisfied
44                                                 from alternative RAM, otherwise they must be satisfied
45                                                 from standard RAM.
46 -                               3               Currently unused
47 See left.               4 & 5   If these bits are set to 0 (PF_PRIVATE), the processes'
48                                                 entire memory space will be considered private
49                                                 (when memory protection is enabled).If these bits are
50                                                 set to 1 (PF_GLOBAL), the processes' entire memory space
51                                                 will be readable and writable by any process (i.e.
52                                                 global). If these bits are set to 2 (PF_SUPERVISOR), the
53                                                 processes' entire memory space will only be readable and
54                                                 writable by itself and any other process in supervisor
55                                                 mode.If these bits are set to 3 (PF_READABLE), the
56                                                 processes' entire memory space will be readable by any
57                                                 application but only writable by itself.
58 -                               6-15    Currently unused
59 */
60
61 // Internal function prototypes
62 static void WriteLOD(void);
63 static void WriteP56(void);
64
65
66 //
67 // Add entry to symbol table (in ALCYON mode)
68 // If 'globflag' is 1, make the symbol global
69 // If in .PRG mode, adjust symbol values for fake link
70 //
71 uint8_t * AddSymEntry(register uint8_t * buf, SYM * sym, int globflag)
72 {
73         // Copy symbol name to buffer (first 8 chars or less)
74         register uint8_t * s = sym->sname;
75         register int i;
76         uint32_t extra = 0;
77
78         for(i=0; i<8 && *s; i++)
79                 *buf++ = *s++;
80
81         while (i++ < 8)
82                 *buf++ = '\0';
83
84         register uint16_t w1 = sym->sattr;
85         register uint16_t w = AL_DEFINED | tdb_tab[w1 & TDB];
86
87         if (prg_flag == 3)
88         {
89                 // Extended symbol - Check to see if symbol is larger than 8 characters
90                 // and write an extra 14 characters where the next symbol would be.
91                 // Modify the flag word for this
92                 if (*s)
93                 {
94                         //printf("%s '%i' - will write extended symbol\n", sym->sname,s[0]);
95                         uint8_t *buf2 = buf + 6;
96
97                         for(i=8; i<8+14 && *s; i++)
98                                 *buf2++ = *s++;
99
100                         while (i++ < 8 + 14)
101                                 *buf2++ = '\0';
102
103                         symsize += 14;
104                         w |= 0x48;
105                         extra = 14;
106                 }
107         }
108
109         //
110         // Construct and deposit flag word
111         //
112         // o  all symbols are AL_DEFINED
113         // o  install T/D/B/A base
114         //   o  install 'equated'
115         //   o  commons (COMMON) are AL_EXTERN, but not BSS
116         // o  exports (DEFINED) are AL_GLOBAL
117         // o  imports (~DEFINED) are AL_EXTERN
118         //
119         if (w1 & EQUATED)               // Equated
120                 w |= AL_EQUATED;
121
122         if (w1 & COMMON)
123         {
124                 w |= AL_EXTERN | AL_GLOBAL;     // Common symbol
125                 w &= ~AL_BSS;           // They're not BSS in Alcyon object files
126         }
127         else if (w1 & DEFINED)
128         {
129                 if (globflag)           // Export the symbol
130                         w |= AL_GLOBAL;
131         }
132         else
133                 w |= AL_EXTERN;         // Imported symbol
134
135         SETBE16(buf, 0, w);
136         buf += 2;
137         register uint32_t z = (uint32_t)sym->svalue;
138
139         if (prg_flag)                   // Relocate value in .PRG segment
140         {
141                 w1 &= DATA | BSS;
142
143                 if (w1)
144                         z += sect[TEXT].sloc;
145
146                 if (w1 & BSS)
147                         z += sect[DATA].sloc;
148         }
149
150         SETBE32(buf, 0, z);             // Deposit symbol value
151         buf += 4;
152
153         symsize += 14;
154         buf += extra;
155
156         return buf;
157 }
158
159
160 //
161 // Add an entry to the BSD symbol table
162 //
163 uint8_t * AddBSDSymEntry(uint8_t * buf, SYM * sym, int globflag)
164 {
165         chptr = buf;                                            // Point to buffer for depositing longs
166         D_long(strindx);                                        // Deposit the symbol string index
167
168         uint16_t w1 = sym->sattr;                       // Obtain symbol attributes
169         uint32_t z = 0;                                         // Initialize resulting symbol flags
170
171         if (w1 & EQUATED)
172         {
173                 z = 0x02000000;                                 // Set equated flag
174         }
175         else
176         {
177                 switch (w1 & TDB)
178                 {
179                 case TEXT: z = 0x04000000; break;       // Set TEXT segment flag
180                 case DATA: z = 0x06000000; break;       // Set DATA segment flag
181                 case BSS : z = 0x08000000; break;       // Set BSS segment flag
182                 }
183         }
184
185         if (globflag)
186                 z |= 0x01000000;                                // Set global flag if requested
187
188         D_long(z);                                                      // Deposit symbol attribute
189         z = sym->svalue;                                        // Obtain symbol value
190
191         if (w1 & (DATA | BSS))
192                 z += sect[TEXT].sloc;                   // If DATA or BSS add TEXT segment size
193
194         if (w1 & BSS)
195                 z += sect[DATA].sloc;                   // If BSS add DATA segment size
196
197         D_long(z);                                                      // Deposit symbol value
198         strcpy(strtable + strindx, sym->sname);
199         strindx += strlen(sym->sname) + 1;      // Incr string index incl null terminate
200         buf += 12;                                                      // Increment buffer to next record
201         symsize += 12;                                          // Increment symbol table size
202
203         return buf;
204 }
205
206
207 //
208 // Add entry to ELF symbol table; if `globflag' is 1, make the symbol global
209 //
210 uint8_t * AddELFSymEntry(uint8_t * buf, SYM * sym, int globflag)
211 {
212         chptr = buf;
213         ch_size = 0;
214         D_long(strindx);                // st_name
215         D_long(sym->svalue);    // st_value
216         D_long(0);                              // st_size
217         uint8_t st_info = 0;
218
219         register WORD w1 = sym->sattr;
220
221         if (w1 & COMMON)
222         {
223                 //w |= AL_EXTERN | AL_GLOBAL;   // common symbol
224                 //w &= ~AL_BSS;         // they're not BSS in Alcyon object files
225         }
226         else if (w1 & DEFINED)
227         {
228                 if (globflag)           // Export the symbol
229                         st_info |= 16;   //STB_GLOBAL (1<<4)
230         }
231         else if (w1 & (GLOBAL | REFERENCED))
232                 st_info |= 16;
233
234         D_byte(st_info);
235         D_byte(0);                              // st_other
236
237         uint16_t st_shndx = 0xFFF1;     // Assume absolute (equated) number
238
239         if (w1 & TEXT)
240                 st_shndx = elfHdrNum[ES_TEXT];
241         else if (w1 & DATA)
242                 st_shndx = elfHdrNum[ES_DATA];
243         else if (w1 & BSS)
244                 st_shndx = elfHdrNum[ES_BSS];
245         else if (globflag)
246                 st_shndx = 0;           // Global, not absolute
247
248         D_word(st_shndx);
249
250         strcpy(strtable + strindx, sym->sname);
251         strindx += strlen(sym->sname) + 1;      // Incr string index incl null terminate
252         symsize += 0x10;                                        // Increment symbol table size
253
254         return buf + 0x10;
255 }
256
257
258 //
259 // Helper function for ELF output
260 //
261 int DepositELFSectionHeader(uint8_t * ptr, uint32_t name, uint32_t type, uint32_t flags, uint32_t addr, uint32_t offset, uint32_t size, uint32_t link, uint32_t info, uint32_t addralign, uint32_t entsize)
262 {
263         chptr = ptr;
264         ch_size = 0;
265         D_long(name);
266         D_long(type);
267         D_long(flags);
268         D_long(addr);
269         D_long(offset);
270         D_long(size);
271         D_long(link);
272         D_long(info);
273         D_long(addralign);
274         D_long(entsize);
275         return 40;
276 }
277
278
279 //
280 // Deposit an entry in the Section Header string table
281 //
282 uint32_t DepositELFSHSTEntry(uint8_t ** pTable, const uint8_t * s)
283 {
284 #ifdef DEBUG_ELF
285 printf("DepositELFSHSTEntry: s = \"%s\"\n", s);
286 #endif
287         uint32_t strSize = strlen(s);
288         strcpy(*pTable, s);
289         *pTable += strSize + 1;
290         return strSize + 1;
291 }
292
293
294 //
295 // Deposit a symbol table entry in the ELF Symbol Table
296 //
297 uint32_t DepositELFSymbol(uint8_t * ptr, uint32_t name, uint32_t addr, uint32_t size, uint8_t info, uint8_t other, uint16_t shndx)
298 {
299         chptr = ptr;
300         ch_size = 0;
301         D_long(name);
302         D_long(addr);
303         D_long(size);
304         *chptr++ = info;
305         *chptr++ = other;
306         D_word(shndx);
307         return 16;
308 }
309
310
311 //
312 // Write an object file to the passed in file descriptor
313 // N.B.: Return value is ignored...
314 //
315 int WriteObject(int fd)
316 {
317         LONG t;                                 // Scratch long
318         LONG tds;                               // TEXT & DATA segment size
319         int i;                                  // Temporary int
320         CHUNK * cp;                             // Chunk (for gather)
321         uint8_t * buf;                  // Scratch area
322         uint8_t * p;                    // Temporary ptr
323         LONG trsize, drsize;    // Size of relocations
324         long unused;                    // For supressing 'write' warnings
325
326         if (verb_flag)
327         {
328                 printf("TEXT segment: %d bytes\n", sect[TEXT].sloc);
329                 printf("DATA segment: %d bytes\n", sect[DATA].sloc);
330                 printf("BSS  segment: %d bytes\n", sect[BSS].sloc);
331         }
332
333         // Write requested object file...
334         if ((obj_format == BSD) || ((obj_format == ALCYON) && (prg_flag == 0)))
335     {
336                 // Force BSD format (if it was ALCYON format)
337                 obj_format = BSD;
338
339                 if (verb_flag)
340                 {
341                         printf("Total       : %d bytes\n", sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc);
342                 }
343
344                 sy_assign(NULL, NULL);                                          // Assign index numbers to the symbols
345                 tds = sect[TEXT].sloc + sect[DATA].sloc;        // Get size of TEXT and DATA segment
346                 buf = malloc(0x800000);                                         // Allocate 8MB object file image memory
347
348                 if (buf == NULL)
349                 {
350                         error("cannot allocate object file memory (in BSD mode)");
351                         return ERROR;
352                 }
353
354                 memset(buf, 0, 0x800000);               // Clear allocated memory
355                 objImage = buf;                                 // Set global object image pointer
356                 strtable = malloc(0x200000);    // Allocate 2MB string table buffer
357
358                 if (strtable == NULL)
359                 {
360                         free(buf);
361                         error("cannot allocate string table memory (in BSD mode)");
362                         return ERROR;
363                 }
364
365                 memset(strtable, 0, 0x200000);  // Clear allocated memory
366
367                 // Build object file header
368                 chptr = buf;                                    // Base of header (for D_foo macros)
369                 ch_size = 0;
370                 challoc = 0x800000;
371                 D_long(0x00000107);                             // Magic number
372                 D_long(sect[TEXT].sloc);                // TEXT size
373                 D_long(sect[DATA].sloc);                // DATA size
374                 D_long(sect[BSS].sloc);                 // BSS size
375                 D_long(0x00000000);                             // Symbol size
376                 D_long(0x00000000);                             // First entry (0L)
377                 D_long(0x00000000);                             // TEXT relocation size
378                 D_long(0x00000000);                             // DATA relocation size
379
380                 // Construct TEXT and DATA segments (without relocation changes)
381                 p = buf + BSDHDRSIZE;
382
383                 for(i=TEXT; i<=DATA; i++)
384                 {
385                         for(cp=sect[i].sfcode; cp!=NULL; cp=cp->chnext)
386                         {
387                                 memcpy(p, cp->chptr, cp->ch_size);
388                                 p += cp->ch_size;
389                         }
390                 }
391
392                 // Do relocation tables (and make changes to segment data)
393                 p = buf + BSDHDRSIZE + tds;             // Move obj image ptr to reloc info
394                 trsize = MarkBSDImage(p, tds, sect[TEXT].sloc, TEXT);// Do TEXT relocation table
395                 chptr = buf + 0x18;                             // Point to relocation hdr entry
396                 D_long(trsize);                                 // Write the relocation table size
397
398                 // Move obj image ptr to reloc info
399                 p = buf + BSDHDRSIZE + tds + trsize;
400                 drsize = MarkBSDImage(p, tds, sect[TEXT].sloc, DATA);// Do DATA relocation table
401                 chptr = buf + 0x1C;                             // Point to relocation hdr entry
402                 D_long(drsize);                                 // Write the relocation table size
403
404                 // Point to start of symbol table
405                 p = buf + BSDHDRSIZE + tds + trsize + drsize;
406                 sy_assign(p, AddBSDSymEntry);   // Build symbol and string tables
407                 chptr = buf + 0x10;                             // Point to sym table size hdr entry
408                 D_long(symsize);                                // Write the symbol table size
409
410                 // Point to string table
411                 p = buf + BSDHDRSIZE + tds + trsize + drsize + symsize;
412                 memcpy(p, strtable, strindx);   // Copy string table to object image
413                 chptr = p;                                              // Point to string table size long
414                 D_long(strindx);                                // Write string table size
415
416                 // Write the BSD object file from the object image buffer
417                 unused = write(fd, buf, BSDHDRSIZE + tds + trsize + drsize + symsize + strindx + 4);
418
419                 if (verb_flag)
420                 {
421                         printf("TextRel size: %d bytes\n", trsize);
422                         printf("DataRel size: %d bytes\n", drsize);
423                 }
424
425                 if (buf)
426                 {
427                         free(strtable);                         // Free allocated memory
428                         free(buf);                                      // Free allocated memory
429                 }
430         }
431         else if (obj_format == ALCYON)
432         {
433                 if (verb_flag)
434                 {
435                         if (prg_flag)
436                                 printf("TOS header  : 28 bytes\n");
437
438                         printf("Total       : %d bytes\n", sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc + (prg_flag ? 28 : 0));
439                 }
440
441                 // Assign index numbers to the symbols, get # of symbols (we assume
442                 // that all symbols can potentially be extended, hence the x28)
443                 uint32_t symbolMaxSize = sy_assign(NULL, NULL) * 28;
444
445                 // Alloc memory for header + text + data, symbol and relocation
446                 // information construction.
447                 tds = sect[TEXT].sloc + sect[DATA].sloc;
448                 buf = malloc(HDRSIZE + tds + symbolMaxSize);
449
450                 // Build object file header just before the text+data image
451                 chptr = buf;                            // -> base of header
452                 ch_size = 0;
453                 challoc = HDRSIZE + tds + symbolMaxSize;
454                 D_word(0x601A);                         // 00 - magic number
455                 D_long(sect[TEXT].sloc);        // 02 - TEXT size
456                 D_long(sect[DATA].sloc);        // 06 - DATA size
457                 D_long(sect[BSS].sloc);         // 0A - BSS size
458                 D_long(0);                                      // 0E - symbol table size (filled later)
459                 D_long(0);                                      // 12 - stack size (unused)
460                 D_long(PRGFLAGS);                       // 16 - PRGFLAGS
461                 D_word(0);                                      // 1A - relocation information exists
462
463                 // Construct text and data segments; fixup relocatable longs in .PRG
464                 // mode; finally write the header + text + data
465                 p = buf + HDRSIZE;
466
467                 for(i=TEXT; i<=DATA; i++)
468                 {
469                         for(cp=sect[i].sfcode; cp!=NULL; cp=cp->chnext)
470                         {
471                                 memcpy(p, cp->chptr, cp->ch_size);
472                                 p += cp->ch_size;
473                         }
474                 }
475
476                 // Do a first pass on the Alcyon image, if in PRG mode
477                 if (prg_flag)
478                         MarkImage(buf + HDRSIZE, tds, sect[TEXT].sloc, 0);
479
480                 // Construct symbol table and update the header entry, if necessary
481                 if (prg_flag > 1)
482                 {
483                         // sy_assign with AddSymEntry updates symsize (stays 0 otherwise)
484                         sy_assign(buf + HDRSIZE + tds, AddSymEntry);
485                         chptr = buf + 0x0E;                     // Point to symbol table size entry
486                         D_long(symsize);
487                 }
488
489                 // Write out the header + text & data + symbol table (if any)
490                 unused = write(fd, buf, HDRSIZE + tds + symsize);
491
492                 // Construct and write relocation information; the size of it changes if
493                 // we're writing a RELMODed executable. N.B.: Destroys buffer!
494                 tds = MarkImage(buf, tds, sect[TEXT].sloc, 1);
495                 unused = write(fd, buf, tds);
496         }
497         else if (obj_format == ELF)
498         {
499                 // Allocate 6MB object file image memory
500                 buf = malloc(0x600000);
501
502                 if (buf == NULL)
503                 {
504                         error("cannot allocate object file memory (in ELF mode)");
505                         return ERROR;
506                 }
507
508                 memset(buf, 0, 0x600000);
509                 objImage = buf;                                 // Set global object image pointer
510                 strtable = malloc(0x200000);    // Allocate 2MB string table buffer
511
512                 if (strtable == NULL)
513                 {
514                         error("cannot allocate string table memory (in ELF mode)");
515                         return ERROR;
516                 }
517
518                 memset(strtable, 0, 0x200000);
519
520                 // This is pretty much a first pass at this shite, so there's room for
521                 // improvement. :-P
522                 uint8_t headers[4 * 10 * 10];   // (DWORD * 10) = 1 hdr, 10 entries
523                 int headerSize = 0;
524                 uint8_t shstrtab[128];                  // The section header string table proper
525                 uint32_t shstTab[9];                    // Index into shstrtab for strings
526                 uint8_t * shstPtr = shstrtab;   // Temp pointer
527                 uint32_t shstSize = 0;
528                 int numEntries = 4;                             // There are always at *least* 4 sections
529                 int shstIndex = 1;                              // The section where the shstrtab lives
530                 int elfSize = 0;                                // Size of the ELF object
531                 // Clear the header numbers
532                 memset(elfHdrNum, 0, 9 * sizeof(int));
533
534                 //
535                 // First step is to see what sections need to be made; we also
536                 // construct the section header string table here at the same time.
537                 //
538                 shstTab[ES_NULL] = shstSize;
539                 shstSize += DepositELFSHSTEntry(&shstPtr, "");
540                 shstTab[ES_SHSTRTAB] = shstSize;
541                 shstSize += DepositELFSHSTEntry(&shstPtr, ".shstrtab");
542                 shstTab[ES_SYMTAB] = shstSize;
543                 shstSize += DepositELFSHSTEntry(&shstPtr, ".symtab");
544                 shstTab[ES_STRTAB] = shstSize;
545                 shstSize += DepositELFSHSTEntry(&shstPtr, ".strtab");
546
547                 if (sect[TEXT].sloc > 0)
548                 {
549                         elfHdrNum[ES_TEXT] = shstIndex;
550                         shstTab[ES_TEXT] = shstSize;
551                         shstSize += DepositELFSHSTEntry(&shstPtr, ".text");
552                         shstIndex++;
553                         numEntries++;
554                 }
555
556                 if (sect[DATA].sloc > 0)
557                 {
558                         elfHdrNum[ES_DATA] = shstIndex;
559                         shstTab[ES_DATA] = shstSize;
560                         shstSize += DepositELFSHSTEntry(&shstPtr, ".data");
561                         shstIndex++;
562                         numEntries++;
563                 }
564
565                 if (sect[BSS].sloc > 0)
566                 {
567                         elfHdrNum[ES_BSS] = shstIndex;
568                         shstTab[ES_BSS] = shstSize;
569                         shstSize += DepositELFSHSTEntry(&shstPtr, ".bss");
570                         shstIndex++;
571                         numEntries++;
572                 }
573
574                 if (sect[TEXT].relocs > 0)
575                 {
576                         elfHdrNum[ES_RELATEXT] = shstIndex;
577                         shstTab[ES_RELATEXT] = shstSize;
578                         shstSize += DepositELFSHSTEntry(&shstPtr, ".relaTEXT");
579                         shstIndex++;
580                         numEntries++;
581                 }
582
583                 if (sect[DATA].relocs > 0)
584                 {
585                         elfHdrNum[ES_RELADATA] = shstIndex;
586                         shstTab[ES_RELADATA] = shstSize;
587                         shstSize += DepositELFSHSTEntry(&shstPtr, ".relaDATA");
588                         shstIndex++;
589                         numEntries++;
590                 }
591
592                 elfHdrNum[ES_SHSTRTAB] = shstIndex + 0;
593                 elfHdrNum[ES_SYMTAB]   = shstIndex + 1;
594                 elfHdrNum[ES_STRTAB]   = shstIndex + 2;
595
596 #ifdef DEBUG_ELF
597 printf("ELF shstrtab size: %i bytes. Entries:\n", shstSize);
598 for(int j=0; j<i; j++)
599         printf("\"%s\"\n", shstrtab + shstTab[j]);
600 #endif
601
602                 // Construct ELF header
603                 // If you want to make any sense out of this you'd better take a look
604                 // at Executable and Linkable Format on Wikipedia.
605                 chptr = buf;
606                 ch_size = 0;
607                 challoc = 0x600000;
608                 D_long(0x7F454C46); // 00 - "<7F>ELF" Magic Number
609                 D_byte(0x01); // 04 - 32 vs 64 (1 = 32, 2 = 64)
610                 D_byte(0x02); // 05 - Endianness (1 = LE, 2 = BE)
611                 D_byte(0x01); // 06 - Original version of ELF (set to 1)
612                 D_byte(0x00); // 07 - Target OS ABI (0 = System V)
613                 D_byte(0x00); // 08 - ABI Extra (unneeded)
614                 D_byte(0x00); // 09 - Pad bytes
615                 D_word(0x00);
616                 D_long(0x00);
617                 D_word(0x01); // 10 - ELF Type (1 = relocatable)
618                 D_word(0x04); // 12 - Architecture (EM_68K = 4, Motorola M68K family)
619                 D_long(0x01); // 14 - Version (1 = original ELF)
620                 D_long(0x00); // 18 - Entry point virtual address (unneeded)
621                 D_long(0x00); // 1C - Program header table offset (unneeded)
622                 D_long(0x00); // 20 - Section header table offset (to be determined)
623
624                 if (0)
625                 {
626                         // Specifically for 68000 CPU
627                         D_long(0x01000000) // 24 - Processor-specific flags - EF_M68K_M68000
628                 }
629                 else
630                 {
631                         // CPUs other than 68000 (68020...)
632                         D_long(0); // 24 - Processor-specific flags (ISA dependent)
633                 }
634
635                 D_word(0x0034); // 28 - ELF header size in bytes
636                 D_word(0); // 2A - Program header table entry size
637                 D_word(0); // 2C - Program header table entry count
638                 D_word(0x0028); // 2E - Section header entry size - 40 bytes for ELF32
639                 D_word(numEntries); // 30 - Section header table entry count
640                 D_word(shstIndex); // 32 - Section header string table index
641
642                 elfSize += 0x34;
643
644                 // Deposit section header 0 (NULL)
645                 headerSize += DepositELFSectionHeader(headers + headerSize, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
646
647                 int textLoc = elfSize;
648
649                 // Construct TEXT section, if any
650                 if (sect[TEXT].sloc > 0)
651                 {
652                         headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_TEXT], 1, 6, 0, elfSize, sect[TEXT].sloc, 0, 0, largestAlign[0], 0);
653
654                         for(CHUNK * cp=sect[TEXT].sfcode; cp!=NULL; cp=cp->chnext)
655                         {
656                                 memcpy(buf + elfSize, cp->chptr, cp->ch_size);
657                                 elfSize += cp->ch_size;
658                         }
659
660                         // Pad for next section (LONG boundary)
661                         elfSize = (elfSize + 3) & ~3;
662                 }
663
664                 int dataLoc = elfSize;
665
666                 // Construct DATA section, if any
667                 if (sect[DATA].sloc > 0)
668                 {
669                         headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_DATA], 1, 3, 0, elfSize, sect[DATA].sloc, 0, 0, largestAlign[1], 0);
670
671                         for(CHUNK * cp=sect[DATA].sfcode; cp!=NULL; cp=cp->chnext)
672                         {
673                                 memcpy(buf + elfSize, cp->chptr, cp->ch_size);
674                                 elfSize += cp->ch_size;
675                         }
676
677                         // Pad for next section (LONG boundary)
678                         elfSize = (elfSize + 3) & ~3;
679                 }
680
681                 // Construct BSS section, if any
682                 if (sect[BSS].sloc > 0)
683                 {
684                         headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_BSS], 8, 3, 0, elfSize, sect[BSS].sloc, 0, 0, largestAlign[2], 0);
685                 }
686
687                 int textrelLoc = headerSize;
688
689                 // Add headers for relocated sections, if any...
690                 if (sect[TEXT].relocs > 0)
691                         headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_RELATEXT], 4, 0x00, 0, 0, 0, elfHdrNum[ES_SYMTAB], elfHdrNum[ES_TEXT], 4, 0x0C);
692
693                 int datarelLoc = headerSize;
694
695                 if (sect[DATA].relocs > 0)
696                         headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_RELADATA], 4, 0x40, 0, 0, 0, elfHdrNum[ES_SYMTAB], elfHdrNum[ES_DATA], 4, 0x0C);
697
698                 // Add shstrtab
699                 headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_SHSTRTAB], 3, 0, 0, elfSize, shstSize, 0, 0, 1, 0);
700                 memcpy(buf + elfSize, shstrtab, shstSize);
701                 elfSize += shstSize;
702                 // Pad for next section (LONG boundary)
703                 elfSize = (elfSize + 3) & ~3;
704
705                 // Add section headers
706                 int headerLoc = elfSize;
707                 chptr = buf + 0x20;             // Set section header offset in ELF header
708                 D_long(headerLoc);
709                 elfSize += (4 * 10) * numEntries;
710
711                 // Add symbol table & string table
712                 int symtabLoc = elfSize;
713                 strindx = 0;    // Make sure we start at the beginning...
714                 elfSize += DepositELFSymbol(buf + elfSize, 0, 0, 0, 0, 0, 0);
715                 *strtable = 0;
716                 strindx++;
717                 extraSyms = 1;
718
719                 if (sect[TEXT].sloc > 0)
720                 {
721                         elfSize += DepositELFSymbol(buf + elfSize, 0, 0, 0, 3, 0, elfHdrNum[ES_TEXT]);
722                         extraSyms++;
723                 }
724
725                 if (sect[DATA].sloc > 0)
726                 {
727                         elfSize += DepositELFSymbol(buf + elfSize, 0, 0, 0, 3, 0, elfHdrNum[ES_DATA]);
728                         extraSyms++;
729                 }
730
731                 if (sect[BSS].sloc > 0)
732                 {
733                         elfSize += DepositELFSymbol(buf + elfSize, 0, 0, 0, 3, 0, elfHdrNum[ES_BSS]);
734                         extraSyms++;
735                 }
736
737                 int numSymbols = sy_assign_ELF(buf + elfSize, AddELFSymEntry);
738                 elfSize += numSymbols * 0x10;
739
740                 // String table
741                 int strtabLoc = elfSize;
742                 memcpy(buf + elfSize, strtable, strindx);
743                 elfSize += strindx;
744                 // Pad for next section (LONG boundary)
745                 elfSize = (elfSize + 3) & ~3;
746
747                 headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_SYMTAB], 2, 0, 0, symtabLoc, (numSymbols + extraSyms) * 0x10, shstIndex + 2, firstglobal + extraSyms, 4, 0x10);
748                 headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_STRTAB], 3, 0, 0, strtabLoc, strindx, 0, 0, 1, 0);
749
750                 // Add relocation tables, if any (no need to align after these, they're
751                 // already on DWORD boundaries)
752                 if (sect[TEXT].relocs > 0)
753                 {
754                         uint32_t textrelSize = CreateELFRelocationRecord(buf + elfSize, buf + textLoc, TEXT);
755                         // Deposit offset & size, now that we know them
756                         chptr = headers + textrelLoc + 0x10;
757                         D_long(elfSize);
758                         D_long(textrelSize);
759                         elfSize += textrelSize;
760                 }
761
762                 if (sect[DATA].relocs > 0)
763                 {
764                         uint32_t datarelSize = CreateELFRelocationRecord(buf + elfSize, buf + dataLoc, DATA);
765                         // Deposit offset & size, now that we know them
766                         chptr = headers + datarelLoc + 0x10;
767                         D_long(elfSize);
768                         D_long(datarelSize);
769                         elfSize += datarelSize;
770                 }
771
772                 // Copy headers into the object
773                 memcpy(buf + headerLoc, headers, headerSize);
774
775                 // Finally, write out the object
776                 unused = write(fd, buf, elfSize);
777
778                 // Free allocated memory
779                 if (buf)
780                 {
781                         free(buf);
782                         free(strtable);
783                 }
784         }
785         else if (obj_format == XEX)
786         {
787                 // Just write the object file
788                 m6502obj(fd);
789         }
790         else if (obj_format == P56 || obj_format == LOD)
791         {
792                 // Allocate 6MB object file image memory
793                 uint8_t * buf = malloc(0x600000);
794
795                 if (buf == NULL)
796                         return error("cannot allocate object file memory (in P56/LOD mode)");
797
798 //              objImage = buf;                                 // Set global object image pointer
799
800                 memset(buf, 0, 0x600000);               // Clear allocated memory
801
802                 // Iterate through DSP ram buffers
803                 chptr = buf;                                    // -> base of header
804                 ch_size = 0;
805                 challoc = 0x600000;
806
807                 if (obj_format == LOD)
808                         WriteLOD();
809                 else
810                         WriteP56();
811
812                 // Write all the things |o/
813                 ssize_t unused = write(fd, buf, chptr - buf);
814
815                 if (buf)
816                         free(buf);
817         }
818
819         return 0;
820 }
821
822
823 static void WriteLOD(void)
824 {
825         D_printf("_START %s 0000 0000 0000 RMAC %01i.%01i.%01i\n\n", firstfname, MAJOR, MINOR, PATCH);
826
827         for(DSP_ORG * l=&dsp_orgmap[0]; l<dsp_currentorg; l++)
828         {
829                 if (l->end != l->start)
830                 {
831                         switch (l->memtype)
832                         {
833                         case ORG_P: D_printf("_DATA P %.4X\n", l->orgadr); break;
834                         case ORG_X: D_printf("_DATA X %.4X\n", l->orgadr); break;
835                         case ORG_Y: D_printf("_DATA Y %.4X\n", l->orgadr); break;
836                         case ORG_L: D_printf("_DATA L %.4X\n", l->orgadr); break;
837                         default:
838                                 error("Internal error: unknown DSP56001 org'd section");
839                                 return;
840                         }
841
842                         CHUNK * cp = l->chunk;
843                         uint8_t * p_chunk = l->start;
844                         uint8_t * p_chunk_end = p_chunk;
845                         uint32_t j = 0;
846
847                         while (p_chunk_end != l->end)
848                         {
849                                 if (l->end < (cp->chptr + cp->ch_size) && l->end > cp->chptr)
850                                 {
851                                         // If the end of the section is inside the current chunk, just dump everything and stop
852                                         p_chunk_end = l->end;
853                                 }
854                                 else
855                                 {
856                                         // If the end of the section is not inside the current chunk, just dump everything from the current chunk and move on to the next
857                                         p_chunk_end = cp->chptr + cp->ch_size;
858                                 }
859
860                                 uint32_t count = (uint32_t)(p_chunk_end - p_chunk);
861
862                                 for(uint32_t i=0; i<count; i+=3)
863                                 {
864                                         if ((j & 7) != 7)
865                                         {
866                                                 D_printf("%.6X ", (((p_chunk[0] << 8) | p_chunk[1]) << 8) | p_chunk[2]);
867                                         }
868                                         else
869                                         {
870                                                 D_printf("%.6X\n", (((p_chunk[0] << 8) | p_chunk[1]) << 8) | p_chunk[2]);
871                                         }
872
873                                         p_chunk += 3;
874                                         j++;
875                                 }
876
877                                 cp = cp->chnext;        // Advance chunk
878
879                                 if (cp != NULL)
880                                         p_chunk = cp->chptr;    // Set dump pointer to start of this chunk
881                         }
882
883                         if ((j & 7) != 0)
884                                 D_printf("\n");
885                 }
886         }
887
888         // Dump the symbol table into the buf
889         DumpLODSymbols();
890
891         D_printf("\n_END %.4X\n", dsp_orgmap[0].orgadr);
892 }
893
894
895 static void WriteP56(void)
896 {
897         for(DSP_ORG * l=&dsp_orgmap[0]; l<dsp_currentorg; l++)
898         {
899                 if (l->end == l->start)
900                         continue;
901
902                 if ((l->memtype < ORG_P) || (l->memtype > ORG_L))
903                 {
904                         error("Internal error: unknown DSP56001 org'd section");
905                         return;
906                 }
907
908                 CHUNK * cp = l->chunk;
909                 uint8_t * p_chunk = l->start;
910                 uint8_t * p_chunk_end = p_chunk;
911
912                 // Memory type (P, X, Y or L)
913                 D_dsp(l->memtype);
914
915                 // Chunk start address (in DSP words)
916                 D_dsp(l->orgadr);
917
918                 // Chunk length (in DSP words)
919                 // We'll fill this field after we write the chunk so we can calculate
920                 // how long it is (so if the chunk is split into different CHUNKs we
921                 // can deal with this during copy)
922                 uint8_t * p_buf_len = chptr;
923                 chptr += 3;
924
925                 // The chunk itself
926                 uint32_t chunk_size = 0;
927
928                 while (p_chunk_end != l->end)
929                 {
930                         if (l->end < (cp->chptr + cp->ch_size) && l->end > cp->chptr)
931                         {
932                                 // If the end of the section is inside the current chunk, just
933                                 // dump everything and stop
934                                 p_chunk_end = l->end;
935                         }
936                         else
937                         {
938                                 // If the end of the section is not inside the current chunk,
939                                 // just dump everything from the current chunk and move on to
940                                 // the next
941                                 p_chunk_end = cp->chptr + cp->ch_size;
942                         }
943
944                         uint32_t current_chunk_size = p_chunk_end - p_chunk;
945                         chunk_size += current_chunk_size;
946                         memcpy(chptr, p_chunk, current_chunk_size);
947                         chptr += current_chunk_size;
948
949                         cp = cp->chnext;        // Advance chunk
950
951                         if (cp != NULL)
952                                 p_chunk = cp->chptr;    // Set dump pointer to start of this chunk
953                 }
954
955                 // Now we can mark the chunk's length (DSP word size is 24-bits, so
956                 // the byte count needs to be divided by 3)
957                 SETBE24(p_buf_len, chunk_size / 3);
958         }
959 }
960