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 <a_samp> // DO NOT REMOVE THIS main() { #emit const.pri foo } stock foo() { printf("Hello, World!"); } ----- end of test code -----
This commit is contained in:
parent
0fa621f5e8
commit
eba8474294
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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(i<sNAMEMAX);
|
||||
name[i]=*s;
|
||||
} /* for */
|
||||
name[i]='\0';
|
||||
sym=findglb(name,sGLOBAL);
|
||||
assert(sym!=NULL);
|
||||
assert(sym->ident==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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user