Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • 01:00

    kobalicek on map_jit

    (compare)

  • 00:59

    kobalicek on master

    Added support for MAP_JIT (OSX,… (compare)

  • Jan 25 23:56

    kobalicek on map_jit

    Added support for MAP_JIT (OSX,… (compare)

  • Jan 24 19:50

    kobalicek on map_jit

    Added support for MAP_JIT (OSX,… (compare)

  • Jan 24 19:26

    kobalicek on map_jit

    Added support for MAP_JIT (OSX,… (compare)

  • Jan 24 09:10

    kobalicek on map_jit

    Added support for MAP_JIT (OSX,… (compare)

  • Jan 18 21:34
    kobalicek labeled #194
  • Jan 18 21:33
    kobalicek edited #83
  • Jan 18 08:36
    kobalicek closed #265
  • Jan 18 08:36
    kobalicek closed #262
  • Jan 18 08:35
    kobalicek closed #264
  • Jan 18 05:52
    AntonSazonov closed #271
  • Jan 18 05:52
    AntonSazonov commented #271
  • Jan 17 23:04
    kobalicek labeled #271
  • Jan 17 22:53
    kobalicek commented #271
  • Jan 17 19:53
    kobalicek closed #173
  • Jan 17 19:52
    kobalicek closed #196
  • Jan 17 19:52
    kobalicek closed #247
  • Jan 17 07:07
    dmitry-vlasov closed #272
  • Jan 17 07:02
    dmitry-vlasov opened #272
Petr Kobalicek
@kobalicek
Just a little note: I have updated instruction timings on https://asmjit.com/asmgrid/ - it now includes instruction timings of ZEN 2 architecture, which has many improvements. I have checked Agner's Fog instruction tables and ZEN 2 is not yet covered there, so enjoy if you need such information :)
ahans
@ahans
Hey all, I'm playing with asmjit to implement a JIT for a simple toy language. I've been making nice progress, but now I'm stumbling across indirect jumps. Currently I create a label for each instruction, when I then come across a jmp instruction, I can look up the label in a map (or create a new one on the fly) and add a jmp (or with some condition) instruction, if the jmp instruction contains the target line directly. However, if that target is in some memory location, I don't know how to make the connection between the data in that memory location and the label. One approach I considered was creating a lookup table mapping from internal/abstract addresses (like the ones I would read from that memory location) and actual code addresses. I could then generate code that does the lookup and then jumps to an address as opposed to a label. However, I'm not sure how to do that either, since as far as I understand actual addresses only manifest once I call JitRuntime::add(). Also, I wonder if there's a better approach to this. THanks!
Petr Kobalicek
@kobalicek

I think this is hard to answer as I have no idea about how you implemented the JIT part of the language. In general emitting code where you don't know where it would jump to is hard, but it's not impossible.

Several options include:

  • if you compile the whole source at once then you can generate multiple functions in a single Assembler/Builder/Compiler, in this case each function would just be a label so problem solved.
  • if your compilation process is incremental - you compile something and then something else, but individual functions are added to runtime independently, then this is a bit complicated, because you would have to keep track of all the functions somehow. Simple solution would be having some table or something that you would reference from your code, once you generate the function you just overwrite the entry in the table. In this case you won't have to patch existing code, just the data in the table. Another possibility is to add such table at the end of the generated function and patch it once you know the address.
I think there is really multiple solutions to the problem, the question is which is the most elegant in this case. I think a bit more specific example would help
Wenlong Li
@lwl4613615
I was using this code DEMO when compiling and encountered error LNK2019: Unresolved external symbol "declspec (dllimport) public: thiscall asmjit :: CodeHolder :: CodeHolder (void)" (_imp ?? 0CodeHolder @ asmjit @@ QAE @ XZ), the symbol is referenced in the function _main, how can I solve that?
Petr Kobalicek
@kobalicek
I can only guess - you are missing asmjit in link libraries, or, if you build asmjit statically you didn't define ASMJIT_STATIC macro
Stephen Eckels
@stevemk14ebr
@ahans you can use a lookup table. Emit assembly to load from an address of a variable you know (address of slot in table) and then later you can set the value of that slot. You asm would do two loads then, one that loads the address of the slot, and one that reads the value from the address. I do something similar here: https://github.com/stevemk14ebr/PolyHook_2_0/blob/db55d3c2c2f6440fdf39f59b1adf61e4d94ecc64/sources/ILCallback.cpp#L185
Dmitry Opokin
@Fihtangolz
https://github.com/Fihtangolz/asmjit strating rust reimplementation of asmjit
Petr Kobalicek
@kobalicek
yeah good luck with the reimplementation
I would not try to make everything 1:1 though
Dmitry Opokin
@Fihtangolz
In general, I found a couple of bugs, it’s strange why I didn’t think about sending them to you right away. Well, I did plan to do a diff project review
Stephen Eckels
@stevemk14ebr
you can you explain the consequences of this asmjit/asmjit#83
in particular does this mean the following is invalid:
arg = cc.newXmm();
cc.movq(arg.as<asmjit::x86::Xmm>(), paramMem);
asmjit::FuncCallNode* call = cc.call(asmjit::Imm(m_Target)), sig);
call->setArg(arg_idx, arg.as<asmjit::x86::Xmm>());
Petr Kobalicek
@kobalicek
it only applies to something like this:
void someFunction(__m128i xmmRegArg)
other args, like float/double/etc are all okay and are passed via XMM, you get them as XMM
Stephen Eckels
@stevemk14ebr
cool, and if i wanted to pass that myself, would aligning the stack to 16 bytes before be sufficient? Or is there no work around
pretend my example did want to use the _m128i
Petr Kobalicek
@kobalicek
well the problem is not passing the reg, however, X64 calling convention basically says you have to pass as a reference, so it becomes:
void someFunction(__m128i* xmmRegArg)
which means that instead of passing XMM you pass GP that points to the memory location where the value is stored
this is tricky and this is the thing that is not implemented atm
Stephen Eckels
@stevemk14ebr
ok so steps would be, align stack manually, move xmm to stack, get gp ptr to stack, and pass that as an arg?
Petr Kobalicek
@kobalicek
well I would say, don't pass SIMD registers to generated functions, only pass normal arguments like float/double/int/ptr, everything else is very specific to the calling convention
funny thing is that on Linux this all works
Stephen Eckels
@stevemk14ebr
ok fair enough, thanks for you help it works for the case i actually care about
Petr Kobalicek
@kobalicek
I think it won't take huge effort to fix this, just I have never needed this feature and it's not really common to generate such functions especially as you gain nothing on Windows
Stephen Eckels
@stevemk14ebr
yes i completely agree with you, also if i may suggest adding the snippet you showed me to the issue to make it clear :)
Petr Kobalicek
@kobalicek
yeah I will
makes sense
done
I should eventually fix this, it's the only known bug that I'm aware of
Stephen Eckels
@stevemk14ebr
i look forward to that! Don't need it atm but it will make my project much more powerful!
btw, asmjit is seriously amazing, take a look at what i was able to build with it: https://github.com/stevemk14ebr/JITCall/blob/91baa7f33c0270ed2d4ddacdab3067320da5bb52/JITTests/JITCallTest.cpp#L102
that's a type erased JIT engine, configurable enough it can write call stubs that are not known at compile time
Petr Kobalicek
@kobalicek
Nice, glad it works!
Stephen Eckels
@stevemk14ebr
got a weird sub esp + add esp pair generated after a call, not sure what's up
0A570000  int         3  
0A570001  sub         esp,4  
0A570004  mov         ecx,dword ptr [esp+8]  
0A570008  mov         eax,0  
0A57000D  mov         eax,dword ptr [ecx+eax]  
0A570010  mov         dword ptr [esp],eax  
0A570013  call        exportOneStd (78EC1060h)  
0A570018  sub         esp,4  
0A57001B  add         esp,4  
0A57001E  ret
[RAPass::BuildCFG]
  L0: void Func(u32@[0] %0)
  {#0}
    mov %1, 0
    mov %2, qword [%0+%1]
    mov dword [esp], %2
    call 0x78EC1060
    sub esp, 4
    [FuncRet]
  {#1}
  L1:
    [FuncEnd]
[RAPass::BuildViews]
[RAPass::BuildDominators]
  IDom of #1 -> #0
  Done (2 iterations)
[RAPass::BuildLiveness]
  LiveIn/Out Done (4 visits)
  {#0}
    IN   [%0]
    GEN  [%1, %2, %0]
    KILL [%1, %2]
  {#1}
  %1 {id:0257 width: 2    freq: 1.0000 priority=1.0100}: [3:5]
  %2 {id:0258 width: 2    freq: 1.0000 priority=1.0100}: [5:7]
  %0 {id:0256 width: 3    freq: 0.3333 priority=0.3433}: [2:5]
[RAPass::BinPack] Available=7 (0x000000EF) Count=3
  00: [3:5@257], [5:7@258]
  01: [2:5@256]
  Completed.
[RAPass::Rewrite]
.section .text {#0}
int3                                        ; CC
L0:
sub esp, 4                                  ; 83EC04
mov ecx, dword [esp+8]                      ; 8B4C2408
mov eax, 0                                  ; B800000000              | <00002> mov %1, 0                        | %1{W|Out}
mov eax, qword [ecx+eax]                    ; 8B0401                  | <00004> mov %2, qword [%0+%1]            | %2{W|Out} %0{R|Use|Last|Kill} %1{R|Use|Last|Kill}
mov dword [esp], eax                        ; 890424                  | <00006> mov dword [esp], %2              | %2{R|Use|Last|Kill}
call 0x78EC1060                             ; E800000000              | <00008> call 0x78EC1060
sub esp, 4                                  ; 83EC04                  | <00010> sub esp, 4
L1:                                         ;                         | L1:
add esp, 4                                  ; 83C404
ret
Petr Kobalicek
@kobalicek
it's okay, the compiler prepares the call stack
Stephen Eckels
@stevemk14ebr
it's pointless though no? I can't see why it would decide to do the sub esp, 4 a second time. The add esp right after makes sense because it has to rebalance the stack
Petr Kobalicek
@kobalicek
It's because of STDCALL - which cleans the arguments stack as well
so asmjit just resets the stack offset to the one it had before the call
I think only STDCALL has this "feature", maybe some kinds of FASTCALL as well, if you use CDECL it would not emit that sub
Stephen Eckels
@stevemk14ebr
Oh now I see! Initial sub esp, 4 to get param, do the stdcall, reset stack to before, now it's func end so cleanup stack with add, ret. Not a big at all but maybe an opimization pass could clean that up
Petr Kobalicek
@kobalicek
would be cool to have some cleanup pass that would cleanup these pointles add esp, sub esp
Markus Schmidl
@marenz2569
Hello there, I would like to know if you plan support for any of ARM, POWER9 or RISCV architecture?
Petr Kobalicek
@kobalicek
ARM is definitely planned, POWER not really atm, and RISC-V after ARM
ARM issue: asmjit/asmjit#74
Petr Kobalicek
@kobalicek
Guys anyone knows more about this MAP_JIT recently introduced by OSX Mojave? It seems asmjit should support this flag when allocating virtual memory
Dmitry Opokin
@Fihtangolz
Uhh got tired, I spent a lot of time but I think I rewrote 10% maybe)
Dmitry Opokin
@Fihtangolz
So if anyone know rust and want help reimpl library on it, review pull and etc welcome