Merge pull request #424 from clbr/trampoline

Trampoline support
This commit is contained in:
Oliver Schmidt
2017-05-18 16:29:34 +02:00
committed by GitHub
12 changed files with 616 additions and 1 deletions

View File

@@ -58,6 +58,7 @@
#include "scanner.h"
#include "standard.h"
#include "symtab.h"
#include "wrappedcall.h"
#include "typeconv.h"
@@ -1315,6 +1316,8 @@ static FuncDesc* ParseFuncDecl (void)
{
unsigned Offs;
SymEntry* Sym;
SymEntry* WrappedCall;
unsigned char WrappedCallData;
/* Create a new function descriptor */
FuncDesc* F = NewFuncDesc ();
@@ -1380,6 +1383,13 @@ static FuncDesc* ParseFuncDecl (void)
/* Leave the lexical level remembering the symbol tables */
RememberFunctionLevel (F);
/* Did we have a WrappedCall for this function? */
GetWrappedCall((void **) &WrappedCall, &WrappedCallData);
if (WrappedCall) {
F->WrappedCall = WrappedCall;
F->WrappedCallData = WrappedCallData;
}
/* Return the function descriptor */
return F;
}
@@ -1447,6 +1457,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
/* Function declaration */
FuncDesc* F;
SymEntry* PrevEntry;
/* Skip the opening paren */
NextToken ();
@@ -1460,6 +1471,16 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
Qualifiers &= ~T_QUAL_FASTCALL;
}
/* Was there a previous entry? If so, copy WrappedCall info from it */
PrevEntry = FindGlobalSym (D->Ident);
if (PrevEntry && PrevEntry->Flags & SC_FUNC) {
FuncDesc* D = PrevEntry->V.F.Func;
if (D->WrappedCall && !F->WrappedCall) {
F->WrappedCall = D->WrappedCall;
F->WrappedCallData = D->WrappedCallData;
}
}
/* Add the function type. Be sure to bounds check the type buffer */
NeedTypeSpace (D, 1);
D->Type[D->Index].C = T_FUNC | Qualifiers;

View File

@@ -536,6 +536,10 @@ static void FunctionCall (ExprDesc* Expr)
/* Special handling for function pointers */
if (IsFuncPtr) {
if (Func->WrappedCall) {
Warning("Calling a wrapped function via a pointer, wrapped-call will not be used");
}
/* If the function is not a fastcall function, load the pointer to
** the function into the primary.
*/
@@ -584,7 +588,47 @@ static void FunctionCall (ExprDesc* Expr)
} else {
/* Normal function */
g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize);
if (Func->WrappedCall) {
char tmp[64];
StrBuf S = AUTO_STRBUF_INITIALIZER;
/* Store the WrappedCall data in tmp4 */
sprintf(tmp, "ldy #%u", Func->WrappedCallData);
SB_AppendStr (&S, tmp);
g_asmcode (&S);
SB_Clear(&S);
SB_AppendStr (&S, "sty tmp4");
g_asmcode (&S);
SB_Clear(&S);
/* Store the original function address in ptr4 */
SB_AppendStr (&S, "ldy #<(_");
SB_AppendStr (&S, (const char*) Expr->Name);
SB_AppendChar (&S, ')');
g_asmcode (&S);
SB_Clear(&S);
SB_AppendStr (&S, "sty ptr4");
g_asmcode (&S);
SB_Clear(&S);
SB_AppendStr (&S, "ldy #>(_");
SB_AppendStr (&S, (const char*) Expr->Name);
SB_AppendChar (&S, ')');
g_asmcode (&S);
SB_Clear(&S);
SB_AppendStr (&S, "sty ptr4+1");
g_asmcode (&S);
SB_Clear(&S);
SB_Done (&S);
g_call (TypeOf (Expr->Type), Func->WrappedCall->Name, ParamSize);
} else {
g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize);
}
}

View File

@@ -60,6 +60,8 @@ FuncDesc* NewFuncDesc (void)
F->ParamCount = 0;
F->ParamSize = 0;
F->LastParam = 0;
F->WrappedCall = 0;
F->WrappedCallData = 0;
/* Return the new struct */
return F;

View File

@@ -67,6 +67,8 @@ struct FuncDesc {
unsigned ParamCount; /* Number of parameters */
unsigned ParamSize; /* Size of the parameters */
struct SymEntry* LastParam; /* Pointer to last parameter */
struct SymEntry* WrappedCall; /* Pointer to the WrappedCall */
unsigned char WrappedCallData;/* The WrappedCall's user data */
};

View File

@@ -51,6 +51,7 @@
#include "scanstrbuf.h"
#include "symtab.h"
#include "pragma.h"
#include "wrappedcall.h"
@@ -88,6 +89,7 @@ typedef enum {
PRAGMA_STATIC_LOCALS,
PRAGMA_STATICLOCALS, /* obsolete */
PRAGMA_WARN,
PRAGMA_WRAPPED_CALL,
PRAGMA_WRITABLE_STRINGS,
PRAGMA_ZPSYM,
PRAGMA_COUNT
@@ -123,6 +125,7 @@ static const struct Pragma {
{ "static-locals", PRAGMA_STATIC_LOCALS },
{ "staticlocals", PRAGMA_STATICLOCALS }, /* obsolete */
{ "warn", PRAGMA_WARN },
{ "wrapped-call", PRAGMA_WRAPPED_CALL },
{ "writable-strings", PRAGMA_WRITABLE_STRINGS },
{ "zpsym", PRAGMA_ZPSYM },
};
@@ -446,6 +449,84 @@ ExitPoint:
}
static void WrappedCallPragma (StrBuf* B)
/* Handle the wrapped-call pragma */
{
StrBuf S = AUTO_STRBUF_INITIALIZER;
const char *Name;
long Val;
SymEntry *Entry;
/* Check for the "push" or "pop" keywords */
switch (ParsePushPop (B)) {
case PP_NONE:
Error ("Push or pop required");
break;
case PP_PUSH:
break;
case PP_POP:
PopWrappedCall();
/* Done */
goto ExitPoint;
case PP_ERROR:
/* Bail out */
goto ExitPoint;
default:
Internal ("Invalid result from ParsePushPop");
}
/* A symbol argument must follow */
if (!SB_GetSym (B, &S, NULL)) {
goto ExitPoint;
}
/* Skip the following comma */
if (!GetComma (B)) {
/* Error already flagged by GetComma */
Error ("Value required for wrapped-call identifier");
goto ExitPoint;
}
if (!GetNumber (B, &Val)) {
Error ("Value required for wrapped-call identifier");
goto ExitPoint;
}
if (Val < 0 || Val > 255) {
Error ("Identifier must be between 0-255");
goto ExitPoint;
}
/* Get the string */
Name = SB_GetConstBuf (&S);
Entry = FindSym(Name);
/* Check if the name is valid */
if (Entry && Entry->Flags & SC_FUNC) {
PushWrappedCall(Entry, Val);
Entry->Flags |= SC_REF;
} else {
/* Segment name is invalid */
Error ("Wrapped-call target does not exist or is not a function");
}
ExitPoint:
/* Call the string buf destructor */
SB_Done (&S);
}
static void CharMapPragma (StrBuf* B)
/* Change the character map */
@@ -791,6 +872,10 @@ static void ParsePragma (void)
FlagPragma (&B, &StaticLocals);
break;
case PRAGMA_WRAPPED_CALL:
WrappedCallPragma(&B);
break;
case PRAGMA_WARN:
WarnPragma (&B);
break;

102
src/cc65/wrappedcall.c Normal file
View File

@@ -0,0 +1,102 @@
/*****************************************************************************/
/* */
/* wrappedcall.c */
/* */
/* WrappedCall management */
/* */
/* */
/* */
/* (C) 2017, Mega Cat Studios */
/* */
/* */
/* 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. */
/* */
/* 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: */
/* */
/* 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. */
/* 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. */
/* */
/*****************************************************************************/
#include <stdarg.h>
#include <string.h>
/* common */
#include "chartype.h"
#include "check.h"
#include "coll.h"
#include "scanner.h"
#include "intptrstack.h"
#include "xmalloc.h"
/* cc65 */
#include "codeent.h"
#include "error.h"
#include "wrappedcall.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* WrappedCalls */
static IntPtrStack WrappedCalls;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void PushWrappedCall (void *Ptr, unsigned char Val)
/* Push the current WrappedCall */
{
if (IPS_IsFull (&WrappedCalls)) {
Error ("WrappedCall stack overflow");
} else {
IPS_Push (&WrappedCalls, Val, Ptr);
}
}
void PopWrappedCall (void)
/* Remove the current WrappedCall */
{
if (IPS_GetCount (&WrappedCalls) < 1) {
Error ("WrappedCall stack is empty");
} else {
IPS_Drop (&WrappedCalls);
}
}
void GetWrappedCall (void **Ptr, unsigned char *Val)
/* Get the current WrappedCall */
{
if (IPS_GetCount (&WrappedCalls) < 1) {
*Ptr = NULL;
*Val = 0;
} else {
long Temp;
IPS_Get (&WrappedCalls, &Temp, Ptr);
*Val = Temp;
}
}

65
src/cc65/wrappedcall.h Normal file
View File

@@ -0,0 +1,65 @@
/*****************************************************************************/
/* */
/* wrappedcall.h */
/* */
/* Wrapped-call management */
/* */
/* */
/* */
/* (C) 2017, Mega Cat Studios */
/* */
/* */
/* 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. */
/* */
/* 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: */
/* */
/* 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. */
/* 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. */
/* */
/*****************************************************************************/
#ifndef WRAPPEDCALL_H
#define WRAPPEDCALL_H
#include <stdio.h>
/* common */
#include "attrib.h"
/* cc65 */
#include "opcodes.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void PushWrappedCall (void *Ptr, unsigned char Val);
/* Push the current WrappedCall */
void PopWrappedCall (void);
/* Pop the current WrappedCall */
void GetWrappedCall (void **Ptr, unsigned char *Val);
/* Get the current WrappedCall, if any */
/* End of wrappedcall.h */
#endif

90
src/common/intptrstack.c Normal file
View File

@@ -0,0 +1,90 @@
/*****************************************************************************/
/* */
/* intptrstack.c */
/* */
/* Integer+ptr stack used for program settings */
/* */
/* */
/* */
/* (C) 2017, Mega Cat Studios */
/* */
/* */
/* 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. */
/* */
/* 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: */
/* */
/* 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. */
/* 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. */
/* */
/*****************************************************************************/
/* common */
#include "check.h"
#include "intptrstack.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void IPS_Get (const IntPtrStack* S, long *Val, void **Ptr)
/* Get the value on top of an int stack */
{
PRECONDITION (S->Count > 0);
if (Val) *Val = S->Stack[S->Count-1].val;
if (Ptr) *Ptr = S->Stack[S->Count-1].ptr;
}
void IPS_Set (IntPtrStack* S, long Val, void *Ptr)
/* Set the value on top of an int stack */
{
PRECONDITION (S->Count > 0);
S->Stack[S->Count-1].val = Val;
S->Stack[S->Count-1].ptr = Ptr;
}
void IPS_Drop (IntPtrStack* S)
/* Drop a value from an int stack */
{
PRECONDITION (S->Count > 0);
--S->Count;
}
void IPS_Push (IntPtrStack* S, long Val, void *Ptr)
/* Push a value onto an int stack */
{
PRECONDITION (S->Count < sizeof (S->Stack) / sizeof (S->Stack[0]));
S->Stack[S->Count].val = Val;
S->Stack[S->Count++].ptr = Ptr;
}
void IPS_Pop (IntPtrStack* S, long *Val, void **Ptr)
/* Pop a value from an int stack */
{
PRECONDITION (S->Count > 0);
if (Val) *Val = S->Stack[--S->Count].val;
if (Ptr) *Ptr = S->Stack[S->Count].ptr;
}

121
src/common/intptrstack.h Normal file
View File

@@ -0,0 +1,121 @@
/*****************************************************************************/
/* */
/* intptrstack.h */
/* */
/* Integer+ptr stack used for program settings */
/* */
/* */
/* */
/* (C) 2017, Mega Cat Studios */
/* */
/* */
/* 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. */
/* */
/* 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: */
/* */
/* 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. */
/* 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. */
/* */
/*****************************************************************************/
#ifndef INTPTRSTACK_H
#define INTPTRSTACK_H
#include "inline.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
typedef struct IntPtrStack IntPtrStack;
struct IntPtrInner {
long val;
void *ptr;
};
struct IntPtrStack {
unsigned Count;
struct IntPtrInner Stack[8];
};
/* An initializer for an empty int stack */
#define STATIC_INTPTRSTACK_INITIALIZER { 0, { 0, 0 }, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} } }
/* Declare an int stack with the given value as first element */
#define INTPTRSTACK(Val, Ptr) { 1, { {Val, Ptr}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} } }
/*****************************************************************************/
/* Code */
/*****************************************************************************/
#if defined(HAVE_INLINE)
INLINE int IPS_IsFull (const IntPtrStack* S)
/* Return true if there is no space left on the given int stack */
{
return (S->Count >= sizeof (S->Stack) / sizeof (S->Stack[0]));
}
#else
# define IPS_IsFull(S) ((S)->Count >= sizeof ((S)->Stack) / sizeof ((S)->Stack[0]))
#endif
#if defined(HAVE_INLINE)
INLINE int IPS_IsEmpty (const IntPtrStack* S)
/* Return true if there are no values on the given int stack */
{
return (S->Count == 0);
}
#else
# define IPS_IsEmpty(S) ((S)->Count == 0)
#endif
#if defined(HAVE_INLINE)
INLINE unsigned IPS_GetCount (const IntPtrStack* S)
/* Return the number of elements on the given int stack */
{
return S->Count;
}
#else
# define IPS_GetCount(S) (S)->Count
#endif
void IPS_Get (const IntPtrStack* S, long *Val, void **Ptr);
/* Get the value on top of an int stack */
void IPS_Set (IntPtrStack* S, long Val, void *Ptr);
/* Set the value on top of an int stack */
void IPS_Drop (IntPtrStack* S);
/* Drop a value from an int stack */
void IPS_Push (IntPtrStack* S, long Val, void *Ptr);
/* Push a value onto an int stack */
void IPS_Pop (IntPtrStack* S, long *Val, void **Ptr);
/* Pop a value from an int stack */
/* End of IntPtrStack.h */
#endif