af019f07c14a8ef32d78e04d655840443d131040
[rmac] / object.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // OBJECT.C - Writing Object Files
4 // Copyright (C) 199x Landon Dyer, 2017 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 "error.h"
11 #include "mark.h"
12 #include "riscasm.h"
13 #include "sect.h"
14 #include "symbol.h"
15 extern void m6502obj(int ofd);
16
17 //#define DEBUG_ELF
18
19 uint32_t symsize = 0;                   // Size of BSD/ELF symbol table
20 uint32_t strindx = 0x00000004;  // BSD/ELF string table index
21 uint8_t * strtable;                             // Pointer to the symbol string table
22 uint8_t * objImage;                             // Global object image pointer
23 int elfHdrNum[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
24 uint32_t extraSyms;
25
26 static uint16_t tdb_tab[] = {
27         0,                              // absolute
28         AL_TEXT,                // TEXT segment based
29         AL_DATA, 0,             // DATA segment based
30         AL_BSS                  // BSS segment based
31 };
32
33 uint32_t PRGFLAGS;      /* PRGFLAGS as defined in Atari Compendium Chapter 2
34 Definition              Bit(s)  Meaning
35 --------------- ------- --------------------------------------------------------
36 PF_FASTLOAD             0               If set, clear only the BSS area on program load,
37                                                 otherwise clear the entire heap.
38 PF_TTRAMLOAD    1               If set, the program may be loaded into alternative RAM,
39                                                 otherwise it must be loaded into standard RAM.
40 PF_TTRAMMEM             2               If set, the program's Malloc() requests may be satisfied
41                                                 from alternative RAM, otherwise they must be satisfied
42                                                 from standard RAM.
43 -                               3               Currently unused
44 See left.               4 & 5   If these bits are set to 0 (PF_PRIVATE), the processes'
45                                                 entire memory space will be considered private
46                                                 (when memory protection is enabled).If these bits are
47                                                 set to 1 (PF_GLOBAL), the processes' entire memory space
48                                                 will be readable and writable by any process (i.e.
49                                                 global). If these bits are set to 2 (PF_SUPERVISOR), the
50                                                 processes' entire memory space will only be readable and
51                                                 writable by itself and any other process in supervisor
52                                                 mode.If these bits are set to 3 (PF_READABLE), the
53                                                 processes' entire memory space will be readable by any
54                                                 application but only writable by itself.
55 -                               6-15    Currently unused
56 */
57
58
59 //
60 // Add entry to symbol table (in ALCYON mode)
61 // If 'globflag' is 1, make the symbol global
62 // If in .PRG mode, adjust symbol values for fake link
63 //
64 uint8_t * AddSymEntry(register uint8_t * buf, SYM * sym, int globflag)
65 {
66         // Copy symbol name to buffer (first 8 chars or less)
67         register uint8_t * s = sym->sname;
68         register int i;
69
70         for(i=0; i<8 && *s; i++)
71                 *buf++ = *s++;
72
73         while (i++ < 8)
74                 *buf++ = '\0';
75
76         //
77         // Construct and deposit flag word
78         //
79         // o  all symbols are AL_DEFINED
80         // o  install T/D/B/A base
81         //   o  install 'equated'
82         //   o  commons (COMMON) are AL_EXTERN, but not BSS
83         // o  exports (DEFINED) are AL_GLOBAL
84         // o  imports (~DEFINED) are AL_EXTERN
85         //
86         register uint16_t w1 = sym->sattr;
87         register uint16_t w = AL_DEFINED | tdb_tab[w1 & TDB];
88
89         if (w1 & EQUATED)               // Equated
90                 w |= AL_EQUATED;
91
92         if (w1 & COMMON)
93         {
94                 w |= AL_EXTERN | AL_GLOBAL;     // Common symbol
95                 w &= ~AL_BSS;           // They're not BSS in Alcyon object files
96         }
97         else if (w1 & DEFINED)
98         {
99                 if (globflag)           // Export the symbol
100                         w |= AL_GLOBAL;
101         }
102         else
103                 w |= AL_EXTERN;         // Imported symbol
104
105         SETBE16(buf, 0, w);
106         buf += 2;
107         register uint32_t z = sym->svalue;
108
109         if (prg_flag)                   // Relocate value in .PRG segment
110         {
111                 w1 &= DATA | BSS;
112
113                 if (w1)
114                         z += sect[TEXT].sloc;
115
116                 if (w1 & BSS)
117                         z += sect[DATA].sloc;
118         }
119
120         SETBE32(buf, 0, z);             // Deposit symbol value
121         buf += 4;
122
123         return buf;
124 }
125
126
127 //
128 // Add an entry to the BSD symbol table
129 //
130 uint8_t * AddBSDSymEntry(uint8_t * buf, SYM * sym, int globflag)
131 {
132         chptr = buf;                                            // Point to buffer for depositing longs
133         D_long(strindx);                                        // Deposit the symbol string index
134
135         uint16_t w1 = sym->sattr;                       // Obtain symbol attributes
136         uint32_t z = 0;                                         // Initialize resulting symbol flags
137
138         if (w1 & EQUATED)
139         {
140                 z = 0x02000000;                                 // Set equated flag
141         }
142         else
143         {
144                 switch (w1 & TDB)
145                 {
146                 case TEXT: z = 0x04000000; break;       // Set TEXT segment flag
147                 case DATA: z = 0x06000000; break;       // Set DATA segment flag
148                 case BSS : z = 0x08000000; break;       // Set BSS segment flag
149                 }
150         }
151
152         if (globflag)
153                 z |= 0x01000000;                                // Set global flag if requested
154
155         D_long(z);                                                      // Deposit symbol attribute
156         z = sym->svalue;                                        // Obtain symbol value
157
158         if (w1 & (DATA | BSS))
159                 z += sect[TEXT].sloc;                   // If DATA or BSS add TEXT segment size
160
161         if (w1 & BSS)
162                 z += sect[DATA].sloc;                   // If BSS add DATA segment size
163
164         D_long(z);                                                      // Deposit symbol value
165         strcpy(strtable + strindx, sym->sname);
166         strindx += strlen(sym->sname) + 1;      // Incr string index incl null terminate
167         buf += 12;                                                      // Increment buffer to next record
168         symsize += 12;                                          // Increment symbol table size
169
170         return buf;
171 }
172
173
174 //
175 // Add entry to ELF symbol table; if `globflag' is 1, make the symbol global
176 //
177 uint8_t * AddELFSymEntry(uint8_t * buf, SYM * sym, int globflag)
178 {
179         chptr = buf;
180         D_long(strindx);                // st_name
181         D_long(sym->svalue);    // st_value
182         D_long(0);                              // st_size
183         uint8_t st_info = 0;
184
185         register WORD w1 = sym->sattr;
186
187         if (w1 & COMMON)
188         {
189                 //w |= AL_EXTERN | AL_GLOBAL;   // common symbol
190                 //w &= ~AL_BSS;         // they're not BSS in Alcyon object files
191         }
192         else if (w1 & DEFINED)
193         {
194                 if (globflag)           // Export the symbol
195                         st_info |= 16;   //STB_GLOBAL (1<<4)
196         }
197         else if (w1 & (GLOBAL | REFERENCED))
198                 st_info |= 16;
199
200         D_byte(st_info);
201         D_byte(0);                              // st_other
202
203         uint16_t st_shndx = 0xFFF1;     // Assume absolute (equated) number
204
205         if (w1 & TEXT)
206                 st_shndx = elfHdrNum[ES_TEXT];
207         else if (w1 & DATA)
208                 st_shndx = elfHdrNum[ES_DATA];
209         else if (w1 & BSS)
210                 st_shndx = elfHdrNum[ES_BSS];
211         else if (globflag)
212                 st_shndx = 0;           // Global, not absolute
213
214         D_word(st_shndx);
215
216         strcpy(strtable + strindx, sym->sname);
217         strindx += strlen(sym->sname) + 1;      // Incr string index incl null terminate
218         symsize += 0x10;                                        // Increment symbol table size
219
220         return buf + 0x10;
221 }
222
223
224 //
225 // Helper function for ELF output
226 //
227 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)
228 {
229         chptr = ptr;
230         D_long(name);
231         D_long(type);
232         D_long(flags);
233         D_long(addr);
234         D_long(offset);
235         D_long(size);
236         D_long(link);
237         D_long(info);
238         D_long(addralign);
239         D_long(entsize);
240         return 40;
241 }
242
243
244 //
245 // Deposit an entry in the Section Header string table
246 //
247 uint32_t DepositELFSHSTEntry(uint8_t ** pTable, const uint8_t * s)
248 {
249 #ifdef DEBUG_ELF
250 printf("DepositELFSHSTEntry: s = \"%s\"\n", s);
251 #endif
252         uint32_t strSize = strlen(s);
253         strcpy(*pTable, s);
254         *pTable += strSize + 1;
255         return strSize + 1;
256 }
257
258
259 //
260 // Deposit a symbol table entry in the ELF Symbol Table
261 //
262 uint32_t DepositELFSymbol(uint8_t * ptr, uint32_t name, uint32_t addr, uint32_t size, uint8_t info, uint8_t other, uint16_t shndx)
263 {
264         chptr = ptr;
265         D_long(name);
266         D_long(addr);
267         D_long(size);
268         *chptr++ = info;
269         *chptr++ = other;
270         D_word(shndx);
271         return 16;
272 }
273
274
275 //
276 // Write an object file to the passed in file descriptor
277 // N.B.: Return value is ignored...
278 //
279 int WriteObject(int fd)
280 {
281         LONG t;                                 // Scratch long
282         LONG tds;                               // TEXT & DATA segment size
283         int i;                                  // Temporary int
284         CHUNK * cp;                             // Chunk (for gather)
285         uint8_t * buf;                  // Scratch area
286         uint8_t * p;                    // Temporary ptr
287         LONG ssize;                             // Size of symbols
288         LONG trsize, drsize;    // Size of relocations
289         long unused;                    // For supressing 'write' warnings
290
291         if (verb_flag)
292         {
293                 printf("TEXT segment: %d bytes\n", sect[TEXT].sloc);
294                 printf("DATA segment: %d bytes\n", sect[DATA].sloc);
295                 printf("BSS  segment: %d bytes\n", sect[BSS].sloc);
296         }
297
298         // Write requested object file...
299         if ((obj_format == BSD) || ((obj_format == ALCYON) && (prg_flag == 0)))
300     {
301                 // Force BSD format (if it was ALCYON format)
302                 obj_format = BSD;
303
304                 if (verb_flag)
305                 {
306                         printf("Total       : %d bytes\n", sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc);
307                 }
308
309                 ssize = sy_assign(NULL, NULL);                          // Assign index numbers to the symbols
310                 tds = sect[TEXT].sloc + sect[DATA].sloc;        // Get size of TEXT and DATA segment
311                 buf = malloc(0x600000);                                         // Allocate 6mb object file image memory
312
313                 if (buf == NULL)
314                 {
315                         error("cannot allocate object file memory (in BSD mode)");
316                         return ERROR;
317                 }
318
319                 memset(buf, 0, 0x600000);               // Clear allocated memory
320                 objImage = buf;                                 // Set global object image pointer
321                 strtable = malloc(0x200000);    // Allocate 2MB string table buffer
322
323                 if (strtable == NULL)
324                 {
325                         error("cannot allocate string table memory (in BSD mode)");
326                         return ERROR;
327                 }
328
329                 memset(strtable, 0, 0x200000);  // Clear allocated memory
330
331                 // Build object file header
332                 chptr = buf;                                    // Base of header (for D_foo macros)
333                 D_long(0x00000107);                             // Magic number
334                 D_long(sect[TEXT].sloc);                // TEXT size
335                 D_long(sect[DATA].sloc);                // DATA size
336                 D_long(sect[BSS].sloc);                 // BSS size
337                 D_long(0x00000000);                             // Symbol size
338                 D_long(0x00000000);                             // First entry (0L)
339                 D_long(0x00000000);                             // TEXT relocation size
340                 D_long(0x00000000);                             // DATA relocation size
341
342                 // Construct TEXT and DATA segments (without relocation changes)
343                 p = buf + BSDHDRSIZE;
344
345                 for(i=TEXT; i<=DATA; i++)
346                 {
347                         for(cp=sect[i].sfcode; cp!=NULL; cp=cp->chnext)
348                         {
349                                 memcpy(p, cp->chptr, cp->ch_size);
350                                 p += cp->ch_size;
351                         }
352                 }
353
354                 // Do relocation tables (and make changes to segment data)
355                 p = buf + BSDHDRSIZE + tds;             // Move obj image ptr to reloc info
356                 trsize = MarkBSDImage(p, tds, sect[TEXT].sloc, TEXT);// Do TEXT relocation table
357                 chptr = buf + 0x18;                             // Point to relocation hdr entry
358                 D_long(trsize);                                 // Write the relocation table size
359
360                 // Move obj image ptr to reloc info
361                 p = buf + BSDHDRSIZE + tds + trsize;
362                 drsize = MarkBSDImage(p, tds, sect[TEXT].sloc, DATA);// Do DATA relocation table
363                 chptr = buf + 0x1C;                             // Point to relocation hdr entry
364                 D_long(drsize);                                 // Write the relocation table size
365
366                 // Point to start of symbol table
367                 p = buf + BSDHDRSIZE + tds + trsize + drsize;
368                 sy_assign(p, AddBSDSymEntry);   // Build symbol and string tables
369                 chptr = buf + 0x10;                             // Point to sym table size hdr entry
370                 D_long(symsize);                                // Write the symbol table size
371
372                 // Point to string table
373                 p = buf + BSDHDRSIZE + tds + trsize + drsize + symsize;
374                 memcpy(p, strtable, strindx);   // Copy string table to object image
375                 chptr = p;                                              // Point to string table size long
376                 D_long(strindx);                                // Write string table size
377
378                 // Write the BSD object file from the object image buffer
379                 unused = write(fd, buf, BSDHDRSIZE + tds + trsize + drsize + symsize + strindx + 4);
380
381                 if (verb_flag)
382                 {
383                         printf("TextRel size: %d bytes\n", trsize);
384                         printf("DataRel size: %d bytes\n", drsize);
385                 }
386
387                 if (buf)
388                 {
389                         free(strtable);                         // Free allocated memory
390                         free(buf);                                      // Free allocated memory
391                 }
392         }
393         else if (obj_format == ALCYON)
394         {
395                 if (verb_flag)
396                 {
397                         if (prg_flag)
398                         {
399                                 printf("TOS header  : 28 bytes\n");
400                                 printf("Total       : %d bytes\n", 28 + sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc);
401                         }
402                         else
403                         {
404                                 printf("Total       : %d bytes\n", sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc);
405                         }
406                 }
407
408                 // Compute size of symbol table; assign numbers to the symbols...
409                 ssize = 0;
410
411                 // As we grabbed BSD *and* Alcyon in prg_flag == 0 mode, this is *always*
412                 // false... :-P
413                 if (prg_flag != 1)
414                         ssize = sy_assign(NULL, NULL) * 14;
415
416                 // Alloc memory for header + text + data, symbol and relocation
417                 // information construction.
418                 t = tds = sect[TEXT].sloc + sect[DATA].sloc;
419
420                 if (t < ssize)
421                         t = ssize;
422
423                 // Is there any reason to do this this way???
424                 buf = malloc(t + HDRSIZE);
425                 buf += HDRSIZE;
426
427                 // Build object file header just before the text+data image
428                 chptr = buf - HDRSIZE;          // -> base of header
429                 D_word(0x601A);                         // 00 - magic number
430                 D_long(sect[TEXT].sloc);        // 02 - TEXT size
431                 D_long(sect[DATA].sloc);        // 06 - DATA size
432                 D_long(sect[BSS].sloc);         // 0A - BSS size
433                 D_long(ssize);                          // 0E - symbol table size
434                 D_long(0);                                      // 12 - stack size (unused)
435                 D_long(PRGFLAGS);                       // 16 - PRGFLAGS
436                 D_word(0);                                      // 1A - relocation information exists
437
438                 // Construct text and data segments; fixup relocatable longs in .PRG
439                 // mode; finally write the header + text + data
440                 p = buf;
441
442                 for(i=TEXT; i<=DATA; i++)
443                 {
444                         for(cp=sect[i].sfcode; cp!=NULL; cp=cp->chnext)
445                         {
446                                 memcpy(p, cp->chptr, cp->ch_size);
447                                 p += cp->ch_size;
448                         }
449                 }
450
451                 // Do a first pass on the Alcyon image, if in PRG mode
452                 if (prg_flag)
453                         MarkImage(buf, tds, sect[TEXT].sloc, 0);
454
455                 unused = write(fd, buf - HDRSIZE, tds + HDRSIZE);
456
457                 // Construct and write symbol table
458                 if (prg_flag != 1)
459                 {
460                         sy_assign(buf, AddSymEntry);
461                         unused = write(fd, buf, ssize);
462                 }
463
464                 // Construct and write relocation information; the size of it changes if
465                 // we're writing a RELMODed executable.
466                 tds = MarkImage(buf, tds, sect[TEXT].sloc, 1);
467                 unused = write(fd, buf, tds);
468         }
469         else if (obj_format == ELF)
470         {
471                 // Allocate 6MB object file image memory
472                 buf = malloc(0x600000);
473
474                 if (buf == NULL)
475                 {
476                         error("cannot allocate object file memory (in BSD mode)");
477                         return ERROR;
478                 }
479
480                 memset(buf, 0, 0x600000);
481                 objImage = buf;                                 // Set global object image pointer
482                 strtable = malloc(0x200000);    // Allocate 2MB string table buffer
483
484                 if (strtable == NULL)
485                 {
486                         error("cannot allocate string table memory (in BSD mode)");
487                         return ERROR;
488                 }
489
490                 memset(strtable, 0, 0x200000);
491
492                 // This is pretty much a first pass at this shite, so there's room for
493                 // improvement. :-P
494                 uint8_t headers[4 * 10 * 10];   // (DWORD * 10) = 1 hdr, 10 entries
495                 int headerSize = 0;
496                 uint8_t shstrtab[128];                  // The section header string table proper
497                 uint32_t shstTab[9];                    // Index into shstrtab for strings
498                 uint8_t * shstPtr = shstrtab;   // Temp pointer
499                 uint32_t shstSize = 0;
500                 int numEntries = 4;                             // There are always at *least* 4 sections
501                 int shstIndex = 1;                              // The section where the shstrtab lives
502                 int elfSize = 0;                                // Size of the ELF object
503                 // Clear the header numbers
504                 memset(elfHdrNum, 0, 9 * sizeof(int));
505
506                 //
507                 // First step is to see what sections need to be made; we also
508                 // construct the section header string table here at the same time.
509                 //
510                 shstTab[ES_NULL] = shstSize;
511                 shstSize += DepositELFSHSTEntry(&shstPtr, "");
512                 shstTab[ES_SHSTRTAB] = shstSize;
513                 shstSize += DepositELFSHSTEntry(&shstPtr, ".shstrtab");
514                 shstTab[ES_SYMTAB] = shstSize;
515                 shstSize += DepositELFSHSTEntry(&shstPtr, ".symtab");
516                 shstTab[ES_STRTAB] = shstSize;
517                 shstSize += DepositELFSHSTEntry(&shstPtr, ".strtab");
518
519                 if (sect[TEXT].sloc > 0)
520                 {
521                         elfHdrNum[ES_TEXT] = shstIndex;
522                         shstTab[ES_TEXT] = shstSize;
523                         shstSize += DepositELFSHSTEntry(&shstPtr, "TEXT");
524                         shstIndex++;
525                         numEntries++;
526                 }
527
528                 if (sect[DATA].sloc > 0)
529                 {
530                         elfHdrNum[ES_DATA] = shstIndex;
531                         shstTab[ES_DATA] = shstSize;
532                         shstSize += DepositELFSHSTEntry(&shstPtr, "DATA");
533                         shstIndex++;
534                         numEntries++;
535                 }
536
537                 if (sect[BSS].sloc > 0)
538                 {
539                         elfHdrNum[ES_BSS] = shstIndex;
540                         shstTab[ES_BSS] = shstSize;
541                         shstSize += DepositELFSHSTEntry(&shstPtr, "BSS");
542                         shstIndex++;
543                         numEntries++;
544                 }
545
546                 if (sect[TEXT].relocs > 0)
547                 {
548                         elfHdrNum[ES_RELATEXT] = shstIndex;
549                         shstTab[ES_RELATEXT] = shstSize;
550                         shstSize += DepositELFSHSTEntry(&shstPtr, ".relaTEXT");
551                         shstIndex++;
552                         numEntries++;
553                 }
554
555                 if (sect[DATA].relocs > 0)
556                 {
557                         elfHdrNum[ES_RELADATA] = shstIndex;
558                         shstTab[ES_RELADATA] = shstSize;
559                         shstSize += DepositELFSHSTEntry(&shstPtr, ".relaDATA");
560                         shstIndex++;
561                         numEntries++;
562                 }
563
564                 elfHdrNum[ES_SHSTRTAB] = shstIndex + 0;
565                 elfHdrNum[ES_SYMTAB]   = shstIndex + 1;
566                 elfHdrNum[ES_STRTAB]   = shstIndex + 2;
567
568 #ifdef DEBUG_ELF
569 printf("ELF shstrtab size: %i bytes. Entries:\n", shstSize);
570 for(int j=0; j<i; j++)
571         printf("\"%s\"\n", shstrtab + shstTab[j]);
572 #endif
573
574                 // Construct ELF header
575                 // If you want to make any sense out of this you'd better take a look
576                 // at Executable and Linkable Format on Wikipedia.
577                 chptr = buf;
578                 D_long(0x7F454C46); // 00 - "<7F>ELF" Magic Number
579                 D_byte(0x01); // 04 - 32 vs 64 (1 = 32, 2 = 64)
580                 D_byte(0x02); // 05 - Endianness (1 = LE, 2 = BE)
581                 D_byte(0x01); // 06 - Original version of ELF (set to 1)
582                 D_byte(0x00); // 07 - Target OS ABI (0 = System V)
583                 D_byte(0x00); // 08 - ABI Extra (unneeded)
584                 D_byte(0x00); // 09 - Pad bytes
585                 D_word(0x00);
586                 D_long(0x00);
587                 D_word(0x01); // 10 - ELF Type (1 = relocatable)
588                 D_word(0x04); // 12 - Architecture (EM_68K = 4, Motorola M68K family)
589                 D_long(0x01); // 14 - Version (1 = original ELF)
590                 D_long(0x00); // 18 - Entry point virtual address (unneeded)
591                 D_long(0x00); // 1C - Program header table offset (unneeded)
592                 D_long(0x00); // 20 - Section header table offset (to be determined)
593
594                 if (0)
595                 {
596                         // Specifically for 68000 CPU
597                         D_long(0x01000000) // 24 - Processor-specific flags - EF_M68K_M68000
598                 }
599                 else
600                 {
601                         // CPUs other than 68000 (68020...)
602                         D_long(0); // 24 - Processor-specific flags (ISA dependent)
603                 }
604
605                 D_word(0x0034); // 28 - ELF header size in bytes
606                 D_word(0); // 2A - Program header table entry size
607                 D_word(0); // 2C - Program header table entry count
608                 D_word(0x0028); // 2E - Section header entry size - 40 bytes for ELF32
609                 D_word(numEntries); // 30 - Section header table entry count
610                 D_word(shstIndex); // 32 - Section header string table index
611
612                 elfSize += 0x34;
613
614                 // Deposit section header 0 (NULL)
615                 headerSize += DepositELFSectionHeader(headers + headerSize, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
616
617                 int textLoc = elfSize;
618
619                 // Construct TEXT section, if any
620                 if (sect[TEXT].sloc > 0)
621                 {
622                         headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_TEXT], 1, 6, 0, elfSize, sect[TEXT].sloc, 0, 0, 2, 0);
623
624                         for(CHUNK * cp=sect[TEXT].sfcode; cp!=NULL; cp=cp->chnext)
625                         {
626                                 memcpy(buf + elfSize, cp->chptr, cp->ch_size);
627                                 elfSize += cp->ch_size;
628                         }
629
630                         // Pad for next section (LONG boundary)
631                         elfSize = (elfSize + 3) & ~3;
632                 }
633
634                 int dataLoc = elfSize;
635
636                 // Construct DATA section, if any
637                 if (sect[DATA].sloc > 0)
638                 {
639                         headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_DATA], 1, 3, 0, elfSize, sect[DATA].sloc, 0, 0, 1, 0);
640
641                         for(CHUNK * cp=sect[DATA].sfcode; cp!=NULL; cp=cp->chnext)
642                         {
643                                 memcpy(buf + elfSize, cp->chptr, cp->ch_size);
644                                 elfSize += cp->ch_size;
645                         }
646
647                         // Pad for next section (LONG boundary)
648                         elfSize = (elfSize + 3) & ~3;
649                 }
650
651                 // Construct BSS section, if any
652                 if (sect[BSS].sloc > 0)
653                 {
654                         headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_BSS], 8, 3, 0, elfSize, sect[BSS].sloc, 0, 0, 2, 0);
655                 }
656
657                 int textrelLoc = headerSize;
658
659                 // Add headers for relocated sections, if any...
660                 if (sect[TEXT].relocs > 0)
661                         headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_RELATEXT], 4, 0x00, 0, 0, 0, elfHdrNum[ES_SYMTAB], elfHdrNum[ES_TEXT], 4, 0x0C);
662
663                 int datarelLoc = headerSize;
664
665                 if (sect[DATA].relocs > 0)
666                         headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_RELADATA], 4, 0x40, 0, 0, 0, elfHdrNum[ES_SYMTAB], elfHdrNum[ES_DATA], 4, 0x0C);
667
668                 // Add shstrtab
669                 headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_SHSTRTAB], 3, 0, 0, elfSize, shstSize, 0, 0, 1, 0);
670                 memcpy(buf + elfSize, shstrtab, shstSize);
671                 elfSize += shstSize;
672                 // Pad for next section (LONG boundary)
673                 elfSize = (elfSize + 3) & ~3;
674
675                 // Add section headers
676                 int headerLoc = elfSize;
677                 chptr = buf + 0x20;             // Set section header offset in ELF header
678                 D_long(headerLoc);
679                 elfSize += (4 * 10) * numEntries;
680
681                 // Add symbol table & string table
682                 int symtabLoc = elfSize;
683                 strindx = 0;    // Make sure we start at the beginning...
684                 elfSize += DepositELFSymbol(buf + elfSize, 0, 0, 0, 0, 0, 0);
685                 *strtable = 0;
686                 strindx++;
687                 extraSyms = 1;
688
689                 if (sect[TEXT].sloc > 0)
690                 {
691                         elfSize += DepositELFSymbol(buf + elfSize, 0, 0, 0, 3, 0, elfHdrNum[ES_TEXT]);
692                         extraSyms++;
693                 }
694
695                 if (sect[DATA].sloc > 0)
696                 {
697                         elfSize += DepositELFSymbol(buf + elfSize, 0, 0, 0, 3, 0, elfHdrNum[ES_DATA]);
698                         extraSyms++;
699                 }
700
701                 if (sect[BSS].sloc > 0)
702                 {
703                         elfSize += DepositELFSymbol(buf + elfSize, 0, 0, 0, 3, 0, elfHdrNum[ES_BSS]);
704                         extraSyms++;
705                 }
706
707                 int numSymbols = sy_assign_ELF(buf + elfSize, AddELFSymEntry);
708                 elfSize += numSymbols * 0x10;
709
710                 // String table
711                 int strtabLoc = elfSize;
712                 memcpy(buf + elfSize, strtable, strindx);
713                 elfSize += strindx;
714                 // Pad for next section (LONG boundary)
715                 elfSize = (elfSize + 3) & ~3;
716
717                 headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_SYMTAB], 2, 0, 0, symtabLoc, (numSymbols + extraSyms) * 0x10, shstIndex + 2, firstglobal + extraSyms, 4, 0x10);
718                 headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_STRTAB], 3, 0, 0, strtabLoc, strindx, 0, 0, 1, 0);
719
720                 // Add relocation tables, if any (no need to align after these, they're
721                 // already on DWORD boundaries)
722                 if (sect[TEXT].relocs > 0)
723                 {
724                         uint32_t textrelSize = CreateELFRelocationRecord(buf + elfSize, buf + textLoc, TEXT);
725                         // Deposit offset & size, now that we know them
726                         chptr = headers + textrelLoc + 0x10;
727                         D_long(elfSize);
728                         D_long(textrelSize);
729                         elfSize += textrelSize;
730                 }
731
732                 if (sect[DATA].relocs > 0)
733                 {
734                         uint32_t datarelSize = CreateELFRelocationRecord(buf + elfSize, buf + dataLoc, DATA);
735                         // Deposit offset & size, now that we know them
736                         chptr = headers + datarelLoc + 0x10;
737                         D_long(elfSize);
738                         D_long(datarelSize);
739                         elfSize += datarelSize;
740                 }
741
742                 // Copy headers into the object
743                 memcpy(buf + headerLoc, headers, headerSize);
744
745                 // Finally, write out the object
746                 unused = write(fd, buf, elfSize);
747
748                 // Free allocated memory
749                 if (buf)
750                 {
751                         free(buf);
752                         free(strtable);
753                 }
754         }
755         else if (obj_format == XEX)
756         {
757                 // Just write the object file
758                 m6502obj(fd);
759         }
760
761         return 0;
762 }
763