Skip to content

Commit d3cadbe

Browse files
committed
make @@@ for functions return the address of the first instruction
1 parent 53c11d4 commit d3cadbe

21 files changed

+1179
-1070
lines changed

Changelog.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
Version 7.4.1
2+
- Made `@@@func` return the address of the first instruction of the
3+
function func, in both Spin2 and C.
24
- Fixed an internal error computing offsets in structures stored in registers
35

46
Version 7.4.0

backends/asm/inlineasm.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ extern void ValidateObjbase(void);
4848
extern Operand *objbase;
4949
extern void ValidateHeapptr(void);
5050
extern Operand *heapptr;
51+
extern void ValidateMethodTable(void);
52+
extern Operand *method_table_base;
53+
5154
extern Operand *resultreg[];
5255
extern Operand *arg1, *arg2;
5356

@@ -136,6 +139,11 @@ CompileInlineOperand(IRList *irl, AST *expr, int *effects, int immflag)
136139
r = frameptr;
137140
r_address = immflag;
138141
}
142+
else if (!strcmp(name, "__methods__")) {
143+
ValidateMethodTable();
144+
r = method_table_base;
145+
r_address = immflag;
146+
}
139147
else if (!strcmp(name, "__heap_ptr")) {
140148
ValidateHeapptr();
141149
r = heapptr;

backends/asm/outasm.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ static Operand *stacktop; // indirect reference through stackptr
8989
Operand *frameptr;
9090
static Operand *linkreg;
9191

92-
static Operand *method_table_base;
93-
static Operand *method_table_label;
92+
Operand *method_table_base;
93+
Operand *method_table_label;
9494

9595
Operand *heapptr;
9696
static Operand *heaplabel;
@@ -294,7 +294,7 @@ PutVarOnStack(Function *func, Symbol *sym, int size)
294294
return false;
295295
}
296296

297-
static void ValidateMethodTable()
297+
void ValidateMethodTable()
298298
{
299299
if (!method_table_base) {
300300
method_table_label = NewOperand(IMM_HUB_LABEL, "__methodtable__", 0);

backends/becommon.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@
3434
#include "becommon.h"
3535

3636
static AST *make_methodptr;
37+
static AST *get_rawfuncaddr;
3738

3839
AST *
39-
BuildMethodPointer(AST *ast)
40+
BuildMethodPointer(AST *ast, bool is_abs)
4041
{
4142
Symbol *sym;
4243
AST *objast;
@@ -78,9 +79,16 @@ BuildMethodPointer(AST *ast)
7879
if (!make_methodptr) {
7980
make_methodptr = AstIdentifier("_make_methodptr");
8081
}
82+
if (!get_rawfuncaddr) {
83+
get_rawfuncaddr = AstIdentifier("_get_rawfuncaddr");
84+
}
8185
call = NewAST(AST_EXPRLIST, funcaddr, NULL);
8286
call = NewAST(AST_EXPRLIST, objast, call);
83-
result = NewAST(AST_FUNCCALL, make_methodptr, call);
87+
if (is_abs) {
88+
result = NewAST(AST_FUNCCALL, get_rawfuncaddr, call);
89+
} else {
90+
result = NewAST(AST_FUNCCALL, make_methodptr, call);
91+
}
8492
// cast the result to the correct function pointer type
8593
result = NewAST(AST_CAST, funcptrtype, result);
8694
return result;

backends/becommon.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#include "symbol.h"
66
#include "expr.h"
77

8-
AST *BuildMethodPointer(AST *ast);
8+
AST *BuildMethodPointer(AST *ast, bool is_abs);
99
void OutputAlignLong(Flexbuf *fb);
1010
void OutputDataBlob(Flexbuf *fb, Flexbuf *databuf, Flexbuf *relocbuf, const char *startLabel, bool emitLabel);
1111

doc/c.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,10 @@ switch (x) {
330330
}
331331
```
332332

333+
### Absolute address of functions
334+
335+
As discussed in the general documentation, function pointers are complicated objects which are not necessarily the address of the first instruction of the function. In the rare cases where some inline assembly requires access to this information, use the absolute address operator (`@@@`, as in Spin2) to obtain it; that is, `@@@foo` is the address of the first instruction of `foo`. Note that trying to call this directly may produce undefined behavior if the function accesses any member variables, including global variables. See the discussion in the general (language independent) documentation for more details.
336+
333337
### Statement expressions
334338

335339
A compound statement enclosed in parentheses may appear as an expression. This is a GCC extension which allows loops, switches, and similar features to appear within an expression.

doc/general.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ Some inline assembly blocks may also be marked to be copied to fcache before exe
173173

174174
Loops will be placed in fcache only if (a) they will fit, and (b) they contain no branches to outside the loop (including subroutine calls). The size of the fcache may be set by the `--fcache` flag, but is generally 256 longs on P2 and 32 longs on P1.
175175

176+
### Pointers to functions
177+
178+
All functions are internally represented as object methods; this is true even of top level C and BASIC functions. In order to call a method, both the function address and the address of the object's data are required. This means that method pointers must somehow encode both of these. Different compiler targets do this in different ways, so it does mean that, in general, an expression like `@foo` is *not* the address of the function `foo` in memory. For example, in the default P2 assembly backend a method pointer is 32 bits, with the top 12 bits being an index into the global method table and the bottom 20 being the address of the object data.
179+
180+
This should usually be transparent to the programmer, but in some cases (e.g. for interacting with assembly language) it may be desireable to obtain the address of the function directly. This may be done with the absolute address operator, that is, `@@@foo` will be the location in memory of the first instruction of function `foo`.
181+
182+
Note that calling `@@@foo` directly will produce undefined results if `foo` accesses any member specific data, either directly or indirectly. So getting the absolute address of a function is *not* something you would normally want to do!
183+
176184
## Interrupt Service Routines
177185

178186
The code generated by FlexSpin is *not* interrupt safe, so it is not possible to run interrupt service routines (ISRs) in the same COG as compiled code. ISRs may, of course, run in COGs that contain only PASM code launched by `coginit`.

doc/spin.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,14 @@ The `:2` indicates that fptr is a pointer to a function which returns 2 results.
477477
478478
It is the programmer's responsibility to make sure that the number of results and arguments passed to a method called via a pointer are correct. No type checking is done.
479479
480+
#### Internal representation
481+
482+
In order to call a method, both the function address and the address of the object's data are required. This means that method pointers must somehow encode both of these. Different compiler targets do this in different ways, so it does mean that, in general, an expression like `@foo` is *not* the address of the function `foo` in memory.
483+
484+
This should usually be transparent to the programmer, but in some cases (e.g. for interacting with assembly language) it may be desireable to obtain the address of the function directly. This may be done with the absolute address operator, that is, `@@@foo` will be the location in memory of the first instruction of function `foo`.
485+
486+
Note that calling `foo` directly (e.g. with `CALL(foo)`) will produce undefined results if `foo` accesses any member specific data, either directly or indirectly. So getting the absolute address of a function is *not* something you would normally want to do!
487+
480488
### Multiple return values and assignments
481489
482490
flexspin allows multiple return values and assignments. For example, to swap two variables `a` and `b` you can write:

frontends/basic/basic.y

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ AdjustParamForByVal(AST *param)
531531
%token BAS_NE "<>"
532532
%token BAS_SHL "shl"
533533
%token BAS_SHR "shr"
534+
%token BAS_ABSADDR "@@@"
534535

535536
%token BAS_ADD_ASSIGN "+="
536537
%token BAS_SUB_ASSIGN "-="
@@ -550,7 +551,7 @@ AdjustParamForByVal(AST *param)
550551
%left '*' '/' BAS_MOD
551552
%left BAS_SHL BAS_SHR
552553
%left BAS_NOT
553-
%left '@'
554+
%left '@' BAS_ABSADDR
554555
%left BAS_NEW
555556
%left '.'
556557
%left '('
@@ -1693,6 +1694,8 @@ pseudofunc_expr:
16931694
}
16941695
| '@' unary_expr
16951696
{ $$ = NewAST(AST_ADDROF, $2, NULL); }
1697+
| BAS_ABSADDR unary_expr
1698+
{ $$ = NewAST(AST_ABSADDROF, $2, NULL); }
16961699
;
16971700

16981701
unary_expr:

frontends/c/cgram.y

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,7 @@ ConstructDefaultValue(AST *decl, AST *val)
10281028

10291029
%token C_LIMITMIN_OP "#<"
10301030
%token C_LIMITMAX_OP "#>"
1031+
%token C_ABSADDR_OP "@@@"
10311032

10321033
%token C_TYPEDEF "typedef"
10331034
%token C_EXTERN "extern"
@@ -1395,7 +1396,9 @@ unary_expression
13951396
| unary_operator cast_expression
13961397
{
13971398
$$ = $1;
1398-
if ($$->kind == AST_ADDROF || $$->kind == AST_ARRAYREF)
1399+
if ($$->kind == AST_ADDROF ||
1400+
$$->kind == AST_ABSADDROF ||
1401+
$$->kind == AST_ARRAYREF)
13991402
$$->left = $2;
14001403
else
14011404
$$->right = $2;
@@ -1411,6 +1414,8 @@ unary_operator
14111414
{ $$ = NewAST(AST_ADDROF, NULL, NULL); }
14121415
| '@'
14131416
{ $$ = NewAST(AST_ADDROF, NULL, NULL); }
1417+
| C_ABSADDR_OP
1418+
{ $$ = NewAST(AST_ABSADDROF, NULL, NULL); }
14141419
| '*'
14151420
{ $$ = NewAST(AST_ARRAYREF, NULL, AstInteger(0)); }
14161421
| '+'

0 commit comments

Comments
 (0)