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