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.
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
<tt/__fastcall__/ functions that have parameters. It must preserve
the <tt/Y/ register if it wraps any variadic functions (they have "<tt/.../"
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
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
@ -1629,6 +1629,11 @@ parameter with the <tt/#pragma/.
The address of a wrapped function is passed in <tt/ptr4/. The wrapper can
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
automatically to where a wrapped function resides, and then to restore the
previous bank when it returns.

View File

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

View File

@ -1057,11 +1057,6 @@ 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.
*/
@ -1110,18 +1105,18 @@ static void FunctionCall (ExprDesc* Expr)
} else {
/* Normal function */
if (Func->WrappedCall) {
if (Expr->Sym && Expr->Sym->V.F.WrappedCall) {
char tmp[64];
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 */
SB_AppendStr (&S, "ldy #<.bank(_");
SB_AppendStr (&S, (const char*) Expr->Name);
SB_AppendChar (&S, ')');
} else {
/* 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);
}
g_asmcode (&S);
@ -1154,7 +1149,7 @@ static void FunctionCall (ExprDesc* Expr)
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 {
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->Sym = Sym;
}
break;

View File

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

View File

@ -70,8 +70,6 @@ struct FuncDesc {
unsigned ParamSize; /* Size of the parameters */
struct SymEntry* LastParam; /* Pointer to last parameter */
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 SegContext* Seg; /* SegContext 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;
/* Label name for static symbols */

View File

@ -61,6 +61,7 @@
#include "symentry.h"
#include "typecmp.h"
#include "typeconv.h"
#include "wrappedcall.h"
#include "symtab.h"
@ -1407,24 +1408,30 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
}
if (Entry == 0) {
/* Create a new entry */
Entry = NewSymEntry (Name, Flags);
/* Set the symbol attributes */
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 */
SymSetAsmName (Entry);
/* Add the entry to the symbol table */
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 */

View File

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