]> git.sur5r.net Git - cc65/blobdiff - src/ar65/objfile.c
Fix for multiple overlay segments.
[cc65] / src / ar65 / objfile.c
index 93fcfbf429a39ee86c4a4b00b5273d698a12dc37..0434f7e59fcc388a95d716cd7471bff798bfa821 100644 (file)
@@ -1,52 +1,51 @@
 /*****************************************************************************/
-/*                                                                          */
-/*                                objfile.c                                 */
-/*                                                                          */
-/*               Object file handling for the ar65 archiver                 */
-/*                                                                          */
-/*                                                                          */
-/*                                                                          */
-/* (C) 1998    Ullrich von Bassewitz                                        */
-/*             Wacholderweg 14                                              */
-/*             D-70597 Stuttgart                                            */
-/* EMail:      uz@musoftware.de                                             */
-/*                                                                          */
-/*                                                                          */
-/* This software is provided 'as-is', without any expressed or implied      */
+/*                                                                           */
+/*                                 objfile.c                                 */
+/*                                                                           */
+/*                Object file handling for the ar65 archiver                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2012, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
 /* warranty.  In no event will the authors be held liable for any damages    */
-/* arising from the use of this software.                                   */
-/*                                                                          */
+/* arising from the use of this software.                                    */
+/*                                                                           */
 /* Permission is granted to anyone to use this software for any purpose,     */
 /* including commercial applications, and to alter it and redistribute it    */
-/* freely, subject to the following restrictions:                           */
-/*                                                                          */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
 /* 1. The origin of this software must not be misrepresented; you must not   */
 /*    claim that you wrote the original software. If you use this software   */
 /*    in a product, an acknowledgment in the product documentation would be  */
-/*    appreciated but is not required.                                      */
+/*    appreciated but is not required.                                       */
 /* 2. Altered source versions must be plainly marked as such, and must not   */
-/*    be misrepresented as being the original software.                             */
-/* 3. This notice may not be removed or altered from any source                     */
-/*    distribution.                                                         */
-/*                                                                          */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
 /*****************************************************************************/
 
 
 
 #include <string.h>
 #include <errno.h>
-#if defined(__WATCOMC__) || defined(_MSC_VER)
-/* The Windows compilers have the file in the wrong directory */
-#  include <sys/utime.h>
-#else
-#  include <sys/types.h>               /* FreeBSD needs this */
-#  include <utime.h>
-#endif
-#include <time.h>
-#include <sys/stat.h>
-
-#include "../common/xmalloc.h"
 
+/* common */
+#include "cddefs.h"
+#include "exprdefs.h"
+#include "filestat.h"
+#include "filetime.h"
+#include "fname.h"
+#include "symdefs.h"
+#include "xmalloc.h"
+
+/* ar65 */
 #include "error.h"
 #include "objdata.h"
 #include "fileio.h"
@@ -56,7 +55,7 @@
 
 
 /*****************************************************************************/
-/*                                  Code                                    */
+/*                                   Code                                    */
 /*****************************************************************************/
 
 
@@ -65,68 +64,163 @@ static const char* GetModule (const char* Name)
 /* Get a module name from the file name */
 {
     /* Make a module name from the file name */
-    const char* Module = Name + strlen (Name);
-    while (Module > Name) {
-       --Module;
-       if (*Module == '/' || *Module == '\\') {
-           ++Module;
-           break;
-       }
-    }
+    const char* Module = FindName (Name);
+
+    /* Must not end with a path separator */
     if (*Module == 0) {
-       Error ("Cannot make module name from `%s'", Name);
+        Error ("Cannot make module name from `%s'", Name);
     }
+
+    /* Done */
     return Module;
 }
 
 
 
-void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name)
+static void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name)
 /* Read the header of the object file checking the signature */
 {
-    H->Magic     = Read32 (Obj);
+    H->Magic      = Read32 (Obj);
     if (H->Magic != OBJ_MAGIC) {
-       Error ("`%s' is not an object file", Name);
+        Error ("`%s' is not an object file", Name);
     }
-    H->Version   = Read16 (Obj);
+    H->Version    = Read16 (Obj);
     if (H->Version != OBJ_VERSION) {
-       Error ("Object file `%s' has wrong version", Name);
+        Error ("Object file `%s' has wrong version", Name);
     }
-    H->Flags     = Read16 (Obj);
-    H->OptionOffs = Read32 (Obj);
-    H->OptionSize = Read32 (Obj);
-    H->FileOffs   = Read32 (Obj);
-    H->FileSize   = Read32 (Obj);
-    H->SegOffs   = Read32 (Obj);
-    H->SegSize   = Read32 (Obj);
-    H->ImportOffs = Read32 (Obj);
-    H->ImportSize = Read32 (Obj);
-    H->ExportOffs = Read32 (Obj);
-    H->ExportSize = Read32 (Obj);
-    H->DbgSymOffs = Read32 (Obj);
-    H->DbgSymSize = Read32 (Obj);
+    H->Flags        = Read16 (Obj);
+    H->OptionOffs   = Read32 (Obj);
+    H->OptionSize   = Read32 (Obj);
+    H->FileOffs     = Read32 (Obj);
+    H->FileSize     = Read32 (Obj);
+    H->SegOffs      = Read32 (Obj);
+    H->SegSize      = Read32 (Obj);
+    H->ImportOffs   = Read32 (Obj);
+    H->ImportSize   = Read32 (Obj);
+    H->ExportOffs   = Read32 (Obj);
+    H->ExportSize   = Read32 (Obj);
+    H->DbgSymOffs   = Read32 (Obj);
+    H->DbgSymSize   = Read32 (Obj);
+    H->LineInfoOffs = Read32 (Obj);
+    H->LineInfoSize = Read32 (Obj);
+    H->StrPoolOffs  = Read32 (Obj);
+    H->StrPoolSize  = Read32 (Obj);
+    H->AssertOffs   = Read32 (Obj);
+    H->AssertSize   = Read32 (Obj);
+    H->ScopeOffs    = Read32 (Obj);
+    H->ScopeSize    = Read32 (Obj);
+    H->SpanOffs     = Read32 (Obj);
+    H->SpanSize     = Read32 (Obj);
 }
 
 
 
-void ObjWriteHeader (FILE* Obj, ObjHeader* H)
-/* Write the header of the object file */
+static void SkipExpr (FILE* F)
+/* Skip an expression in F */
 {
-    Write32 (Obj, H->Magic);
-    Write16 (Obj, H->Version);
-    Write16 (Obj, H->Flags);
-    Write32 (Obj, H->OptionOffs);
-    Write32 (Obj, H->OptionSize);
-    Write32 (Obj, H->FileOffs);
-    Write32 (Obj, H->FileSize);
-    Write32 (Obj, H->SegOffs);
-    Write32 (Obj, H->SegSize);
-    Write32 (Obj, H->ImportOffs);
-    Write32 (Obj, H->ImportSize);
-    Write32 (Obj, H->ExportOffs);
-    Write32 (Obj, H->ExportSize);
-    Write32 (Obj, H->DbgSymOffs);
-    Write32 (Obj, H->DbgSymSize);
+    /* Get the operation and skip it */
+    unsigned char Op = Read8 (F);
+
+    /* Handle then different expression nodes */
+    switch (Op) {
+
+        case EXPR_NULL:
+            break;
+
+        case EXPR_LITERAL:
+            /* 32 bit literal value */
+            (void) Read32 (F);
+            break;
+
+        case EXPR_SYMBOL:
+            /* Variable seized symbol index */
+            (void) ReadVar (F);
+            break;
+
+        case EXPR_SECTION:
+            /* 8 bit segment number */
+            (void) Read8 (F);
+            break;
+
+        default:
+            /* What's left are unary and binary nodes */
+            SkipExpr (F);   /* Left */
+            SkipExpr (F);   /* right */
+            break;
+    }
+}
+
+
+
+static void SkipLineInfoList (FILE* F)
+/* Skip a list of line infos in F */
+{
+    /* Number of indices preceeds the list */
+    unsigned long Count = ReadVar (F);
+
+    /* Skip indices */
+    while (Count--) {
+        (void) ReadVar (F);
+    }
+}
+
+
+
+void ObjReadData (FILE* F, ObjData* O)
+/* Read object file data from the given file. The function expects the Name
+** and Start fields to be valid. Header and basic data are read.
+*/
+{
+    unsigned long Count;
+
+    /* Seek to the start of the object file data */
+    fseek (F, O->Start, SEEK_SET);
+
+    /* Read the object file header */
+    ObjReadHeader (F, &O->Header, O->Name);
+
+    /* Read the string pool */
+    fseek (F, O->Start + O->Header.StrPoolOffs, SEEK_SET);
+    Count = ReadVar (F);
+    CollGrow (&O->Strings, Count);
+    while (Count--) {
+        CollAppend (&O->Strings, ReadStr (F));
+    }
+
+    /* Read the exports */
+    fseek (F, O->Start + O->Header.ExportOffs, SEEK_SET);
+    Count = ReadVar (F);
+    CollGrow (&O->Exports, Count);
+    while (Count--) {
+
+        unsigned char ConDes[CD_TYPE_COUNT];
+
+        /* Skip data until we get to the name */
+        unsigned Type = ReadVar (F);
+        (void) Read8 (F);       /* AddrSize */
+        ReadData (F, ConDes, SYM_GET_CONDES_COUNT (Type));
+
+        /* Now this is what we actually need: The name of the export */
+        CollAppend (&O->Exports, CollAt (&O->Strings, ReadVar (F)));
+
+        /* Skip the export value */
+        if (SYM_IS_EXPR (Type)) {
+            /* Expression tree */
+            SkipExpr (F);
+        } else {
+            /* Literal value */
+            (void) Read32 (F);
+        }
+
+        /* Skip the size if necessary */
+        if (SYM_HAS_SIZE (Type)) {
+            (void) ReadVar (F);
+        }
+
+        /* Line info indices */
+        SkipLineInfoList (F);
+        SkipLineInfoList (F);
+    }
 }
 
 
@@ -142,12 +236,19 @@ void ObjAdd (const char* Name)
     /* Open the object file */
     FILE* Obj = fopen (Name, "rb");
     if (Obj == 0) {
-       Error ("Could not open `%s': %s", Name, strerror (errno));
+        Error ("Could not open `%s': %s", Name, strerror (errno));
     }
 
-    /* Get the modification time of the object file */
-    if (fstat (fileno (Obj), &StatBuf) != 0) {
-       Error ("Cannot stat object file `%s': %s", Name, strerror (errno));
+    /* Get the modification time of the object file. There's a race condition
+    ** here, since we cannot use fileno() (non-standard identifier in standard
+    ** header file), and therefore not fstat. When using stat with the
+    ** file name, there's a risk that the file was deleted and recreated
+    ** while it was open. Since mtime and size are only used to check
+    ** if a file has changed in the debugger, we will ignore this problem
+    ** here.
+    */
+    if (FileStat (Name, &StatBuf) != 0) {
+        Error ("Cannot stat object file `%s': %s", Name, strerror (errno));
     }
 
     /* Read and check the header */
@@ -159,59 +260,39 @@ void ObjAdd (const char* Name)
     /* Check if we already have a module with this name */
     O = FindObjData (Module);
     if (O == 0) {
-       /* Not found, create a new entry */
-       O = NewObjData ();
+        /* Not found, create a new entry */
+        O = NewObjData ();
     } else {
-       /* Found - check the file modification times of the internal copy
-        * and the external one.
-        */
-       if (difftime ((time_t)O->MTime, StatBuf.st_mtime) > 0.0) {
-           Warning ("Replacing module `%s' by older version", O->Name);
-       }
+        /* Found - check the file modification times of the internal copy
+        ** and the external one.
+        */
+        if (difftime ((time_t)O->MTime, StatBuf.st_mtime) > 0.0) {
+            Warning ("Replacing module `%s' by older version in library `%s'",
+                     O->Name, LibName);
+        }
+
+        /* Free data */
+        ClearObjData (O);
     }
 
     /* Initialize the object module data structure */
-    O->Name      = xstrdup (Module);
-    O->Flags     = OBJ_HAVEDATA;
-    O->MTime     = StatBuf.st_mtime;
-    O->ImportSize = H.ImportSize;
-    O->Imports   = xmalloc (O->ImportSize);
-    O->ExportSize = H.ExportSize;
-    O->Exports   = xmalloc (O->ExportSize);
-
-    /* Read imports and exports */
-    fseek (Obj, H.ImportOffs, SEEK_SET);
-    ReadData (Obj, O->Imports, O->ImportSize);
-    fseek (Obj, H.ExportOffs, SEEK_SET);
-    ReadData (Obj, O->Exports, O->ExportSize);
-
-    /* Skip the object file header */
-    O->Start = ftell (NewLib);
-    fseek (NewLib, OBJ_HDR_SIZE, SEEK_CUR);
-
-    /* Copy the remaining sections */
-    fseek (Obj, H.DbgSymOffs, SEEK_SET);
-    H.DbgSymOffs = LibCopyTo (Obj, H.DbgSymSize) - O->Start;
-    fseek (Obj, H.OptionOffs, SEEK_SET);
-    H.OptionOffs = LibCopyTo (Obj, H.OptionSize) - O->Start;
-    fseek (Obj, H.SegOffs, SEEK_SET);
-    H.SegOffs = LibCopyTo (Obj, H.SegSize) - O->Start;
-    fseek (Obj, H.FileOffs, SEEK_SET);
-    H.FileOffs = LibCopyTo (Obj, H.FileSize) - O->Start;
-
-    /* Calculate the amount of data written */
-    O->Size = ftell (NewLib) - O->Start;
-
-    /* Clear the remaining header fields */
-    H.ImportOffs = H.ImportSize = 0;
-    H.ExportOffs = H.ExportSize = 0;
-
-    /* Seek back and write the updated header */
-    fseek (NewLib, O->Start, SEEK_SET);
-    ObjWriteHeader (NewLib, &H);
-
-    /* Now seek again to end of file */
-    fseek (NewLib, 0, SEEK_END);
+    O->Name     = xstrdup (Module);
+    O->Flags    = OBJ_HAVEDATA;
+    O->MTime    = (unsigned long) StatBuf.st_mtime;
+    O->Start    = 0;
+
+    /* Determine the file size. Note: Race condition here */
+    fseek (Obj, 0, SEEK_END);
+    O->Size     = ftell (Obj);
+
+    /* Read the basic data from the object file */
+    ObjReadData (Obj, O);
+
+    /* Copy the complete object data to the library file and update the
+    ** starting offset
+    */
+    fseek (Obj, 0, SEEK_SET);
+    O->Start    = LibCopyTo (Obj, O->Size);
 
     /* Done, close the file (we read it only, so no error check) */
     fclose (Obj);
@@ -222,68 +303,37 @@ void ObjAdd (const char* Name)
 void ObjExtract (const char* Name)
 /* Extract a module from the library */
 {
-    unsigned long ImportStart;
-    unsigned long ExportStart;
-    struct utimbuf U;
-    ObjHeader H;
     FILE* Obj;
 
-
     /* Make a module name from the file name */
     const char* Module = GetModule (Name);
 
     /* Try to find the module in the library */
-    ObjData* O = FindObjData (Module);
+    const ObjData* O = FindObjData (Module);
 
     /* Bail out if the module does not exist */
     if (O == 0) {
-       Error ("Module `%s' not found in library", Module);
+        Error ("Module `%s' not found in library `%s'", Module, LibName);
     }
 
     /* Open the output file */
     Obj = fopen (Name, "w+b");
     if (Obj == 0) {
-       Error ("Cannot open target file `%s': %s", Name, strerror (errno));
+        Error ("Cannot open target file `%s': %s", Name, strerror (errno));
     }
 
-    /* Copy the first four segments including the header to the new file */
+    /* Copy the complete object file data from the library to the new object
+    ** file.
+    */
     LibCopyFrom (O->Start, O->Size, Obj);
 
-    /* Write imports and exports */
-    ImportStart = ftell (Obj);
-    WriteData (Obj, O->Imports, O->ImportSize);
-    ExportStart = ftell (Obj);
-    WriteData (Obj, O->Exports, O->ExportSize);
-
-    /* Seek back and read the header */
-    fseek (Obj, 0, SEEK_SET);
-    ObjReadHeader (Obj, &H, Name);
-
-    /* Update the header fields */
-    H.ImportOffs = ImportStart;
-    H.ImportSize = O->ImportSize;
-    H.ExportOffs = ExportStart;
-    H.ExportSize = O->ExportSize;
-
-    /* Write the changed header */
-    fseek (Obj, 0, SEEK_SET);
-    ObjWriteHeader (Obj, &H);
-
     /* Close the file */
     if (fclose (Obj) != 0) {
-       Error ("Problem closing object file `%s': %s", Name, strerror (errno));
+        Error ("Problem closing object file `%s': %s", Name, strerror (errno));
     }
 
     /* Set access and modification time */
-    U.actime = O->MTime;
-    U.modtime = O->MTime;
-    if (utime (Name, &U) != 0) {
-       Error ("Cannot set mod time on `%s': %s", Name, strerror (errno));
+    if (SetFileTimes (Name, O->MTime) != 0) {
+        Error ("Cannot set mod time on `%s': %s", Name, strerror (errno));
     }
 }
-
-
-
-
-
-