Multiple functions and mutually recursive functions

23 views
Skip to first unread message

Rahul Garg

unread,
Aug 9, 2014, 5:06:06 PM8/9/14
to asmji...@googlegroups.com
Hi.

Thanks for the asmjit library, it is very well written. However, I have hit upon a wall, which I am sure has a solution but which I am unable to locate in documentation.
I am using the latest version from github. I have two related questions:

1.  How can create 2 functions using the same compiler instance? I saw some references to setCurrentEmmitable but does not seem to exist?
2.  Expanding on the previous question, how does one create two mutually recursive functions? Eg: function A calls B and function B calls A?

thanks,
Rahul

Rahul Garg

unread,
Aug 11, 2014, 7:40:49 PM8/11/14
to asmji...@googlegroups.com
To add more details,

1. I am using the compiler API and not the assembler API
2. I need pointer to both the functions after compilation, while make() returns pointer to a single function afaik.

Any help here will be appreciated.

thanks :)
rahul

Petr Kobalíček

unread,
Aug 12, 2014, 3:31:30 PM8/12/14
to asmjit-dev
Hi Rahul,

I will try to explain how to do.


1. How can create 2 functions using the same compiler instance?

This is actually easy and supported. The only requirement is to keep the instances returned by `addFunc()`.

Example:
X86Compiler c(...);

// Variables to keep the function nodes.
X86FuncNode* funcA;
X86FuncNode* funcB;

// ------- Function A -------.
funcA = c.addFunc(kFuncConvHost, FuncBuilder0<Void>());
...
c.endFunc();

// ------- Function B -------.
funcB = c.addFunc(kFuncConvHost, FuncBuilder0<Void>());
...
c.endFunc();

// This will make both.
void* p = c.make();

Problem here is how you will get the pointer to the second function. I will explain below.


2. I saw some references to setCurrentEmmitable but does not seem to exist?

It does, the function is called `setCursor()`, but it doesn't do what you want. The setCursor is for injecting code and it basically sets the current node so the next emitted node is added after it (you can use this technique to put some variable to be initialized at the beginning of the function for example).


3. Expanding on the previous question, how does one create two mutually recursive functions? Eg: function A calls B and function B calls A?

Okay, more complicated, more ways how it can be done, but possible and supported.

Let's extend the first example, but instead of using addFunc() we can use newFunc(). This method creates a new function node, but won't add it to the compiler.

Each function always has two labels - Entry and Exit. You can use entry label to reference the function that you didn't yet generate by function that you are just generating. See the example:

X86FuncNode* funcA = c.newFunc(kFuncConvHost, FuncBuilder0<Void>());
X86FuncNode* funcB = c.newFunc(kFuncConvHost, FuncBuilder0<Void>());

// ------- Function A -------.
c.addNode(funcA);

// You can call func A or func B simply by:
c.call(funcA->getEntryLabel());
c.call(funcB->getEntryLabel());
...
c.endFunc();

// ------- Function B -------.
c.addNode(funcB);

// You can call func A or func B simply by (the same...):
c.call(funcA->getEntryLabel());
c.call(funcB->getEntryLabel());
...
c.endFunc();

...

c.make();


4. I need pointer to both the functions after compilation, while make() returns pointer to a single function afaik.

I think I have to work on this one as it's possible to get the pointer, but it's not straightforward as it should be. Basically the Compiler itself doesn't have such functionality yet, but it's easy to get the pointer from the assembler. As Compiler is basically a high-level interface that serializes to assembler, you can create X86Assembler instance and serialize the compiler content to it.

JitRuntime runtime;
X86Compiler c(&runtime);

// Instead of calling c.make(), do the following:
X86Assembler a(c.getRuntime());

// Serialize to assembler.
c.serialize(a);

// This will allocate a virtual memory and relocate to it.
void* p = a.make();

// To get any function, you will have to use labels again, as assembler
// always stores the offset of bound labels, the pointer can be easily
// calculated:
void* pFuncB = (void*)( (uint8_t*)p + a.getLabelData(funcB->getEntryLabel() );

Also when calling `c.make()` or `a.make()` the virtual memory allocated is for the whole code, so it can only be released by a single call to `runtime.release(ptr)`.



PS: Thanks for the questions, I will put this to tests so it's tested. I just wrote it how it should work, but didn't test now. If you face any problems please let me know.

Cheers,
Petr

--

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

Petr Kobalíček

unread,
Aug 12, 2014, 4:09:46 PM8/12/14
to asmjit-dev
I added ticket for getting the offset easier:

Rahul Garg

unread,
Aug 13, 2014, 12:36:10 AM8/13/14
to asmji...@googlegroups.com
Thanks a lot for the answers! I will try the suggested solutions and will keep an eye on the ticket.
Once again, thanks for the great work on the library.

rahul

Petr Kobalíček

unread,
Aug 13, 2014, 3:01:02 AM8/13/14
to asmjit-dev
You are welcome!

I did a small mistake in my last snippet, it should have been:

void* pFuncB = (void*)(
  (uint8_t*)p + a.getLabelData(funcB->getEntryLabel())->offset );
 
Cheers
Petr
Reply all
Reply to author
Forward
0 new messages