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