1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-01 13:41:34 +00:00

Create one literal pool per function, so that literal pool data is removed

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
This commit is contained in:
uz 2009-12-04 14:12:25 +00:00
parent 1f90ec93a0
commit 50ff6d0768
7 changed files with 231 additions and 74 deletions

View 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

View 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;

View 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 ();

View 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"
@ -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));
}

View 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 */

View 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;

View 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);
}