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