Fixed wrapped call when the function to wrap has already got defined before it is wrapped with the pragma.

This commit is contained in:
acqn 2023-12-10 00:47:10 +08:00
parent b1c1502494
commit b66682a05b
8 changed files with 34 additions and 50 deletions

View File

@ -1613,13 +1613,13 @@ parameter with the <tt/#pragma/.
This pragma sets a wrapper for functions, often used for trampolines. This pragma sets a wrapper for functions, often used for trampolines.
The name is a function returning <tt/void/, and taking no parameters. The <tt/name/ is a wrapper function returning <tt/void/, and taking no parameters.
It must preserve the CPU's <tt/A/ and <tt/X/ registers if it wraps any It must preserve the CPU's <tt/A/ and <tt/X/ registers if it wraps any
<tt/__fastcall__/ functions that have parameters. It must preserve <tt/__fastcall__/ functions that have parameters. It must preserve
the <tt/Y/ register if it wraps any variadic functions (they have "<tt/.../" the <tt/Y/ register if it wraps any variadic functions (they have "<tt/.../"
in their prototypes). in their prototypes).
The identifier is an 8-bit number that's set into <tt/tmp4/. If the identifier The <tt/identifier/ is an 8-bit number that's set into <tt/tmp4/. If the <tt/identifier/
is "bank", then ca65's <tt><url url="ca65.html#.BANK" name=".bank"></tt> function will be used is "bank", then ca65's <tt><url url="ca65.html#.BANK" name=".bank"></tt> function will be used
to determine the number from the bank attribute defined in the linker config, to determine the number from the bank attribute defined in the linker config,
see <url url="ld65.html#MEMORY" name="Other MEMORY area attributes">. Note that see <url url="ld65.html#MEMORY" name="Other MEMORY area attributes">. Note that
@ -1629,6 +1629,11 @@ parameter with the <tt/#pragma/.
The address of a wrapped function is passed in <tt/ptr4/. The wrapper can The address of a wrapped function is passed in <tt/ptr4/. The wrapper can
call that function by using "<tt/jsr callptr4/". call that function by using "<tt/jsr callptr4/".
All functions ever declared or defined when this pragma is in effect will be wrapped
when they are called explicitly by their names later in the same translation unit.
Invocation of these functions in any other ways, for example, that via a function
pointer or in inline assembly code, will not be wrapped.
This feature is useful, for example, with banked memory, to switch banks This feature is useful, for example, with banked memory, to switch banks
automatically to where a wrapped function resides, and then to restore the automatically to where a wrapped function resides, and then to restore the
previous bank when it returns. previous bank when it returns.

View File

@ -61,7 +61,6 @@
#include "standard.h" #include "standard.h"
#include "staticassert.h" #include "staticassert.h"
#include "symtab.h" #include "symtab.h"
#include "wrappedcall.h"
#include "typeconv.h" #include "typeconv.h"
@ -1965,9 +1964,6 @@ static void ParseAnsiParamList (FuncDesc* F)
static FuncDesc* ParseFuncDecl (void) static FuncDesc* ParseFuncDecl (void)
/* Parse the argument list of a function with the enclosing parentheses */ /* Parse the argument list of a function with the enclosing parentheses */
{ {
SymEntry* WrappedCall;
unsigned int WrappedCallData;
/* Create a new function descriptor */ /* Create a new function descriptor */
FuncDesc* F = NewFuncDesc (); FuncDesc* F = NewFuncDesc ();
@ -2023,13 +2019,6 @@ static FuncDesc* ParseFuncDecl (void)
/* Leave the lexical level remembering the symbol tables */ /* Leave the lexical level remembering the symbol tables */
RememberFunctionLevel (F); 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 the function descriptor */
return F; return F;
} }
@ -2099,7 +2088,6 @@ static void DirectDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode)
/* Function declarator */ /* Function declarator */
FuncDesc* F; FuncDesc* F;
SymEntry* PrevEntry;
/* Parse the function declarator */ /* Parse the function declarator */
F = ParseFuncDecl (); F = ParseFuncDecl ();
@ -2110,16 +2098,6 @@ static void DirectDecl (DeclSpec* Spec, Declarator* D, declmode_t Mode)
Qualifiers &= ~T_QUAL_FASTCALL; 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 = GetFuncDesc (PrevEntry->Type);
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 */ /* Add the function type. Be sure to bounds check the type buffer */
NeedTypeSpace (D, 1); NeedTypeSpace (D, 1);
D->Type[D->Index].C = T_FUNC | Qualifiers; D->Type[D->Index].C = T_FUNC | Qualifiers;

View File

@ -1057,11 +1057,6 @@ static void FunctionCall (ExprDesc* Expr)
/* Special handling for function pointers */ /* Special handling for function pointers */
if (IsFuncPtr) { 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 /* If the function is not a fastcall function, load the pointer to
** the function into the primary. ** the function into the primary.
*/ */
@ -1110,18 +1105,18 @@ static void FunctionCall (ExprDesc* Expr)
} else { } else {
/* Normal function */ /* Normal function */
if (Func->WrappedCall) { if (Expr->Sym && Expr->Sym->V.F.WrappedCall) {
char tmp[64]; char tmp[64];
StrBuf S = AUTO_STRBUF_INITIALIZER; StrBuf S = AUTO_STRBUF_INITIALIZER;
if (Func->WrappedCallData == WRAPPED_CALL_USE_BANK) { if (Expr->Sym->V.F.WrappedCallData == WRAPPED_CALL_USE_BANK) {
/* Store the bank attribute in tmp4 */ /* Store the bank attribute in tmp4 */
SB_AppendStr (&S, "ldy #<.bank(_"); SB_AppendStr (&S, "ldy #<.bank(_");
SB_AppendStr (&S, (const char*) Expr->Name); SB_AppendStr (&S, (const char*) Expr->Name);
SB_AppendChar (&S, ')'); SB_AppendChar (&S, ')');
} else { } else {
/* Store the WrappedCall data in tmp4 */ /* Store the WrappedCall data in tmp4 */
sprintf(tmp, "ldy #%u", Func->WrappedCallData); sprintf(tmp, "ldy #%u", Expr->Sym->V.F.WrappedCallData);
SB_AppendStr (&S, tmp); SB_AppendStr (&S, tmp);
} }
g_asmcode (&S); g_asmcode (&S);
@ -1154,7 +1149,7 @@ static void FunctionCall (ExprDesc* Expr)
SB_Done (&S); SB_Done (&S);
g_call (CG_CallFlags (Expr->Type), Func->WrappedCall->Name, ArgSize); g_call (CG_CallFlags (Expr->Type), Expr->Sym->V.F.WrappedCall->Name, ArgSize);
} else { } else {
g_call (CG_CallFlags (Expr->Type), (const char*) Expr->Name, ArgSize); g_call (CG_CallFlags (Expr->Type), (const char*) Expr->Name, ArgSize);
} }
@ -1328,6 +1323,7 @@ static void Primary (ExprDesc* E)
E->Type = type_int; E->Type = type_int;
} }
E->Sym = Sym;
} }
break; break;

View File

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

View File

@ -70,8 +70,6 @@ struct FuncDesc {
unsigned ParamSize; /* Size of the parameters */ unsigned ParamSize; /* Size of the parameters */
struct SymEntry* LastParam; /* Pointer to last parameter */ struct SymEntry* LastParam; /* Pointer to last parameter */
struct FuncDesc* FuncDef; /* Descriptor used in definition */ struct FuncDesc* FuncDef; /* Descriptor used in definition */
struct SymEntry* WrappedCall; /* Pointer to the WrappedCall */
unsigned int WrappedCallData; /* The WrappedCall's user data */
}; };

View File

@ -159,6 +159,8 @@ struct SymEntry {
struct { struct {
struct SegContext* Seg; /* SegContext for this function */ struct SegContext* Seg; /* SegContext for this function */
struct LiteralPool* LitPool; /* Literal pool for this function */ struct LiteralPool* LitPool; /* Literal pool for this function */
struct SymEntry* WrappedCall; /* Pointer to the WrappedCall */
unsigned int WrappedCallData; /* The WrappedCall's user data */
} F; } F;
/* Label name for static symbols */ /* Label name for static symbols */

View File

@ -61,6 +61,7 @@
#include "symentry.h" #include "symentry.h"
#include "typecmp.h" #include "typecmp.h"
#include "typeconv.h" #include "typeconv.h"
#include "wrappedcall.h"
#include "symtab.h" #include "symtab.h"
@ -1407,24 +1408,30 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
} }
if (Entry == 0) { if (Entry == 0) {
/* Create a new entry */ /* Create a new entry */
Entry = NewSymEntry (Name, Flags); Entry = NewSymEntry (Name, Flags);
/* Set the symbol attributes */ /* Set the symbol attributes */
Entry->Type = TypeDup (T); Entry->Type = TypeDup (T);
/* If this is a function, clear additional fields */
if (IsTypeFunc (T)) {
Entry->V.F.Seg = 0;
}
/* Add the assembler name of the symbol */ /* Add the assembler name of the symbol */
SymSetAsmName (Entry); SymSetAsmName (Entry);
/* Add the entry to the symbol table */ /* Add the entry to the symbol table */
AddSymEntry (Tab, Entry); AddSymEntry (Tab, Entry);
}
/* If this is a function, do we wrap calls to it? */
if (IsTypeFunc (Entry->Type)) {
SymEntry* WrappedCall;
unsigned int WrappedCallData;
/* Always use the latest wrapper data for it */
GetWrappedCall ((void**)&WrappedCall, &WrappedCallData);
if (WrappedCall) {
Entry->V.F.WrappedCall = WrappedCall;
Entry->V.F.WrappedCallData = WrappedCallData;
}
} }
/* Add an alias of the global symbol to the local symbol table */ /* Add an alias of the global symbol to the local symbol table */

View File

@ -22,23 +22,23 @@ void func3() {
} }
#pragma wrapped-call(push, trampoline_inc, 0)
void func2() { void func2() {
func3(); func3();
} }
#pragma wrapped-call(push, trampoline_inc, 0)
void func2(void);
#pragma wrapped-call(push, trampoline_set, 4) #pragma wrapped-call(push, trampoline_set, 4)
void func1(void);
#pragma wrapped-call(pop)
#pragma wrapped-call(pop)
void func1(void) { void func1(void) {
func2(); func2();
} }
#pragma wrapped-call(pop)
#pragma wrapped-call(pop)
int main(void) int main(void)
{ {
flag = 0; flag = 0;