Jump Tables in 6a

454 views
Skip to first unread message

distributed

unread,
Mar 18, 2013, 4:37:52 PM3/18/13
to golan...@googlegroups.com
Dear Gophers

I'm trying to use jump tables in 6a assembler files. Say I have a function like this:

TEXT ·asmfunc(SB),7,$0
MOVQ $42, AX

// TODO: find jump target, move it to BX
// TODO: jump to address specified in BX

lab1:
MOVQ $43, AX
JMP funcend

lab2:
MOVQ $44, AX
JMP funcend

funcend:
MOVQ AX, r+0(FP)
RET

with the corresponding

func asmfunc() uint64

I want to put the addresses of the labels lab1, lab2 into a table so that I can dispatch to one of them at the beginning of asmfunc. Unfortunately I can't for the life of me figure out how to fill such a table with 6l. I fail at the first step: taking the address of a label. Reading "A Manual for the Plan 9 Assembler" I suspected it to be "$lab1<>+0(SB)", however using this expression like in "MOVQ $lab1<>+0(SB), AX" I wind up with 6a telling me "syntax error, last name: lab1".

Is what I try to achieve possible in 6a? What am I missing? ;)


Cheers,
distributed

ron minnich

unread,
Mar 18, 2013, 4:41:28 PM3/18/13
to distributed, golan...@googlegroups.com
anytime I need to do this sort of thing (and all us plan 9 guys have,
over the years, with this toolchain) I write it in C, compile it, and
see what I get. If I care I can optimize from there. But if you start
with C, you get a lot of the bookkeeping bits right.

So write it with a table of void *, and cast them to functions, and
call them, and just in general lay the C out the way you want assembly
to look, and it will make it easier. It has for me anyway.

ron

minux

unread,
Mar 18, 2013, 4:45:11 PM3/18/13
to distributed, golan...@googlegroups.com
i believe it's impossible to get the address of a label in plan 9 assembler (the
object file simply doesn't allow that).

however, you could define new function for each of your label as an approximate.

TEXT ·asmfunc(SB),7,$0
MOVQ $42, AX

// TODO: find jump target, move it to BX
// TODO: jump to address specified in BX

TEXT lab1<>(SB),7,$0
MOVQ $43, AX
JMP funcend<>(SB)

TEXT lab2<>(SB),7,$0
MOVQ $44, AX
JMP funcend<>(SB)

TEXT funcend<>(SB),7,$0
// blah blah

DATA jumptable<>+0(SB)/8,$lab1<>(SB)
DATA jumptable<>+8(SB)/8,$lab2<>(SB)

distributed

unread,
Mar 18, 2013, 5:45:34 PM3/18/13
to golan...@googlegroups.com, distributed
This is a very useful suggestion. I will investigate the code that 6c generates for a corresponding C program.

Just to be clear, it's not like I absolutely need the performance ;) I was just curious about how expensive certain parts of my interpreting 6502 instruction set simulator are, and I was especially interested about the dispatcher :)

distributed

unread,
Mar 18, 2013, 5:51:00 PM3/18/13
to golan...@googlegroups.com, distributed
I started to fear that this is not possible ;)

I tried the code you suggested, minux. The package go builds fine. However, I cannot build programs importing the package containing asmfunc, go build fails with "jumptable(51): not defined". I have no idea why the link step fails or what the 51 means.


Russ Cox

unread,
Mar 18, 2013, 5:51:27 PM3/18/13
to distributed, golang-nuts
jump tables are not possible in the current object file format.

distributed

unread,
Mar 18, 2013, 6:28:28 PM3/18/13
to golan...@googlegroups.com, distributed
Thanks for the confirmation. Out of curiosity, what about the current object file format prevents jump tables, missing relocation entries?

Russ Cox

unread,
Mar 18, 2013, 11:54:02 PM3/18/13
to distributed, golang-nuts
There is no way to emit a data reference to a specific instruction within a function.

Michael Jones

unread,
Mar 19, 2013, 12:00:52 AM3/19/13
to Russ Cox, distributed, golang-nuts
But you can easily have function dispatch tables. It costs you a call and a return, but the "dispatch" is an indexed load and very fast. My code does this.

For example:

func CountAndFrequencyForLength(base, length int) (count int, counts []int) {
if base < 1 || length < 1 || length >= len(dispatchCFFL) {
return simple.CountAndFrequencyForLength(base, length)
}
return dispatchCFFL[length](base)
}

// everything below this is autogenerated by the makefile

var dispatchCFFL = []func(int) (int, []int){
nil,
countAndFrequencyForLength1,
countAndFrequencyForLength2,
countAndFrequencyForLength3,
countAndFrequencyForLength4,
countAndFrequencyForLength5,
countAndFrequencyForLength6,
countAndFrequencyForLength7,
countAndFrequencyForLength8,
countAndFrequencyForLength9,
countAndFrequencyForLength10,
countAndFrequencyForLength11,
countAndFrequencyForLength12,
countAndFrequencyForLength13,
countAndFrequencyForLength14,
countAndFrequencyForLength15,
countAndFrequencyForLength16,
countAndFrequencyForLength17,
countAndFrequencyForLength18,
countAndFrequencyForLength19,
countAndFrequencyForLength20,
countAndFrequencyForLength21,
countAndFrequencyForLength22,
countAndFrequencyForLength23,
countAndFrequencyForLength24,
countAndFrequencyForLength25,
countAndFrequencyForLength26,
countAndFrequencyForLength27,
countAndFrequencyForLength28,
countAndFrequencyForLength29,
countAndFrequencyForLength30,
countAndFrequencyForLength31,
countAndFrequencyForLength32,
}

func countAndFrequencyForLength1(base int) (int, []int) {
:
return c, f
}

func countAndFrequencyForLength2(base int) (int, []int) {
:
return c, f
}

func countAndFrequencyForLength3(base int) (int, []int) {
:
return c, f
}



On Mon, Mar 18, 2013 at 8:54 PM, Russ Cox <r...@golang.org> wrote:
There is no way to emit a data reference to a specific instruction within a function.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Michael T. Jones | Chief Technology Advocate  | m...@google.com |  +1 650-335-5765

distributed

unread,
Mar 19, 2013, 3:59:03 AM3/19/13
to golan...@googlegroups.com, Russ Cox, distributed
Thanks for the clarification.

Michael, this is the implementation that I wanted to pitch the "naked" jump table against, except that I have no autogenerated parts. In my instruction set simulator I've got something like

opdec := s6502tab[I]
if opdec.Handler != nil {
opdec.Handler(s, opdec.AddMode, I)
return
}

 with s being the CPU state.

Michael Jones

unread,
Mar 19, 2013, 9:50:26 AM3/19/13
to distributed, golang-nuts, Russ Cox
Looks good.

"Labes as Values" is one of the great (i.e., helps me) extensions of GCC over K&R/ANSI C/C++ and is about doing just what you want. Behold:

Labels as Values
================

   You can get the address of a label defined in the current function
(or a containing function) with the unary operator `&&'.  The value has
type `void *'.  This value is a constant and can be used wherever a
constant of that type is valid.  For example:

     void *ptr;
     ...
     ptr = &&foo;

   To use these values, you need to be able to jump to one.  This is
done with the computed goto statement(1), `goto *EXP;'.  For example,

     goto *ptr;

Any expression of type `void *' is allowed.

   One way of using these constants is in initializing a static array
that will serve as a jump table:

     static void *array[] = { &&foo, &&bar, &&hack };

   Then you can select a label with indexing, like this:

     goto *array[i];

Note that this does not check whether the subscript is in bounds--array
indexing in C never does that.

   Such an array of label values serves a purpose much like that of the
`switch' statement.  The `switch' statement is cleaner, so use that
rather than an array unless the problem does not fit a `switch'
statement very well.

   Another use of label values is in an interpreter for threaded code.
The labels within the interpreter function can be stored in the
threaded code for super-fast dispatching.

   You may not use this mechanism to jump to code in a different
function.  If you do that, totally unpredictable things will happen.
The best way to avoid this is to store the label address only in
automatic variables and never pass it as an argument.

   An alternate way to write the above example is

     static const int array[] = { &&foo - &&foo, &&bar - &&foo,
                                  &&hack - &&foo };
     goto *(&&foo + array[i]);

This is more friendly to code living in shared libraries, as it reduces
the number of dynamic relocations that are needed, and by consequence,
allows the data to be read-only.

   ---------- Footnotes ----------

   (1) The analogous feature in Fortran is called an assigned goto, but
that name seems inappropriate in C, where one can do more than simply
store label addresses in label variables.

This is EXTREMELY valuable. Good for 10-15% speedup.

Michael



--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Lucio

unread,
Mar 19, 2013, 11:55:28 AM3/19/13
to golan...@googlegroups.com, distributed, Russ Cox
So why did they have to add an operator (&&), what stopped them from merely using "&"?  Seems gratuitous to me.

Oops, off-topic!

Lucio.
Reply all
Reply to author
Forward
0 new messages