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