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