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