+
+ 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 /) 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
+ #pragma zpsym (<name>)
Tell the compiler that the -- previously as external declared -- symbol with
diff --git a/src/cc65/expr.c b/src/cc65/expr.c
index fdf18c4d6..ee658fbb5 100644
--- a/src/cc65/expr.c
+++ b/src/cc65/expr.c
@@ -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;
diff --git a/src/cc65/function.c b/src/cc65/function.c
index 09f44d39c..dcc625a69 100644
--- a/src/cc65/function.c
+++ b/src/cc65/function.c
@@ -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 ();
diff --git a/src/cc65/litpool.c b/src/cc65/litpool.c
index e026db0d4..30c605d5f 100644
--- a/src/cc65/litpool.c
+++ b/src/cc65/litpool.c
@@ -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"
@@ -54,8 +56,27 @@
-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,16 +210,8 @@ void ResetLiteralPoolOffs (unsigned Offs)
* removing values from the pool.
*/
{
- CHECK (Offs <= SB_GetLen (&LiteralPool));
- SB_Cut (&LiteralPool, Offs);
-}
-
-
-
-void AddLiteralChar (char C)
-/* Add one character to the literal pool */
-{
- SB_AppendChar (&LiteralPool, C);
+ CHECK (Offs <= SB_GetLen (&LP->Pool));
+ SB_Cut (&LP->Pool, Offs);
}
@@ -143,11 +221,21 @@ unsigned AddLiteral (const char* S)
* the pool
*/
{
- /* Remember the starting offset */
- unsigned Start = SB_GetLen (&LiteralPool);
+ return AddLiteralBuf (S, strlen (S) + 1);
+}
- /* Copy the string including the terminator growing the buffer if needed */
- SB_AppendBuf (&LiteralPool, S, strlen (S) + 1);
+
+
+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 (&LP->Pool);
+
+ /* 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));
}
diff --git a/src/cc65/litpool.h b/src/cc65/litpool.h
index 99fd27bfb..26f602ca3 100644
--- a/src/cc65/litpool.h
+++ b/src/cc65/litpool.h
@@ -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 */
diff --git a/src/cc65/pragma.c b/src/cc65/pragma.c
index 510683df1..37ae1bbb1 100644
--- a/src/cc65/pragma.c
+++ b/src/cc65/pragma.c
@@ -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;
diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c
index 74ceb6742..ecd023d05 100644
--- a/src/cc65/scanner.c
+++ b/src/cc65/scanner.c
@@ -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);
}