Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User defined macros #18

Closed
lightclient opened this issue Mar 5, 2021 · 7 comments
Closed

User defined macros #18

lightclient opened this issue Mar 5, 2021 · 7 comments
Assignees
Labels
A-assembler Area: assembler C-enhance Category: a request for an improvement E-hard Experience: difficult, probably not for the faint of heart

Comments

@lightclient
Copy link
Contributor

Seems that we should come up with a template for macros.

@lightclient
Copy link
Contributor Author

NASM multi-line macro format:

%macro  prologue 1 

        push    ebp 
        mov     ebp,esp 
        sub     esp,%1 

%endmacro

@lightclient lightclient added the C-enhance Category: a request for an improvement label Mar 10, 2021
@SamWilsn
Copy link
Contributor

So you define the macro with %macro and %endmacro? Seems reasonable.

Couple follow-up questions:

How does invoking the macro look? Something like:

jumpdest :foo
prologue(55)

How do nested macros work?


What are the scoping rules? Are they file scoped, or globally scoped? What about labels in macros? Something like Rust's macro hygiene or just let them collide?

@lightclient lightclient added the A-assembler Area: assembler label Mar 10, 2021
@lightclient
Copy link
Contributor Author

Yep, that seems like a good way to invoke a macro. A nested macro would need to have been previously defined and we'll expand it. As we discussed on telegram, the arguments must be constants and the developer will need to prepare the stack to call the macro.

@lightclient
Copy link
Contributor Author

Also, named arguments.

@lightclient
Copy link
Contributor Author

final format from @SamWilsn on chat (few changes by me):

%def approve_selector()
    selector("approve(address,uint256)")
%end
%def transfer_selector(): selector("transfer(address,uint256)")

%macro check_selector($sel, $dest)
    dup1
    push4 $sel
    push2 $dest
    jumpi
%end

%check_selector(approve_selector(), .approve)
%check_selector(transfer_selector(), .transfer)

push1 0x00
push1 0x00
revert

@SamWilsn
Copy link
Contributor

SamWilsn commented Apr 25, 2021

To clarify the example a little bit, we want to introduce two new constructs: def and macro.

Macros

Definition

Single- and Multi- Line

Macros can be defined in either single-line or multi-line formats. The two formats are distinguished by a colon following the parenthesis closing the argument list. The single-line and multi-line formats are equivalent.

Single-Line:

%def expression_name(): 0xffffffff

%macro instruction_name(): push1 0xff

Multi-Line:

%def expression_name()
    0xffffffff
%end

%macro instruction_name()
    push1 0xff
%end

Arguments

TODO

Behaviour

Expression Macro

%def creates an expression macro. Expression macros with no arguments may also be called constants.

Expression macros can take the place of an immediate/label, specifically:

  • As the argument to a push instruction.
  • As the argument to an instruction macro.
  • As the argument to an expression macro.

Expression macros cannot take the place of an opcode.

An expression macro can accept zero or more arguments, but only:

  • Literals (currently integers)
  • Labels
  • Other expression macros

If a multi-line expression macro has two lines which produce a return value, the assembler should emit an error. A multi-line expression macro with two return values could look like:

%def two_integers()
    1
    2
%end

%def two_macros()
    selector("hi()")
    selector("bye()")
%end

Instruction Macro

%macro creates an instruction macro.

Instruction macros can take the place of zero or more opcodes, and cannot be used as the argument to push instructions.

An instruction macro can accept zero or more arguments, but only:

  • Literals (currently integers)
  • Labels
  • Expression macros

A single-line style instruction macro can only expand to a single instruction.

Hygiene

Labels defined in a macro (ie. jumpdest .foo) are only visible inside of the replacement opcodes, they do not conflict with other labels and cannot be referred to outside of the replacement opcodes. References to labels inside of a macro should first resolve to labels defined within the replacement, and if no match is found, to the global namespace. For example:

%macro foo()
    jumpdest .a
    push1 .a
%end

%foo()
%foo()

; Should compile to `0x5b60005b6003`
%macro foo()
    push1 .a
%end

%foo()
jumpdest .a

; Should compile to `0x60025b`
%macro foo()
    jumpdest .a
    push1 .a
%end

jumpdest .a
%foo()
push1 .a

; Should compile to `0x5b5b60016000`
%macro foo()
    push1 .a
%end

%foo()

; Should not compile
%macro foo()
    jumpdest .a
%end

%foo()
push1 .a

; Should not compile

Usage

Instruction macros must be prefixed with a percent sign (%), while expression macros are unadorned.

Expression Macro

push5 some_expression()

Instruction Macro

%some_instruction()

@SamWilsn SamWilsn changed the title Macro template User defined macros Apr 29, 2021
@lightclient lightclient self-assigned this Jul 11, 2021
@lightclient lightclient added the E-hard Experience: difficult, probably not for the faint of heart label Jul 11, 2021
@lightclient
Copy link
Contributor Author

I think this is done now!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-assembler Area: assembler C-enhance Category: a request for an improvement E-hard Experience: difficult, probably not for the faint of heart
Projects
None yet
Development

No branches or pull requests

2 participants