]> Shamusworld >> Repos - rmac/blobdiff - object.c
Fix a small buglet in the last patch. :-)
[rmac] / object.c
index a1847967f879e48648c01787a9ca06298e7af1c8..0b7df7ed8ecc77b1d7bb2eb1ad9ad26b6319821b 100644 (file)
--- a/object.c
+++ b/object.c
@@ -1,7 +1,7 @@
 //
 // RMAC - Reboot's Macro Assembler for all Atari computers
 // OBJECT.C - Writing Object Files
-// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011-2020 Reboot and Friends
 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
 // Source utilised with the kind permission of Landon Dyer
 //
@@ -9,11 +9,13 @@
 #include "object.h"
 #include "6502.h"
 #include "direct.h"
+#include "dsp56k.h"
 #include "error.h"
 #include "mark.h"
 #include "riscasm.h"
 #include "sect.h"
 #include "symbol.h"
+#include "version.h"
 
 //#define DEBUG_ELF
 
@@ -56,6 +58,10 @@ See left.            4 & 5   If these bits are set to 0 (PF_PRIVATE), the processes'
 -                              6-15    Currently unused
 */
 
+// Internal function prototypes
+static void WriteLOD(void);
+static void WriteP56(void);
+
 
 //
 // Add entry to symbol table (in ALCYON mode)
@@ -118,7 +124,8 @@ uint8_t * AddSymEntry(register uint8_t * buf, SYM * sym, int globflag)
                w |= AL_EXTERN | AL_GLOBAL;     // Common symbol
                w &= ~AL_BSS;           // They're not BSS in Alcyon object files
        }
-       else if (w1 & DEFINED)
+
+       if (w1 & DEFINED)
        {
                if (globflag)           // Export the symbol
                        w |= AL_GLOBAL;
@@ -166,14 +173,16 @@ uint8_t * AddBSDSymEntry(uint8_t * buf, SYM * sym, int globflag)
        {
                z = 0x02000000;                                 // Set equated flag
        }
-       else
+
+       // If a symbol is both EQUd and flagged as TBD then we let
+       // the later take precedence. Otherwise the linker will not even
+       // bother trying to relocate the address during link time
+
+       switch (w1 & TDB)
        {
-               switch (w1 & TDB)
-               {
-               case TEXT: z = 0x04000000; break;       // Set TEXT segment flag
-               case DATA: z = 0x06000000; break;       // Set DATA segment flag
-               case BSS : z = 0x08000000; break;       // Set BSS segment flag
-               }
+       case TEXT: z = 0x04000000; break;       // Set TEXT segment flag
+       case DATA: z = 0x06000000; break;       // Set DATA segment flag
+       case BSS : z = 0x08000000; break;       // Set BSS segment flag
        }
 
        if (globflag)
@@ -212,12 +221,7 @@ uint8_t * AddELFSymEntry(uint8_t * buf, SYM * sym, int globflag)
 
        register WORD w1 = sym->sattr;
 
-       if (w1 & COMMON)
-       {
-               //w |= AL_EXTERN | AL_GLOBAL;   // common symbol
-               //w &= ~AL_BSS;         // they're not BSS in Alcyon object files
-       }
-       else if (w1 & DEFINED)
+       if (w1 & DEFINED)
        {
                if (globflag)           // Export the symbol
                        st_info |= 16;   //STB_GLOBAL (1<<4)
@@ -308,14 +312,13 @@ uint32_t DepositELFSymbol(uint8_t * ptr, uint32_t name, uint32_t addr, uint32_t
 //
 int WriteObject(int fd)
 {
-       LONG t;                                 // Scratch long
        LONG tds;                               // TEXT & DATA segment size
        int i;                                  // Temporary int
        CHUNK * cp;                             // Chunk (for gather)
        uint8_t * buf;                  // Scratch area
        uint8_t * p;                    // Temporary ptr
        LONG trsize, drsize;    // Size of relocations
-       long unused;                    // For supressing 'write' warnings
+       uint32_t unused;                // For supressing 'write' warnings
 
        if (verb_flag)
        {
@@ -326,7 +329,9 @@ int WriteObject(int fd)
 
        // Write requested object file...
        if ((obj_format == BSD) || ((obj_format == ALCYON) && (prg_flag == 0)))
-    {
+       {
+               ch_size = 0;
+
                // Force BSD format (if it was ALCYON format)
                obj_format = BSD;
 
@@ -351,6 +356,7 @@ int WriteObject(int fd)
 
                if (strtable == NULL)
                {
+                       free(buf);
                        error("cannot allocate string table memory (in BSD mode)");
                        return ERROR;
                }
@@ -359,6 +365,8 @@ int WriteObject(int fd)
 
                // Build object file header
                chptr = buf;                                    // Base of header (for D_foo macros)
+               ch_size = 0;
+               challoc = 0x800000;
                D_long(0x00000107);                             // Magic number
                D_long(sect[TEXT].sloc);                // TEXT size
                D_long(sect[DATA].sloc);                // DATA size
@@ -421,6 +429,8 @@ int WriteObject(int fd)
        }
        else if (obj_format == ALCYON)
        {
+               ch_size = 0;
+
                if (verb_flag)
                {
                        if (prg_flag)
@@ -431,6 +441,7 @@ int WriteObject(int fd)
 
                // Assign index numbers to the symbols, get # of symbols (we assume
                // that all symbols can potentially be extended, hence the x28)
+               // (To clarify: 28 bytes is the size of an extended symbol)
                uint32_t symbolMaxSize = sy_assign(NULL, NULL) * 28;
 
                // Alloc memory for header + text + data, symbol and relocation
@@ -440,6 +451,8 @@ int WriteObject(int fd)
 
                // Build object file header just before the text+data image
                chptr = buf;                            // -> base of header
+               ch_size = 0;
+               challoc = HDRSIZE + tds + symbolMaxSize;
                D_word(0x601A);                         // 00 - magic number
                D_long(sect[TEXT].sloc);        // 02 - TEXT size
                D_long(sect[DATA].sloc);        // 06 - DATA size
@@ -473,6 +486,9 @@ int WriteObject(int fd)
                        sy_assign(buf + HDRSIZE + tds, AddSymEntry);
                        chptr = buf + 0x0E;                     // Point to symbol table size entry
                        D_long(symsize);
+
+                       if (verb_flag)
+                               printf("Symbol table: %d bytes\n", symsize);
                }
 
                // Write out the header + text & data + symbol table (if any)
@@ -592,6 +608,8 @@ for(int j=0; j<i; j++)
                // If you want to make any sense out of this you'd better take a look
                // at Executable and Linkable Format on Wikipedia.
                chptr = buf;
+               ch_size = 0;
+               challoc = 0x600000;
                D_long(0x7F454C46); // 00 - "<7F>ELF" Magic Number
                D_byte(0x01); // 04 - 32 vs 64 (1 = 32, 2 = 64)
                D_byte(0x02); // 05 - Endianness (1 = LE, 2 = BE)
@@ -774,7 +792,213 @@ for(int j=0; j<i; j++)
                // Just write the object file
                m6502obj(fd);
        }
+       else if (obj_format == P56 || obj_format == LOD)
+       {
+               // Allocate 6MB object file image memory
+               uint8_t * buf = malloc(0x600000);
+
+               if (buf == NULL)
+                       return error("cannot allocate object file memory (in P56/LOD mode)");
+
+//             objImage = buf;                                 // Set global object image pointer
+
+               memset(buf, 0, 0x600000);               // Clear allocated memory
+
+               // Iterate through DSP ram buffers
+               chptr = buf;                                    // -> base of header
+               ch_size = 0;
+               challoc = 0x600000;
+
+               if (obj_format == LOD)
+                       WriteLOD();
+               else
+                       WriteP56();
+
+               // Write all the things \o/
+               unused = write(fd, buf, chptr - buf);
+
+               if (buf)
+                       free(buf);
+       }
+       else if (obj_format == RAW)
+       {
+               if (!org68k_active)
+               {
+                       return error("cannot output absolute binary without a starting address (.org or command line)");
+               }
+
+               // Alloc memory for text + data construction.
+               tds = sect[TEXT].sloc + sect[DATA].sloc;
+               buf = malloc(tds);
+               chptr = buf;
+
+               // Construct text and data segments; fixup relocatable longs;
+               // finally write the text + data
+
+               p = buf;
+               objImage = buf;                                 // Set global object image pointer
 
+               for (i = TEXT; i <= DATA; i++)
+               {
+                       for (cp = sect[i].sfcode; cp != NULL; cp = cp->chnext)
+                       {
+                               memcpy(p, cp->chptr, cp->ch_size);
+                               p += cp->ch_size;
+                       }
+               }
+
+               if (MarkABSImage(buf, tds, sect[TEXT].sloc, TEXT) != OK)  // Do TEXT relocation table
+               {
+                       return ERROR;
+               }
+               if (MarkABSImage(buf, tds, sect[TEXT].sloc, DATA) != OK) // Do DATA relocation table
+               {
+                       return ERROR;
+               }
+
+               // Write out the header + text & data + symbol table (if any)
+               unused = write(fd, buf, tds);
+
+       }
        return 0;
 }
 
+
+static void WriteLOD(void)
+{
+       D_printf("_START %s 0000 0000 0000 RMAC %01i.%01i.%01i\n\n", firstfname, MAJOR, MINOR, PATCH);
+
+       for(DSP_ORG * l=&dsp_orgmap[0]; l<dsp_currentorg; l++)
+       {
+               if (l->end != l->start)
+               {
+                       switch (l->memtype)
+                       {
+                       case ORG_P: D_printf("_DATA P %.4X\n", l->orgadr); break;
+                       case ORG_X: D_printf("_DATA X %.4X\n", l->orgadr); break;
+                       case ORG_Y: D_printf("_DATA Y %.4X\n", l->orgadr); break;
+                       case ORG_L: D_printf("_DATA L %.4X\n", l->orgadr); break;
+                       default:
+                               error("Internal error: unknown DSP56001 org'd section");
+                               return;
+                       }
+
+                       CHUNK * cp = l->chunk;
+                       uint8_t * p_chunk = l->start;
+                       uint8_t * p_chunk_end = p_chunk;
+                       uint32_t j = 0;
+
+                       while (p_chunk_end != l->end)
+                       {
+                               if (l->end < (cp->chptr + cp->ch_size) && l->end > cp->chptr)
+                               {
+                                       // If the end of the section is inside the current chunk, just dump everything and stop
+                                       p_chunk_end = l->end;
+                               }
+                               else
+                               {
+                                       // If the end of the section is not inside the current chunk, just dump everything from the current chunk and move on to the next
+                                       p_chunk_end = cp->chptr + cp->ch_size;
+                               }
+
+                               uint32_t count = (uint32_t)(p_chunk_end - p_chunk);
+
+                               for(uint32_t i=0; i<count; i+=3)
+                               {
+                                       if ((j & 7) != 7)
+                                       {
+                                               D_printf("%.6X ", (((p_chunk[0] << 8) | p_chunk[1]) << 8) | p_chunk[2]);
+                                       }
+                                       else
+                                       {
+                                               D_printf("%.6X\n", (((p_chunk[0] << 8) | p_chunk[1]) << 8) | p_chunk[2]);
+                                       }
+
+                                       p_chunk += 3;
+                                       j++;
+                               }
+
+                               cp = cp->chnext;        // Advance chunk
+
+                               if (cp != NULL)
+                                       p_chunk = cp->chptr;    // Set dump pointer to start of this chunk
+                       }
+
+                       if ((j & 7) != 0)
+                               D_printf("\n");
+               }
+       }
+
+       // Dump the symbol table into the buf
+       DumpLODSymbols();
+
+       D_printf("\n_END %.4X\n", dsp_orgmap[0].orgadr);
+}
+
+
+static void WriteP56(void)
+{
+       for(DSP_ORG * l=&dsp_orgmap[0]; l<dsp_currentorg; l++)
+       {
+               if (l->end == l->start)
+                       continue;
+
+               if ((l->memtype < ORG_P) || (l->memtype > ORG_L))
+               {
+                       error("Internal error: unknown DSP56001 org'd section");
+                       return;
+               }
+
+               CHUNK * cp = l->chunk;
+               uint8_t * p_chunk = l->start;
+               uint8_t * p_chunk_end = p_chunk;
+
+               // Memory type (P, X, Y or L)
+               D_dsp(l->memtype);
+
+               // Chunk start address (in DSP words)
+               D_dsp(l->orgadr);
+
+               // Chunk length (in DSP words)
+               // We'll fill this field after we write the chunk so we can calculate
+               // how long it is (so if the chunk is split into different CHUNKs we
+               // can deal with this during copy)
+               uint8_t * p_buf_len = chptr;
+               chptr += 3;
+
+               // The chunk itself
+               uint32_t chunk_size = 0;
+
+               while (p_chunk_end != l->end)
+               {
+                       if (l->end < (cp->chptr + cp->ch_size) && l->end > cp->chptr)
+                       {
+                               // If the end of the section is inside the current chunk, just
+                               // dump everything and stop
+                               p_chunk_end = l->end;
+                       }
+                       else
+                       {
+                               // If the end of the section is not inside the current chunk,
+                               // just dump everything from the current chunk and move on to
+                               // the next
+                               p_chunk_end = cp->chptr + cp->ch_size;
+                       }
+
+                       uint32_t current_chunk_size = p_chunk_end - p_chunk;
+                       chunk_size += current_chunk_size;
+                       memcpy(chptr, p_chunk, current_chunk_size);
+                       chptr += current_chunk_size;
+
+                       cp = cp->chnext;        // Advance chunk
+
+                       if (cp != NULL)
+                               p_chunk = cp->chptr;    // Set dump pointer to start of this chunk
+               }
+
+               // Now we can mark the chunk's length (DSP word size is 24-bits, so
+               // the byte count needs to be divided by 3)
+               SETBE24(p_buf_len, chunk_size / 3);
+       }
+}
+