flat assembler
Message board for the users of flat assembler.
 Home   FAQ   Search   Register 
 Profile   Log in to check your private messages   Log in 
flat assembler > Macroinstructions > Trying to improve my syscall macro

Author
Thread Post new topic Reply to topic
triplefault



Joined: 28 Mar 2012
Posts: 14

Trying to improve my syscall macro

This is for 64 bit Linux syscalls. I am trying to improve my limited knowledge of fasm macros so I decided to write a macro for invoking syscalls in a similar way to the invoke and cinvoke macros for Windows.

The first version of my macro looks like this:


Code:
macro syscall sysnump1p2p3p4p5p6 {
  macro maybe_mov regp \{
    if ~ reg eq p & ~ p eq
      mov regp
    end if
  \}
  maybe_mov rdip1
  maybe_mov rsip2
  maybe_mov rdxp3
  maybe_mov r10p4
  maybe_mov r8p5
  maybe_mov r9p6
  if ~ sysnum eq
    mov raxsysnum
  end if
  syscall
}



It works but it is long and definitely breaks the DRY principle because I copied, pasted and modified the same line 6 times (the maybe_mov part).

The fasm manual indicates that I can use # to concatenate names (page 4187 of fasm.txt for Linux at the time of writing this) so I thought out I could use irps to loop through registers, rename my parameters from p1-p6 to prdi-pr9 and then concatenate the register name to p to generate the parameter name. It turns out that this doesn't work and gives me an "undefined symbol 'preg'" error message. This is the new code that doesn't work:


Code:
macro syscall sysnumprdiprsiprdxpr10pr8pr9 {
  irps regrdi rsi rdx r10 r8 r9 \{
    if ~ reg eq p#reg & ~ p#reg eq
      mov regp#reg
    end if
  \}
  if ~ sysnum eq
    mov raxsysnum
  end if
  syscall
}



The error is at the 'mov reg, p#reg' line. I spent a few hours of my afternoon trying to figure out an alternative way to do this but nothing else I tried worked. I'm not looking for a solution I can copy and paste, I would like to know what my mistake is and how I can fix it.

_________________
I should save this password in some place I can remember.
Post 22 Apr 2017, 00:14
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15324
Location: Bigweld Industries

The # also has to be escaped with backslashes.

Code:
if ~ reg eq p\#reg & ~ p\#reg eq

Post 22 Apr 2017, 00:20
View user's profile Send private message Visit poster's website Reply with quote
triplefault



Joined: 28 Mar 2012
Posts: 14


revolution wrote:
The # also has to be escaped with backslashes.

Code:
if ~ reg eq p\#reg & ~ p\#reg eq




Thank you, that solves one issue but now I'm getting "undefined symbol 'prdi'" even though it is one of the parameters of my macro.

[Edit] Now that I know that I have to escape more than { and } in a macro within a macro, what other characters besides {, } and # need to be escaped? The manual only mentions { and }. [Edit 2] Ignore my last question, I was not searching the right way, I found the answer here.

I have noticed that the if condition that successfully evaluates to true for only the defined parameters in my original code always evaluates to true even if the parameter is empty in my second attempt (after adding the backslashes to escape the #). Also sorry for editing so many times, I'm trying to find a solution and I update this with my new attempts and questions.

For reference here's the new code with added backslashes:


Code:
macro syscall sysnumprdiprsiprdxpr10pr8pr9 {
  irps regrdi rsi rdx r10 r8 r9 \{
    if ~ reg eq p\#reg & ~ p\#reg eq
      mov regp\#reg
    end if 
  \}
  if ~ sysnum eq
    mov raxsysnum
  end if
  syscall
}


_________________
I should save this password in some place I can remember.
Post 22 Apr 2017, 01:33
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15324
Location: Bigweld Industries

I see that your macro can never work that way. The outer macro replaces all instances of prdi it finds and then processes the inner code. Since the outer macro never finds prdi (it only sees p\#reg) then no parameter replacement happens.


Last edited by revolution on 22 Apr 2017, 04:49; edited 1 time in total
Post 22 Apr 2017, 03:10
View user's profile Send private message Visit poster's website Reply with quote
triplefault



Joined: 28 Mar 2012
Posts: 14

You are right, I was expecting it to process the inner macro first but that would make no sense because it needs to process the outer macro first to realize that there is an inner macro. I'll continue using my first version of the macro that works well. Thank you for your help.
Post 22 Apr 2017, 04:46
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881

triplefault
If you need to enumerate multiple sequences of tokens pairwise, you can put one sequence into a stack of a symbol and then pop from that stack while enumerating tokens from another sequence:

Code:
macro syscall [arg*] {
    common local reg
        irps \regr9 r8 r10 rdx rsi rdi rax \{ define reg \reg \}
    forward
        if ~arg eq reg
            mov regarg
        end if
        restore reg
    common irpv _,reg \{ restore reg \}
        syscall
}


Here reg provides a stack and restore pops from it while the syscall arguments are being enumerated. This macro produces less unnecessary lines and catches more mistakes, but it is still error-prone in case some arguments are already partially in the listed registers. E.g., if the second macro argument is rax, its value will be overwritten by the syscall number before being put into rdi. That can be handled correctly, but the macro would become significantly more complex.

P.S. It is a good idea to avoid overriding existing instructions and directives if not necessary. I.e., msyscall or xsyscall would be better names for the macro.

_________________
Faith is a superposition of knowledge and fallacy
Post 22 Apr 2017, 20:36
View user's profile Send private message Reply with quote
triplefault



Joined: 28 Mar 2012
Posts: 14

l_inc: thank you for the recommendation and the code, I'll avoid overriding existing things in the future. Your solution works and it is what I wanted to do. This was just an exercise to practice writing macros so I don't worry about the potential problem of overwriting a register because in practice I'm more likely to avoid using a macro for this.
Post 23 Apr 2017, 03:57
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >

Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001-2005 phpBB Group.

Main index   Download   Documentation   Examples   Message board
Copyright © 2004-2017, Tomasz Grysztar.