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