]> git.sur5r.net Git - cc65/commitdiff
Create one literal pool per function, so that literal pool data is removed
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Fri, 4 Dec 2009 14:12:25 +0000 (14:12 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Fri, 4 Dec 2009 14:12:25 +0000 (14:12 +0000)
together with a function, if it is not used. Literal storage can now be
controlled by #pragma writable-strings on a per function basis.

git-svn-id: svn://svn.cc65.org/cc65/trunk@4499 b7a2c559-68d2-44c3-8de9-860c34a00d81

doc/cc65.sgml
src/cc65/expr.c
src/cc65/function.c
src/cc65/litpool.c
src/cc65/litpool.h
src/cc65/pragma.c
src/cc65/scanner.c

index 4171a41d450e8d87f65c06aab31ac504435f9826..fddb3793719454b25191c6933f7bfc6defd055e0 100644 (file)
@@ -244,7 +244,7 @@ Here is a description of all the command line options:
   better way is to declare characters explicitly as "signed" if needed. You
   can also use <tt><ref id="pragma-signed-chars"
   name="#pragma&nbsp;signed-chars"></tt> for better control of this option.
-
+                                                                        
 
   <label id="option--standard">
   <tag><tt>--standard std</tt></tag>
@@ -300,7 +300,9 @@ Here is a description of all the command line options:
   <tag><tt>--writable-strings</tt></tag>
 
   Make string literals writable by placing them into the data segment instead
-  of the rodata segment.
+  of the rodata segment. You can also use <tt><ref id="pragma-writable-strings"
+  name="#pragma&nbsp;writable-strings"></tt> to control this option on a
+  per function basis.
 
 
   <label id="option-static-locals">
@@ -975,6 +977,26 @@ parameter with the <tt/#pragma/.
         #pragma warn (unused-param, pop)
   </verb></tscreen>
 
+<sect1><tt>#pragma writable-strings ([push,] on|off)</tt><label id="pragma-writable-strings"><p>
+
+  Changes the storage location of string literals. For historical reasons, 
+  the C standard defines that string literals are of type "char[]", but 
+  writing to such a literal causes undefined behaviour. Most compilers 
+  (including cc65) place string literals in the read-only data segment, which
+  may cause problems with old C code that writes to string literals.
+
+  Using this pragma (or the corresponding command line option <tt/<ref
+  name="--writable-strings" id="option-writable-strings">/) causes the
+  literals to be placed in the data segment so they can be written to without
+  worry.
+
+  Please note that the value of this flag that is in effect when a function
+  is encountered, determines where the literals are stored. Changing the 
+  <tt/#pragma/ within a function doesn't have an effect for this function.
+
+  The <tt/#pragma/ understands the push and pop parameters as explained above.
+
+
 <sect1><tt>#pragma zpsym (&lt;name&gt;)</tt><p>
 
   Tell the compiler that the -- previously as external declared -- symbol with
index fdf18c4d687395b59c3fc91eaa6f82629d6b4951..ee658fbb58208240b9770d6ba3fc9c6dea69e646 100644 (file)
@@ -751,7 +751,7 @@ static void Primary (ExprDesc* E)
             E->Type  = GetCharArrayType (GetLiteralPoolOffs () - CurTok.IVal);
             E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL;
             E->IVal  = CurTok.IVal;
-            E->Name  = LiteralPoolLabel;
+            E->Name  = GetLiteralPoolLabel ();
             NextToken ();
             break;
 
index 09f44d39c3e52b04283c9931f4c4509fb73cc290..dcc625a690c0d5213a7404d88ab5fcb4dbf150d0 100644 (file)
@@ -380,9 +380,9 @@ void NewFunc (SymEntry* Func)
     /* Reenter the lexical level */
     ReenterFunctionLevel (D);
 
-    /* Check if the function header contains unnamed parameters. These are 
+    /* Check if the function header contains unnamed parameters. These are
      * only allowed in cc65 mode.
-     */ 
+     */
     if ((D->Flags & FD_UNNAMED_PARAMS) != 0 && (IS_Get (&Standard) != STD_CC65)) {
         Error ("Parameter name omitted");
     }
@@ -439,6 +439,9 @@ void NewFunc (SymEntry* Func)
     /* Allocate code and data segments for this function */
     Func->V.F.Seg = PushSegments (Func);
 
+    /* Allocate a new literal pool */
+    PushLiteralPool (Func);
+
     /* If this is a fastcall function, push the last parameter onto the stack */
     if (IsQualFastcall (Func->Type) && D->ParamCount > 0) {
 
@@ -539,6 +542,10 @@ void NewFunc (SymEntry* Func)
     /* Eat the closing brace */
     ConsumeRCurly ();
 
+    /* Dump the literal pool, the restore the old one */
+    DumpLiteralPool ();
+    PopLiteralPool ();
+
     /* Switch back to the old segments */
     PopSegments ();
 
index e026db0d49af72c85687d75068e9ef46c7bfa785..30c605d5fb7b1afee0407d3f737fe4c1651125bb 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2004 Ullrich von Bassewitz                                        */
-/*               Römerstraße 52                                              */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 1998-2009, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -37,7 +37,9 @@
 
 /* common */
 #include "check.h"
+#include "coll.h"
 #include "tgttrans.h"
+#include "xmalloc.h"
 
 /* cc65 */
 #include "asmlabel.h"
 
 
 
-unsigned             LiteralPoolLabel  = 0;    /* Pool asm label */
-static StrBuf         LiteralPool       = STATIC_STRBUF_INITIALIZER;
+/* Forward for struct SymEntry */
+struct SymEntry;
+
+/* Definition of the literal pool */
+typedef struct LiteralPool LiteralPool;
+struct LiteralPool {
+    int                 Writable;       /* True if strings are writable */
+    unsigned            Label;          /* Pool asm label */
+    struct SymEntry*    Func;           /* Function that contains the pool */
+    StrBuf              Pool;           /* The pool itself */
+};
+
+/* The current literal pool */
+static LiteralPool*     LP = 0;
+
+/* Stack that contains the nested literal pools. Since TOS is in LiteralPool
+ * and functions aren't nested in C, the maximum depth is 1. I'm using a
+ * collection anyway, so the code is prepared for nested functions or
+ * whatever.
+ */
+static Collection       LPStack  = STATIC_COLLECTION_INITIALIZER;
 
 
 
@@ -65,11 +86,68 @@ static StrBuf         LiteralPool       = STATIC_STRBUF_INITIALIZER;
 
 
 
+static LiteralPool* NewLiteralPool (struct SymEntry* Func)
+/* Create a new literal pool and return it */
+{
+    /* Allocate memory */
+    LiteralPool* LP = xmalloc (sizeof (*LP));
+
+    /* Initialize the fields */
+    LP->Writable = IS_Get (&WritableStrings);
+    LP->Label = GetLocalLabel ();
+    LP->Func  = Func;
+    SB_Init (&LP->Pool);
+
+    /* Return the new pool */
+    return LP;
+}
+
+
+
+static void FreeLiteralPool (LiteralPool* LP)
+/* Free a LiteralPool structure */
+{
+    /* Free the string buffer contained within the struct */
+    SB_Done (&LP->Pool);
+
+    /* Free the struct itself */
+    xfree (LP);
+}
+
+
+
 void InitLiteralPool (void)
 /* Initialize the literal pool */
 {
-    /* Get the pool label */
-    LiteralPoolLabel = GetLocalLabel ();
+    /* Create a new pool */
+    LP = NewLiteralPool (0);
+}
+
+
+
+void PushLiteralPool (struct SymEntry* Func)
+/* Push the current literal pool onto the stack and create a new one */
+{
+    /* We must have a literal pool to push! */
+    PRECONDITION (LP != 0);
+
+    /* Push the old pool */
+    CollAppend (&LPStack, LP);
+
+    /* Create a new one */
+    LP = NewLiteralPool (Func);
+}
+
+
+
+void PopLiteralPool (void)
+/* Free the current literal pool and restore the one from TOS */
+{
+    /* Free the current literal pool */
+    FreeLiteralPool (LP);
+
+    /* Pop one from stack */
+    LP = CollPop (&LPStack);
 }
 
 
@@ -79,7 +157,7 @@ void TranslateLiteralPool (unsigned Offs)
  * charset.
  */
 {
-    TgtTranslateBuf (SB_GetBuf (&LiteralPool) + Offs, SB_GetLen (&LiteralPool) - Offs);
+    TgtTranslateBuf (SB_GetBuf (&LP->Pool) + Offs, SB_GetLen (&LP->Pool) - Offs);
 }
 
 
@@ -88,25 +166,33 @@ void DumpLiteralPool (void)
 /* Dump the literal pool */
 {
     /* If nothing there, exit... */
-    if (SB_GetLen (&LiteralPool) == 0) {
+    if (SB_GetLen (&LP->Pool) == 0) {
        return;
     }
 
-    /* Switch to the data segment */
-    if (IS_Get (&WritableStrings)) {
+    /* Switch to the correct segment */
+    if (LP->Writable) {
        g_usedata ();
     } else {
                g_userodata ();
     }
 
     /* Define the label */
-    g_defdatalabel (LiteralPoolLabel);
+    g_defdatalabel (LP->Label);
 
     /* Translate the buffer contents into the target charset */
     TranslateLiteralPool (0);
 
     /* Output the buffer data */
-    g_defbytes (SB_GetConstBuf (&LiteralPool), SB_GetLen (&LiteralPool));
+    g_defbytes (SB_GetConstBuf (&LP->Pool), SB_GetLen (&LP->Pool));
+}
+
+
+
+unsigned GetLiteralPoolLabel (void)
+/* Return the asm label for the current literal pool */
+{
+    return LP->Label;
 }
 
 
@@ -114,7 +200,7 @@ void DumpLiteralPool (void)
 unsigned GetLiteralPoolOffs (void)
 /* Return the current offset into the literal pool */
 {
-    return SB_GetLen (&LiteralPool);
+    return SB_GetLen (&LP->Pool);
 }
 
 
@@ -124,30 +210,32 @@ void ResetLiteralPoolOffs (unsigned Offs)
  * removing values from the pool.
  */
 {
-    CHECK (Offs <= SB_GetLen (&LiteralPool));
-    SB_Cut (&LiteralPool, Offs);
+    CHECK (Offs <= SB_GetLen (&LP->Pool));
+    SB_Cut (&LP->Pool, Offs);
 }
 
 
 
-void AddLiteralChar (char C)
-/* Add one character to the literal pool */
+unsigned AddLiteral (const char* S)
+/* Add a literal string to the literal pool. Return the starting offset into
+ * the pool
+ */
 {
-    SB_AppendChar (&LiteralPool, C);
+    return AddLiteralBuf (S, strlen (S) + 1);
 }
 
 
 
-unsigned AddLiteral (const char* S)
-/* Add a literal string to the literal pool. Return the starting offset into
- * the pool
+unsigned AddLiteralBuf (const void* Buf, unsigned Len)
+/* Add a buffer containing a literal string to the literal pool. Return the
+ * starting offset into the pool for this string.
  */
 {
     /* Remember the starting offset */
-    unsigned Start = SB_GetLen (&LiteralPool);
+    unsigned Start = SB_GetLen (&LP->Pool);
 
-    /* Copy the string including the terminator growing the buffer if needed */
-    SB_AppendBuf (&LiteralPool, S, strlen (S) + 1);
+    /* Append the buffer */
+    SB_AppendBuf (&LP->Pool, Buf, Len);
 
     /* Return the starting offset */
     return Start;
@@ -155,11 +243,21 @@ unsigned AddLiteral (const char* S)
 
 
 
+unsigned AddLiteralStr (const StrBuf* S)
+/* Add a literal string to the literal pool. Return the starting offset into
+ * the pool for this string.
+ */
+{
+    return AddLiteralBuf (SB_GetConstBuf (S), SB_GetLen (S));
+}
+
+
+
 const char* GetLiteral (unsigned Offs)
 /* Get a pointer to the literal with the given offset in the pool */
 {
-    CHECK (Offs < SB_GetLen (&LiteralPool));
-    return SB_GetConstBuf (&LiteralPool) + Offs;
+    CHECK (Offs < SB_GetLen (&LP->Pool));
+    return SB_GetConstBuf (&LP->Pool) + Offs;
 }
 
 
@@ -169,8 +267,8 @@ void GetLiteralStrBuf (StrBuf* Target, unsigned Offs)
  * into Target.
  */
 {
-    CHECK (Offs <= SB_GetLen (&LiteralPool));
-    SB_Slice (Target, &LiteralPool, Offs, SB_GetLen (&LiteralPool) - Offs);
+    CHECK (Offs <= SB_GetLen (&LP->Pool));
+    SB_Slice (Target, &LP->Pool, Offs, SB_GetLen (&LP->Pool) - Offs);
 }
 
 
@@ -178,7 +276,7 @@ void GetLiteralStrBuf (StrBuf* Target, unsigned Offs)
 void PrintLiteralPoolStats (FILE* F)
 /* Print statistics about the literal space used */
 {
-    fprintf (F, "Literal space used: %u bytes\n", SB_GetLen (&LiteralPool));
+    fprintf (F, "Literal space used: %u bytes\n", SB_GetLen (&LP->Pool));
 }
 
 
index 99fd27bfbe15c0fda7d2ce18a8b8bb6b68a0c5d4..26f602ca32cbb8910c4938a15733fb8435edee1b 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2001 Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
-/* EMail:        uz@cc65.org                                                */
+/* (C) 1998-2009, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -51,7 +51,8 @@
 
 
 
-extern unsigned LiteralPoolLabel;              /* Pool asm label */
+/* Forward for struct SymEntry */
+struct SymEntry;
 
 
 
@@ -64,6 +65,12 @@ extern unsigned LiteralPoolLabel;            /* Pool asm label */
 void InitLiteralPool (void);
 /* Initialize the literal pool */
 
+void PushLiteralPool (struct SymEntry* Func);
+/* Push the current literal pool onto the stack and create a new one */
+
+void PopLiteralPool (void);
+/* Free the current literal pool and restore the one from TOS */
+
 void TranslateLiteralPool (unsigned Offs);
 /* Translate the literals starting from the given offset into the target
  * charset.
@@ -72,6 +79,9 @@ void TranslateLiteralPool (unsigned Offs);
 void DumpLiteralPool (void);
 /* Dump the literal pool */
 
+unsigned GetLiteralPoolLabel (void);
+/* Return the asm label for the current literal pool */
+
 unsigned GetLiteralPoolOffs (void);
 /* Return the current offset into the literal pool */
 
@@ -80,14 +90,21 @@ void ResetLiteralPoolOffs (unsigned Offs);
  * removing values from the pool.
  */
 
-void AddLiteralChar (char C);
-/* Add one character to the literal pool */
-
 unsigned AddLiteral (const char* S);
 /* Add a literal string to the literal pool. Return the starting offset into
  * the pool for this string.
  */
 
+unsigned AddLiteralBuf (const void* Buf, unsigned Len);
+/* Add a buffer containing a literal string to the literal pool. Return the
+ * starting offset into the pool for this string.
+ */
+
+unsigned AddLiteralStr (const StrBuf* S);
+/* Add a literal string to the literal pool. Return the starting offset into
+ * the pool for this string.
+ */
+
 const char* GetLiteral (unsigned Offs);
 /* Get a pointer to the literal with the given offset in the pool */
 
index 510683df1720713ecf3553ef45fdb20409a90423..37ae1bbb140991cbab8a7c3741c3024e533d8f2a 100644 (file)
@@ -84,6 +84,7 @@ typedef enum {
     PRAGMA_STATIC_LOCALS,
     PRAGMA_STATICLOCALS,                                /* obsolete */
     PRAGMA_WARN,
+    PRAGMA_WRITABLE_STRINGS,
     PRAGMA_ZPSYM,
     PRAGMA_COUNT
 } pragma_t;
@@ -93,28 +94,29 @@ static const struct Pragma {
     const char*        Key;            /* Keyword */
     pragma_t           Tok;            /* Token */
 } Pragmas[PRAGMA_COUNT] = {
-    { "bss-name",       PRAGMA_BSS_NAME         },
-    { "bssseg",         PRAGMA_BSSSEG           },      /* obsolete */
-    { "charmap",        PRAGMA_CHARMAP          },
-    { "check-stack",    PRAGMA_CHECK_STACK      },
-    { "checkstack",     PRAGMA_CHECKSTACK      },      /* obsolete */
-    { "code-name",      PRAGMA_CODE_NAME        },
-    { "codeseg",        PRAGMA_CODESEG         },      /* obsolete */
-    { "codesize",       PRAGMA_CODESIZE         },
-    { "data-name",      PRAGMA_DATA_NAME        },
-    { "dataseg",        PRAGMA_DATASEG         },      /* obsolete */
-    { "optimize",       PRAGMA_OPTIMIZE         },
-    { "register-vars",  PRAGMA_REGISTER_VARS    },
-    { "regvaraddr",     PRAGMA_REGVARADDR      },
-    { "regvars",        PRAGMA_REGVARS          },      /* obsolete */
-    { "rodata-name",    PRAGMA_RODATA_NAME      },
-    { "rodataseg",      PRAGMA_RODATASEG       },      /* obsolete */
-    { "signed-chars",   PRAGMA_SIGNED_CHARS     },
-    { "signedchars",    PRAGMA_SIGNEDCHARS     },      /* obsolete */
-    { "static-locals",  PRAGMA_STATIC_LOCALS    },
-    { "staticlocals",   PRAGMA_STATICLOCALS    },      /* obsolete */
-    { "warn",           PRAGMA_WARN             },
-    { "zpsym",          PRAGMA_ZPSYM           },
+    { "bss-name",               PRAGMA_BSS_NAME         },
+    { "bssseg",                 PRAGMA_BSSSEG           },      /* obsolete */
+    { "charmap",                PRAGMA_CHARMAP          },
+    { "check-stack",            PRAGMA_CHECK_STACK      },
+    { "checkstack",             PRAGMA_CHECKSTACK      },      /* obsolete */
+    { "code-name",              PRAGMA_CODE_NAME        },
+    { "codeseg",                PRAGMA_CODESEG         },      /* obsolete */
+    { "codesize",               PRAGMA_CODESIZE         },
+    { "data-name",              PRAGMA_DATA_NAME        },
+    { "dataseg",                PRAGMA_DATASEG         },      /* obsolete */
+    { "optimize",               PRAGMA_OPTIMIZE         },
+    { "register-vars",          PRAGMA_REGISTER_VARS    },
+    { "regvaraddr",             PRAGMA_REGVARADDR      },
+    { "regvars",                PRAGMA_REGVARS          },      /* obsolete */
+    { "rodata-name",            PRAGMA_RODATA_NAME      },
+    { "rodataseg",              PRAGMA_RODATASEG       },      /* obsolete */
+    { "signed-chars",           PRAGMA_SIGNED_CHARS     },
+    { "signedchars",            PRAGMA_SIGNEDCHARS     },      /* obsolete */
+    { "static-locals",          PRAGMA_STATIC_LOCALS    },
+    { "staticlocals",           PRAGMA_STATICLOCALS    },      /* obsolete */
+    { "warn",                   PRAGMA_WARN             },
+    { "writable-strings",       PRAGMA_WRITABLE_STRINGS },
+    { "zpsym",                  PRAGMA_ZPSYM           },
 };
 
 /* Result of ParsePushPop */
@@ -772,6 +774,10 @@ static void ParsePragma (void)
             WarnPragma (&B);
             break;
 
+        case PRAGMA_WRITABLE_STRINGS:
+            FlagPragma (&B, &WritableStrings);
+            break;
+
        case PRAGMA_ZPSYM:
            StringPragma (&B, MakeZPSym);
            break;
index 74ceb6742c4a9137aa885d78ee3859d0b9644473..ecd023d0539c680f356611dcd4d217a67213c58c 100644 (file)
@@ -406,9 +406,9 @@ static void CharConst (void)
 
 static void StringConst (void)
 /* Parse a quoted string */
-{
-    NextTok.IVal = GetLiteralPoolOffs ();
-    NextTok.Tok  = TOK_SCONST;
+{        
+    /* String buffer */
+    StrBuf S = AUTO_STRBUF_INITIALIZER;
 
     /* Concatenate strings. If at least one of the concenated strings is a wide
      * character literal, the whole string is a wide char literal, otherwise
@@ -436,7 +436,7 @@ static void StringConst (void)
                Error ("Unexpected newline");
                break;
            }
-           AddLiteralChar (ParseChar ());
+                   SB_AppendChar (&S, ParseChar ());
        }
 
        /* Skip closing quote char if there was one */
@@ -448,7 +448,14 @@ static void StringConst (void)
     }
 
     /* Terminate the string */
-    AddLiteralChar ('\0');
+    SB_AppendChar (&S, '\0');
+
+    /* Add the whole string to the literal pool */
+    NextTok.IVal = AddLiteralStr (&S);
+    NextTok.Tok  = TOK_SCONST;
+
+    /* Free the buffer */
+    SB_Done (&S);
 }