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
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 };
27 static uint16_t tdb_tab[] = {
29 AL_TEXT, // TEXT segment based
30 AL_DATA, 0, // DATA segment based
31 AL_BSS // BSS segment based
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
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
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
65 uint8_t * AddSymEntry(register uint8_t * buf, SYM * sym, int globflag)
67 // Copy symbol name to buffer (first 8 chars or less)
68 register uint8_t * s = sym->sname;
72 for(i=0; i<8 && *s; i++)
78 register uint16_t w1 = sym->sattr;
79 register uint16_t w = AL_DEFINED | tdb_tab[w1 & TDB];
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
88 //printf("%s '%i' - will write extended symbol\n", sym->sname,s[0]);
89 uint8_t *buf2 = buf + 6;
91 for(i=8; i<8+14 && *s; i++)
105 // Construct and deposit flag word
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
114 if (w1 & EQUATED) // Equated
119 w |= AL_EXTERN | AL_GLOBAL; // Common symbol
120 w &= ~AL_BSS; // They're not BSS in Alcyon object files
122 else if (w1 & DEFINED)
124 if (globflag) // Export the symbol
128 w |= AL_EXTERN; // Imported symbol
132 register uint32_t z = (uint32_t)sym->svalue;
134 if (prg_flag) // Relocate value in .PRG segment
139 z += sect[TEXT].sloc;
142 z += sect[DATA].sloc;
145 SETBE32(buf, 0, z); // Deposit symbol value
156 // Add an entry to the BSD symbol table
158 uint8_t * AddBSDSymEntry(uint8_t * buf, SYM * sym, int globflag)
160 chptr = buf; // Point to buffer for depositing longs
161 D_long(strindx); // Deposit the symbol string index
163 uint16_t w1 = sym->sattr; // Obtain symbol attributes
164 uint32_t z = 0; // Initialize resulting symbol flags
168 z = 0x02000000; // Set equated flag
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
181 z |= 0x01000000; // Set global flag if requested
183 D_long(z); // Deposit symbol attribute
184 z = sym->svalue; // Obtain symbol value
186 if (w1 & (DATA | BSS))
187 z += sect[TEXT].sloc; // If DATA or BSS add TEXT segment size
190 z += sect[DATA].sloc; // If BSS add DATA segment size
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
203 // Add entry to ELF symbol table; if `globflag' is 1, make the symbol global
205 uint8_t * AddELFSymEntry(uint8_t * buf, SYM * sym, int globflag)
209 D_long(strindx); // st_name
210 D_long(sym->svalue); // st_value
211 D_long(0); // st_size
214 register WORD w1 = sym->sattr;
218 //w |= AL_EXTERN | AL_GLOBAL; // common symbol
219 //w &= ~AL_BSS; // they're not BSS in Alcyon object files
221 else if (w1 & DEFINED)
223 if (globflag) // Export the symbol
224 st_info |= 16; //STB_GLOBAL (1<<4)
226 else if (w1 & (GLOBAL | REFERENCED))
230 D_byte(0); // st_other
232 uint16_t st_shndx = 0xFFF1; // Assume absolute (equated) number
235 st_shndx = elfHdrNum[ES_TEXT];
237 st_shndx = elfHdrNum[ES_DATA];
239 st_shndx = elfHdrNum[ES_BSS];
241 st_shndx = 0; // Global, not absolute
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
254 // Helper function for ELF output
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)
275 // Deposit an entry in the Section Header string table
277 uint32_t DepositELFSHSTEntry(uint8_t ** pTable, const uint8_t * s)
280 printf("DepositELFSHSTEntry: s = \"%s\"\n", s);
282 uint32_t strSize = strlen(s);
284 *pTable += strSize + 1;
290 // Deposit a symbol table entry in the ELF Symbol Table
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)
307 // Write an object file to the passed in file descriptor
308 // N.B.: Return value is ignored...
310 int WriteObject(int fd)
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
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);
328 // Write requested object file...
329 if ((obj_format == BSD) || ((obj_format == ALCYON) && (prg_flag == 0)))
331 // Force BSD format (if it was ALCYON format)
336 printf("Total : %d bytes\n", sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc);
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
345 error("cannot allocate object file memory (in BSD mode)");
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
353 if (strtable == NULL)
355 error("cannot allocate string table memory (in BSD mode)");
359 memset(strtable, 0, 0x200000); // Clear allocated memory
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
372 // Construct TEXT and DATA segments (without relocation changes)
373 p = buf + BSDHDRSIZE;
375 for(i=TEXT; i<=DATA; i++)
377 for(cp=sect[i].sfcode; cp!=NULL; cp=cp->chnext)
379 memcpy(p, cp->chptr, cp->ch_size);
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
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
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
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
408 // Write the BSD object file from the object image buffer
409 unused = write(fd, buf, BSDHDRSIZE + tds + trsize + drsize + symsize + strindx + 4);
413 printf("TextRel size: %d bytes\n", trsize);
414 printf("DataRel size: %d bytes\n", drsize);
419 free(strtable); // Free allocated memory
420 free(buf); // Free allocated memory
423 else if (obj_format == ALCYON)
425 uint32_t symbolmaxsize = 0;
431 printf("TOS header : 28 bytes\n");
432 printf("Total : %d bytes\n", 28 + sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc);
436 printf("Total : %d bytes\n", sect[TEXT].sloc + sect[DATA].sloc + sect[BSS].sloc);
441 symbolmaxsize = sy_assign(NULL, NULL) * 28; // Assign index numbers to the symbols
443 // Alloc memory for header + text + data, symbol and relocation
444 // information construction.
445 t = tds = sect[TEXT].sloc + sect[DATA].sloc;
447 if (t < symbolmaxsize)
450 // Is there any reason to do this this way???
451 buf = malloc(t + HDRSIZE);
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
465 // Construct text and data segments; fixup relocatable longs in .PRG
466 // mode; finally write the header + text + data
469 for(i=TEXT; i<=DATA; i++)
471 for(cp=sect[i].sfcode; cp!=NULL; cp=cp->chnext)
473 memcpy(p, cp->chptr, cp->ch_size);
478 // Do a first pass on the Alcyon image, if in PRG mode
480 MarkImage(buf, tds, sect[TEXT].sloc, 0);
482 unused = write(fd, buf - HDRSIZE, tds + HDRSIZE);
484 // Construct and write symbol table
487 sy_assign(buf, AddSymEntry);
488 unused = write(fd, buf, symsize);
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);
496 // If we generated a symbol table we need to update the placeholder value
497 // we wrote above in the header
499 symsize = BYTESWAP32(symsize);
500 unused = write(fd, &symsize, 4);
503 else if (obj_format == ELF)
505 // Allocate 6MB object file image memory
506 buf = malloc(0x600000);
510 error("cannot allocate object file memory (in ELF mode)");
514 memset(buf, 0, 0x600000);
515 objImage = buf; // Set global object image pointer
516 strtable = malloc(0x200000); // Allocate 2MB string table buffer
518 if (strtable == NULL)
520 error("cannot allocate string table memory (in ELF mode)");
524 memset(strtable, 0, 0x200000);
526 // This is pretty much a first pass at this shite, so there's room for
528 uint8_t headers[4 * 10 * 10]; // (DWORD * 10) = 1 hdr, 10 entries
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));
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.
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");
553 if (sect[TEXT].sloc > 0)
555 elfHdrNum[ES_TEXT] = shstIndex;
556 shstTab[ES_TEXT] = shstSize;
557 shstSize += DepositELFSHSTEntry(&shstPtr, ".text");
562 if (sect[DATA].sloc > 0)
564 elfHdrNum[ES_DATA] = shstIndex;
565 shstTab[ES_DATA] = shstSize;
566 shstSize += DepositELFSHSTEntry(&shstPtr, ".data");
571 if (sect[BSS].sloc > 0)
573 elfHdrNum[ES_BSS] = shstIndex;
574 shstTab[ES_BSS] = shstSize;
575 shstSize += DepositELFSHSTEntry(&shstPtr, ".bss");
580 if (sect[TEXT].relocs > 0)
582 elfHdrNum[ES_RELATEXT] = shstIndex;
583 shstTab[ES_RELATEXT] = shstSize;
584 shstSize += DepositELFSHSTEntry(&shstPtr, ".relaTEXT");
589 if (sect[DATA].relocs > 0)
591 elfHdrNum[ES_RELADATA] = shstIndex;
592 shstTab[ES_RELADATA] = shstSize;
593 shstSize += DepositELFSHSTEntry(&shstPtr, ".relaDATA");
598 elfHdrNum[ES_SHSTRTAB] = shstIndex + 0;
599 elfHdrNum[ES_SYMTAB] = shstIndex + 1;
600 elfHdrNum[ES_STRTAB] = shstIndex + 2;
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]);
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.
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
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)
630 // Specifically for 68000 CPU
631 D_long(0x01000000) // 24 - Processor-specific flags - EF_M68K_M68000
635 // CPUs other than 68000 (68020...)
636 D_long(0); // 24 - Processor-specific flags (ISA dependent)
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
648 // Deposit section header 0 (NULL)
649 headerSize += DepositELFSectionHeader(headers + headerSize, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
651 int textLoc = elfSize;
653 // Construct TEXT section, if any
654 if (sect[TEXT].sloc > 0)
656 headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_TEXT], 1, 6, 0, elfSize, sect[TEXT].sloc, 0, 0, largestAlign[0], 0);
658 for(CHUNK * cp=sect[TEXT].sfcode; cp!=NULL; cp=cp->chnext)
660 memcpy(buf + elfSize, cp->chptr, cp->ch_size);
661 elfSize += cp->ch_size;
664 // Pad for next section (LONG boundary)
665 elfSize = (elfSize + 3) & ~3;
668 int dataLoc = elfSize;
670 // Construct DATA section, if any
671 if (sect[DATA].sloc > 0)
673 headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_DATA], 1, 3, 0, elfSize, sect[DATA].sloc, 0, 0, largestAlign[1], 0);
675 for(CHUNK * cp=sect[DATA].sfcode; cp!=NULL; cp=cp->chnext)
677 memcpy(buf + elfSize, cp->chptr, cp->ch_size);
678 elfSize += cp->ch_size;
681 // Pad for next section (LONG boundary)
682 elfSize = (elfSize + 3) & ~3;
685 // Construct BSS section, if any
686 if (sect[BSS].sloc > 0)
688 headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_BSS], 8, 3, 0, elfSize, sect[BSS].sloc, 0, 0, largestAlign[2], 0);
691 int textrelLoc = headerSize;
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);
697 int datarelLoc = headerSize;
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);
703 headerSize += DepositELFSectionHeader(headers + headerSize, shstTab[ES_SHSTRTAB], 3, 0, 0, elfSize, shstSize, 0, 0, 1, 0);
704 memcpy(buf + elfSize, shstrtab, shstSize);
706 // Pad for next section (LONG boundary)
707 elfSize = (elfSize + 3) & ~3;
709 // Add section headers
710 int headerLoc = elfSize;
711 chptr = buf + 0x20; // Set section header offset in ELF header
713 elfSize += (4 * 10) * numEntries;
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);
723 if (sect[TEXT].sloc > 0)
725 elfSize += DepositELFSymbol(buf + elfSize, 0, 0, 0, 3, 0, elfHdrNum[ES_TEXT]);
729 if (sect[DATA].sloc > 0)
731 elfSize += DepositELFSymbol(buf + elfSize, 0, 0, 0, 3, 0, elfHdrNum[ES_DATA]);
735 if (sect[BSS].sloc > 0)
737 elfSize += DepositELFSymbol(buf + elfSize, 0, 0, 0, 3, 0, elfHdrNum[ES_BSS]);
741 int numSymbols = sy_assign_ELF(buf + elfSize, AddELFSymEntry);
742 elfSize += numSymbols * 0x10;
745 int strtabLoc = elfSize;
746 memcpy(buf + elfSize, strtable, strindx);
748 // Pad for next section (LONG boundary)
749 elfSize = (elfSize + 3) & ~3;
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);
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)
758 uint32_t textrelSize = CreateELFRelocationRecord(buf + elfSize, buf + textLoc, TEXT);
759 // Deposit offset & size, now that we know them
760 chptr = headers + textrelLoc + 0x10;
763 elfSize += textrelSize;
766 if (sect[DATA].relocs > 0)
768 uint32_t datarelSize = CreateELFRelocationRecord(buf + elfSize, buf + dataLoc, DATA);
769 // Deposit offset & size, now that we know them
770 chptr = headers + datarelLoc + 0x10;
773 elfSize += datarelSize;
776 // Copy headers into the object
777 memcpy(buf + headerLoc, headers, headerSize);
779 // Finally, write out the object
780 unused = write(fd, buf, elfSize);
782 // Free allocated memory
789 else if (obj_format == XEX)
791 // Just write the object file