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