flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Trying to improve my syscall macro

Author
Thread Post new topic Reply to topic
triplefault



Joined: 28 Mar 2012
Posts: 14
triplefault 22 Apr 2017, 00:14
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 sysnum, p1, p2, p3, p4, p5, p6 {
  macro maybe_mov reg, p \{
    if ~ reg eq p & ~ p eq
      mov reg, p
    end if
  \}
  maybe_mov rdi, p1
  maybe_mov rsi, p2
  maybe_mov rdx, p3
  maybe_mov r10, p4
  maybe_mov r8, p5
  maybe_mov r9, p6
  if ~ sysnum eq
    mov rax, sysnum
  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 sysnum, prdi, prsi, prdx, pr10, pr8, pr9 {
  irps reg, rdi rsi rdx r10 r8 r9 \{
    if ~ reg eq p#reg & ~ p#reg eq
      mov reg, p#reg
    end if
  \}
  if ~ sysnum eq
    mov rax, sysnum
  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: 20300
Location: In your JS exploiting you and your system
revolution 22 Apr 2017, 00:20
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
triplefault 22 Apr 2017, 01:33
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 sysnum, prdi, prsi, prdx, pr10, pr8, pr9 {
  irps reg, rdi rsi rdx r10 r8 r9 \{
    if ~ reg eq p\#reg & ~ p\#reg eq
      mov reg, p\#reg
    end if 
  \}
  if ~ sysnum eq
    mov rax, sysnum
  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: 20300
Location: In your JS exploiting you and your system
revolution 22 Apr 2017, 03:10
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
triplefault 22 Apr 2017, 04:46
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
l_inc 22 Apr 2017, 20:36
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 \reg, r9 r8 r10 rdx rsi rdi rax \{ define reg \reg \}
    forward
        if ~arg eq reg
            mov reg, arg
        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
triplefault 23 Apr 2017, 03:57
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


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.