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