+ // Reached maximum file handles
+ if (hd == NHANDLES)
+ {
+ if (flush_handles()) return 1;
+ }
+
+ // Attempt to open input file
+ if ((fd = tryopen(&fname)) < 0)
+ {
+ printf("Cannot find input module %s\n", fname);
+ return 1;
+ }
+
+ // The file is open; save its info in the handle and name arrays
+ handle[hd] = fd;
+ name[hd] = fname; // This is the name from tryopen()
+ hflag[hd] = flag;
+
+ // Include files
+ if (flag)
+ {
+ temp = strlen(sym); // Get symbol length
+
+ // 100 chars is max length of a symbol
+ if (temp > 99)
+ {
+ sym[99] = '\0';
+ temp = 99;
+ }
+
+ // Malloc enough space for two symbols, then build the second one. Second one may be one
+ // character longer than first
+ if ((hsym1[hd] = malloc((long)temp + 1)) == NULL
+ || (hsym2[hd] = malloc((long)temp + 2)) == NULL)
+ {
+ printf("dofile() : out of memory for include-file symbols\n");
+ return 1;
+ }
+
+ strcpy(hsym1[hd], sym);
+ strcpy(hsym2[hd], sym);
+
+ if (temp == 99)
+ {
+ if (sym[99] == 'x')
+ {
+ printf("Last char of %s is already 'x': choose another name\n", sym);
+ return 1;
+ }
+
+ hsym2[hd][99] = 'x';
+ }
+ else
+ {
+ hsym2[hd][temp] = 'x';
+ hsym2[hd][temp+1] = '\0';
+ }
+ }
+
+ hd++; // Increment next handle index
+ return 0; // No problems
+}
+
+
+//
+// Pad TEXT or DATA Segment to the Requested Boundary
+//
+int segmentpad(FILE * fd, long segsize, int value)
+{
+ long padsize; // Number of pad bytes needed
+ int i; // Good 'ol iterator
+ char padarray[32]; // Array of padding bytes
+ char * padptr; // Pointer to array
+
+ // Determine the number of padding bytes that are needed
+ padsize = (segsize + secalign) & ~secalign;
+ padsize = padsize - segsize;
+
+ // Fill pad array if padding is required
+ if (padsize)
+ {
+ padptr = padarray;
+
+ for(i=0; i<16; i++)
+ {
+ putword(padptr, value);
+ padptr += 2;
+ }
+
+ symoffset += padsize;
+
+ if (fwrite(padarray, padsize, 1, fd) != 1) // Write padding bytes
+ return 1;
+ }
+
+ return 0; // All done
+}
+
+
+//
+// Write the Output File
+//
+int write_ofile(struct OHEADER * header)
+{
+ FILE * fd; // File descriptor
+ unsigned osize; // Object segment size
+ struct OFILE * otemp; // Object file pointer
+ int i, j; // Iterators
+ char himage[0x168]; // Header image (COF = 0xA8)
+ unsigned tsoff, dsoff, bsoff; // Segment offset values
+ unsigned index, type, value; // Symbol table index, type and value
+ short abstype; // ABS symbol type
+ char symbol[14]; // Symbol record for ABS files
+ int slen; // Symbol string length
+
+ symoffset = 0; // Initialise symbol offset
+
+ // Add correct output extension if none
+ if (strchr(ofile, '.') == NULL)
+ {
+ if (aflag && cflag)
+ strcat(ofile, ".cof"); // COF files
+ else if (aflag && !cflag)
+ strcat(ofile, ".abs"); // ABS files
+ else
+ strcat(ofile, ".o"); // Object files (partial linking etc)
+ }
+
+ fd = fopen(ofile, "wb"); // Attempt to open output file
+
+ if (!fd)
+ {
+ printf("Can't open output file %s\n", ofile); // Error opening output file
+ return 1;
+ }
+
+ // Build the output file header
+ // Absolute (COF) header
+ if (cflag)
+ {
+ tsoff = dsoff = bsoff = 0xA8; // Initialises segment offsets
+
+ // Process each object file segment size to obtain a cumulative segment size for both
+ // the TEXT and DATA segments
+ for(i=0; i<(int)obj_index; i++)
+ {
+ dsoff += obj_segsize[i][0]; // Adding TEXT segment sizes
+ bsoff += obj_segsize[i][0] + obj_segsize[i][1]; // Adding TEXT and DATA segment sizes
+ }
+
+ // Currently this only builds a COF absolute file. Conditionals and additional code will
+ // need to be added for ABS and partial linking.
+
+ // Build the COF_HDR
+ putword(himage + 0, 0x0150 ); // Magic Number (0x0150)
+ putword(himage + 2, 0x0003 ); // Sections Number (3)
+ putlong(himage + 4, 0x00000000 ); // Date (0L)
+ putlong(himage + 8, dsoff + header->dsize); // Offset to Symbols Section
+ putlong(himage + 12, ost_index); // Number of Symbols
+ putword(himage + 16, 0x001C ); // Size of RUN_HDR (0x1C)
+ putword(himage + 18, 0x0003 ); // Executable Flags (3)
+
+ // Build the RUN_HDR
+ putlong(himage + 20, 0x00000107 ); // Magic/vstamp
+ putlong(himage + 24, header->tsize ); // TEXT size in bytes
+ putlong(himage + 28, header->dsize ); // DATA size in bytes
+ putlong(himage + 32, header->bsize ); // BSS size in bytes
+ putlong(himage + 36, tbase ); // Start of executable, normally @TEXT
+ putlong(himage + 40, tbase ); // @TEXT
+ putlong(himage + 44, dbase ); // @DATA
+
+ // Build the TEXT SEC_HDR
+ putlong(himage + 48, 0x2E746578 );
+ putlong(himage + 52, 0x74000000 ); // ".text"
+ putlong(himage + 56, tbase ); // TEXT START
+ putlong(himage + 60, tbase ); // TEXT START
+ putlong(himage + 64, header->tsize ); // TEXT size in bytes
+ putlong(himage + 68, tsoff ); // Offset to section data in file
+ putlong(himage + 72, 0x00000000 ); // Offset to section reloc in file (0L)
+ putlong(himage + 76, 0x00000000 ); // Offset to debug lines structures (0L)
+ putlong(himage + 80, 0x00000000 ); // Nreloc/nlnno (0L)
+ putlong(himage + 84, 0x00000020 ); // SEC_FLAGS: STYP_TEXT
+
+ // Build the DATA SEC_HDR
+ putlong(himage + 88, 0x2E646174 );
+ putlong(himage + 92, 0x61000000 ); // ".data"
+ putlong(himage + 96, dbase ); // DATA START
+ putlong(himage + 100, dbase ); // DATA START
+ putlong(himage + 104, header->dsize ); // DATA size in bytes
+ putlong(himage + 108, dsoff ); // Offset to section data in file
+ putlong(himage + 112, 0x00000000 ); // Offset to section reloc in file (0L)
+ putlong(himage + 116, 0x00000000 ); // Offset to debugging lines structures (0L)
+ putlong(himage + 120, 0x00000000 ); // Nreloc/nlnno (0L)
+ putlong(himage + 124, 0x00000040 ); // SEC_FLAGS: STYP_DATA
+
+ // Build the BSS SEC_HDR
+ putlong(himage + 128, 0x2E627373 );
+ putlong(himage + 132, 0x00000000 ); // ".bss"
+ putlong(himage + 136, bbase ); // BSS START
+ putlong(himage + 140, bbase ); // BSS START
+ putlong(himage + 144, header->bsize ); // BSS size in bytes
+ putlong(himage + 148, bsoff ); // Offset to section data in file
+ putlong(himage + 152, 0x00000000 ); // Offset to section reloc in file (0L)
+ putlong(himage + 156, 0x00000000 ); // Offset to debugging lines structures (0L)
+ putlong(himage + 160, 0x00000000 ); // Nreloc/nlnno (0L)
+ putlong(himage + 164, 0x00000080 ); // SEC_FLAGS: STYP_BSS
+
+ symoffset = 168; // Update symbol offset
+ }
+ // Absolute (ABS) header
+ else
+ {
+ // Build the ABS header
+ putword(himage + 0, 0x601B ); // Magic Number (0x601B)
+ putlong(himage + 2, header->tsize ); // TEXT segment size
+ putlong(himage + 6, header->dsize ); // DATA segment size
+ putlong(himage + 10, header->bsize ); // BSS segment size
+ putlong(himage + 14, ost_index * 14 ); // Symbol table size (?)
+ putlong(himage + 18, 0x00000000 ); //
+ putlong(himage + 22, tbase ); // TEXT base address
+ putword(himage + 26, 0xFFFF ); // Flags (?)
+ putlong(himage + 28, dbase ); // DATA base address
+ putlong(himage + 32, bbase ); // BSS base address
+
+ symoffset = 36; // Update symbol offset
+ }
+
+ // Write the header, but not if noheaderflag
+ // Absolute (ABS) header
+ if (!cflag)
+ {
+ if (!noheaderflag)
+ if (fwrite(himage, 36, 1, fd) != 1)
+ goto werror;
+ }
+ // Absolute (COF) header
+ else
+ {
+ if (fwrite(himage, 168, 1, fd) != 1)
+ goto werror;
+ }
+
+ // Write the TEXT segment of each object file
+ for(otemp=olist; otemp!=NULL; otemp=otemp->o_next)
+ {
+ osize = otemp->o_header.tsize;
+
+ // Write only if segment has size
+ if (osize)
+ {
+ if (vflag > 1)
+ printf("Writing TEXT Segment of %s\n", otemp->o_name);
+
+ if (fwrite(otemp->o_image + 32, osize, 1, fd) != 1)
+ goto werror;
+
+ // Pad to required alignment boundary
+ if (segmentpad(fd, osize, 0x0000))
+ goto werror;
+
+ symoffset += osize;
+ }
+ }
+
+ // Write the DATA segment of each object file
+ for(otemp = olist; otemp != NULL; otemp = otemp->o_next)
+ {
+ osize = otemp->o_header.dsize;
+
+ // Write only if the segment has size
+ if (osize)
+ {
+ if (vflag > 1)
+ printf("Writing DATA Segment of %s\n", otemp->o_name);
+
+ if (fwrite((otemp->o_image + 32 + otemp->o_header.tsize), osize, 1, fd) != 1)
+ goto werror;
+
+ // Pad to required alignment boundary
+ if (segmentpad(fd, osize, 0))
+ goto werror;
+
+ symoffset += osize;
+ }
+ }
+
+ if (!noheaderflag)
+ {
+ // Write the symbols table and string table
+ // Absolute (COF) symbol/string table
+ if (cflag)
+ {
+ if (header->ssize)
+ {
+ if (fwrite(ost, (ost_ptr - ost), 1, fd) != 1) goto werror;
+ if (fwrite(oststr, (oststr_ptr - oststr), 1, fd) != 1) goto werror;
+ }
+ }
+ // Absolute (ABS) symbol/string table
+ else
+ {
+ // The symbol and string table have been created as part of the dosym() function and the
+ // output symbol and string tables are in COF format. For an ABS file we need to process
+ // through this to create the 14 character long combined symbol and string table.
+ // Format of symbol table in ABS: AAAAAAAATTVVVV, where (A)=STRING, (T)=TYPE & (V)=VALUE
+
+ for(i=0; i<ost_index; i++)
+ {
+ memset(symbol, 0, 14); // Initialise symbol record
+ abstype = 0; // Initialise ABS symbol type
+ slen = 0; // Initialise symbol string length
+ index = getlong(ost + (i * 12)); // Get symbol index
+ type = getlong((ost + (i * 12)) + 4); // Get symbol type
+
+ if (type & 0xF0000000)
+ continue; // Not doing debug symbols
+
+ value = getlong((ost + (i * 12)) + 8); // Get symbol value
+ slen = strlen(oststr + index);
+
+ // Get symbol string (maximum 8 chars)
+ if (slen > 8)
+ {
+ for(j=0; j<8; j++)
+ *(symbol + j) = *(oststr + index + j);
+ }
+ else
+ {
+ for(j=0; j<slen; j++)
+ *(symbol + j) = *(oststr + index + j);
+ }
+
+ // Modify to ABS symbol type
+ switch (type)
+ {
+ case 0x02000000: abstype = (short)ABST_DEFINED; break;
+ case 0x04000000: abstype = (short)ABST_DEFINED | ABST_TEXT; break;
+ case 0x05000000: abstype = (short)ABST_DEFINED | ABST_GLOBAL | ABST_TEXT; break;
+ case 0x06000000: abstype = (short)ABST_DEFINED | ABST_DATA; break;
+ case 0x07000000: abstype = (short)ABST_DEFINED | ABST_GLOBAL | ABST_DATA; break;
+ case 0x08000000: abstype = (short)ABST_DEFINED | ABST_BSS; break;
+ case 0x09000000: abstype = (short)ABST_DEFINED | ABST_GLOBAL | ABST_BSS; break;
+ default:
+ printf("write_ofile: abs, cannot determine symbol type\n");
+ type = 0;
+ break;
+ }
+
+ putword(symbol + 8, abstype); // Write back new ABS type
+ putlong(symbol + 10, value); // Write back value
+
+ if (fwrite(symbol, 14, 1, fd) != 1) goto werror; // Write symbol record
+ }
+ }
+ }
+
+ // Close the file
+ if (fclose(fd))
+ {
+ printf("Close error on output file %s\n",ofile);
+ return 1;
+ }
+ else
+ return 0;
+
+werror: // OMG! Why did Atari use these :)
+ printf("Write error on output file %s\n", ofile);
+ fclose(fd); // Try to close output file anyway
+ return 1;
+}
+
+
+//
+// Display the Symbol Load Map
+//
+int write_map(struct OHEADER * header)
+{
+ unsigned i, o; // Inner and outer loop iterators
+ unsigned c; // Column number
+ unsigned index; // Symbol string index
+ unsigned type; // Symbol type
+ unsigned value; // Symbol value
+ char * symbol; // Symbol string value
+
+ if (ost_index == 0)
+ return 0; // Return if no symbols to map
+
+ printf("LOAD MAP\n\n");
+
+ // Outer loop for each of the symbol areas to map out;
+ // 0 = NON-RELOCATABLE SYMBOLS
+ // 1 = TEXT-SEGMENT RELOCATABLE SYMBOLS
+ // 2 = DATA-SEGMENT RELOCATABLE SYMBOLS
+ // 3 = BSS-SEGMENT RELOCATABLE SYMBOLS
+ for(o=0; o<4; o++)
+ {
+ // Display the correct map header for the symbols being processed
+ switch (o)
+ {
+ case 0: printf("NON-RELOCATABLE SYMBOLS\n\n"); break;
+ case 1: printf("TEXT-SEGMENT RELOCATABLE SYMBOLS\n\n"); break;
+ case 2: printf("DATA-SEGMENT RELOCATABLE SYMBOLS\n\n"); break;
+ case 3: printf("BSS-SEGMENT RELOCATABLE SYMBOLS\n\n"); break;
+ }
+
+ c = 0; // Initialise column number
+
+ // Inner loop to process each record in the symbol table
+ for(i=0; i<(unsigned)ost_index; i++)
+ {
+ index = getlong(ost + (i * 12)); // Get symbol string index
+ type = getlong(ost + (i * 12) + 4); // Get symbol type
+ value = getlong(ost + (i * 12) + 8); // Get symbol value
+ symbol = oststr + index; // Get symbol string
+
+ // Display only three columns
+ if (c == 3)
+ {
+ printf("\n");
+ c = 0;
+ }
+
+ // If local symbols not included and the type is local then go to next symbol record
+ if (!lflag & !(type & 0x01000000))
+ continue;
+
+ // Output each symbol to the display, dependant on type
+ switch (o)
+ {
+ case 0: // Non-relocatable symbols
+ if (type == 0x02000000 || type == 0x03000000)
+ {
+ printf("%-8s %c %08X ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
+ c++;
+ }
+
+ break;
+ case 1: // TEXT segment relocatable symbols
+ if (type == 0x04000000 || type == 0x05000000)
+ {
+ printf("%-8s %c %08X ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
+ c++;
+ }
+
+ break;
+ case 2: // DATA segment relocatble symbols
+ if (type == 0x06000000 || type == 0x07000000)
+ {
+ printf("%-8s %c %08X ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
+ c++;
+ }
+
+ break;
+ case 3: // BSS segment relocatable symbols
+ if (type == 0x08000000 || type == 0x09000000)
+ {
+ printf("%-8s %c %08X ", symbol, (type & 0x01000000) ? 'G' : 'L', value);
+ c++;
+ }
+
+ break;
+ }
+ }