From eba8474294c1c106dd6e4f62a73160798f16458d Mon Sep 17 00:00:00 2001 From: Zeex Date: Fri, 3 Jan 2014 07:59:25 +0700 Subject: [PATCH] Fix generation of function addresses in #emit code This fixes a bug where the compiler generated incorrect addresses for functions in #emit code if they were defined after the point of use. For example, you couldn't reliably get the address of a function with "#emit CONST.pri XXX" unless you make sure that XXX is defined before the function in which you have you are referencing it. Now the resolution of the function's address is deferred until assembling phase (as with CALL), and the assembler is guaranteed to see all symbols with their final addresses. To distinguish between functions and numeric operands I added a '.' (period) in front of function names for both #emit and normal calls. See also 5) here: http://forum.sa-mp.com/showthread.php?t=355877 --------- test code -------- #include // DO NOT REMOVE THIS main() { #emit const.pri foo } stock foo() { printf("Hello, World!"); } ----- end of test code ----- --- source/compiler/sc2.c | 21 ++++++++++++--------- source/compiler/sc4.c | 1 + source/compiler/sc6.c | 34 +++++++++++++++++++++++++++------- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/source/compiler/sc2.c b/source/compiler/sc2.c index b79d8fad..44a36dfa 100644 --- a/source/compiler/sc2.c +++ b/source/compiler/sc2.c @@ -1220,16 +1220,19 @@ static int command(void) if (sym==NULL || sym->ident!=iFUNCTN && sym->ident!=iREFFUNC && (sym->usage & uDEFINE)==0) { error(17,str); /* undefined symbol */ } else { - if (strcmp(name, "call")==0) { - assert((sym->ident & iFUNCTN)!=0 || (sym->ident & iREFFUNC)!=0); - stgwrite(sym->name); + if (sym->ident==iFUNCTN || sym->ident==iREFFUNC) { + if ((sym->usage & uNATIVE)!=0) { + /* reserve a SYSREQ id if called for the first time */ + sym->addr=ntv_funcid++; + outval(sym->addr,FALSE); + } else { + /* normal function, write its name instead of the address + * so that the address will be resolved at assemble time + */ + stgwrite("."); + stgwrite(sym->name); + } /* if */ } else { - if ((sym->ident & iFUNCTN)!=0 && (sym->usage & uNATIVE)!=0) { - if (sc_status==statWRITE && (sym->usage & uREAD)==0 && sym->addr>=0) { - /* reserve a SYSREQ id if called for the first time */ - sym->addr=ntv_funcid++; - } /* if */ - } outval(sym->addr,FALSE); } /* if */ /* mark symbol as "used", unknown whether for read or write */ diff --git a/source/compiler/sc4.c b/source/compiler/sc4.c index 4135225e..f982b586 100644 --- a/source/compiler/sc4.c +++ b/source/compiler/sc4.c @@ -744,6 +744,7 @@ SC_FUNC void ffcall(symbol *sym,const char *label,int numargs) stgwrite("l."); stgwrite(label); } else { + stgwrite("."); stgwrite(sym->name); } /* if */ if (sc_asmfile diff --git a/source/compiler/sc6.c b/source/compiler/sc6.c index 1935d81d..795c8f0a 100644 --- a/source/compiler/sc6.c +++ b/source/compiler/sc6.c @@ -95,13 +95,32 @@ static ucell hex2long(const char *s,char **n) static ucell getparam(const char *s,char **n) { + int i; ucell result=0; - for ( ;; ) { - result+=hex2long(s,(char**)&s); - if (*s!='+') - break; - s++; - } /* for */ + char name[sNAMEMAX+1]; + symbol *sym; + + if (*s=='.') { + /* this is a function, find it in the global symbol table */ + for (i=0; !isspace(*(++s)); i++) { + assert(*s!='\0'); + assert(iident==iFUNCTN || sym->ident==iREFFUNC); + assert(sym->vclass==sGLOBAL); + result=sym->addr; + } else { + for ( ;; ) { + result+=hex2long(s,(char**)&s); + if (*s!='+') + break; + s++; + } /* for */ + } /* if */ if (n!=NULL) *n=(char*)s; return result; @@ -385,7 +404,8 @@ static cell do_call(FILE *fbin,char *params,cell opcode) /* look up the function address; note that the correct file number must * already have been set (in order for static globals to be found). */ - sym=findglb(name,sGLOBAL); + assert(name[0]=='.'); + sym=findglb(name+1,sGLOBAL); assert(sym!=NULL); assert(sym->ident==iFUNCTN || sym->ident==iREFFUNC); assert(sym->vclass==sGLOBAL);