Git Product home page Git Product logo

asmjit's Introduction

AsmJit

AsmJit is a lightweight library for machine code generation written in C++ language.

See asmjit.com page for more details, examples, and documentation.

Documentation

Contributing

Breaking Changes

Breaking the API is sometimes inevitable, what to do?

Project Organization

  • / - Project root
    • src - Source code
      • asmjit - Source code and headers (always point include path in here)
        • core - Core API, backend independent except relocations
        • arm - ARM specific API, used only by ARM and AArch64 backends
        • x86 - X86 specific API, used only by X86 and X64 backends
    • test - Unit and integration tests (don't embed in your project)
    • tools - Tools used for configuring, documenting, and generating files

Ports

  • 32-bit ARM/Thumb port (work in progress)
  • RISC-V port (not in progress, help welcome)

Support

Notable Donors List:

Authors & Maintainers

asmjit's People

Contributors

aegistudio avatar alexjbest avatar bnoordhuis avatar chlumsky avatar devnexen avatar fthielke avatar godcodehunter avatar helios-vmg avatar higuoxing avatar ivanov avatar kirbyfan64 avatar kobalicek avatar krig avatar michaelrfairhurst avatar orvid avatar pmeerw avatar ppaulweber avatar samuelpordeus avatar smcallis avatar svost avatar tetzank avatar uvxwx avatar vogelsgesang avatar vvalter avatar wjakob avatar wjk avatar xantares avatar zeewanderer avatar zeex avatar zehmatt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

asmjit's Issues

*** ERROR: No virtual memory (2).

It often throws this error, but very little amount of code is generated. Also it throws assert in debug mode:

x86assembler.cpp: line 1935
ASMJIT_ASSERT(o0->getSize() == 1);

fstsw and fnstsw generate wrong opcode

When using the fstsw ax and fntstsw ax instructions asmjit outputs only part of their opcode. E.g. for fnstsw ax instead of DF E0 it generates E0, which is loopne.

I used this program to reproduce the bug:

#include <asmjit/asmjit.h>

using namespace asmjit;
using namespace asmjit::x86;

int main() {
  JitRuntime runtime;
  X86Assembler a(&runtime);

  a.fnstsw(ax);
  void *code = a.make();

  runtime.release(code);
}

"cmp al, 0" causes problems

I got problems with the Assembler class trying to assemble a code jit with "cmp al, 0" in it. It screws up the resulting opcodes.
Can anyone check it and solve it if I'm not wrong?
Thank you for fixing the problem and creating asmjit
Jeoni

AVX codegen

I'm having problem using AVX instructions. When I try to make a simple program that just adds two vectors together using AVX instructions I get the incorrect result.

When I add in a breakpoint using a.db(0xCC) and use GDB to disassemble the machine code around the PC it looks like the code has not been generated properly.

Here is a gist with the program https://gist.github.com/henrygouk/44120a19d2ab3f51b010

And here is what I have gotten out of GDB:

(gdb) disassemble $pc-17,+18
Dump of assembler code from 0x7ffff7fe8000 to 0x7ffff7fe8012:
   0x00007ffff7fe8000:  vmovups (%rsi),%ymm0
   0x00007ffff7fe8004:  vmovups (%rdx),%ymm1
   0x00007ffff7fe8008:  vaddps %ymm1,%ymm1,%ymm0
   0x00007ffff7fe800c:  vmovups %xmm0,(%rdi)
   0x00007ffff7fe8010:  int3   
=> 0x00007ffff7fe8011:  retq   
End of assembler dump.

the vaddps instruction has the wrong operands and the final vmovups instruction is operating on xmm0 instead of ymm0.

Am I doing something wrong, or is this a problem in asmjit?

Crash when JitRuntime isn't on the stack

Not sure whether it's an issue or just i'm doing it wrong, so here's my code first

#include <asmjit/asmjit.h>

using namespace asmjit;

struct my_compiler {
        JitRuntime rt;
        X86Compiler *c;
};

int
main(int argc, char **argv)
{
        struct my_compiler *comp;

        comp = (struct my_compiler *) malloc(sizeof(struct my_compiler));

        comp->c = new X86Compiler(&comp->rt);
        comp->c->addFunc(kFuncConvHost, FuncBuilder2<int, int, int>());

        return 0;
}

And this is the BT i've got when running this

>   asmjit.dll!asmjit::X86Compiler::newFunc(unsigned int conv, const asmjit::FuncPrototype & p) Line 1092   C++
    asmjit.dll!asmjit::X86Compiler::addFunc(unsigned int conv, const asmjit::FuncPrototype & p) Line 1114   C++

with the message

Unhandled exception at 0x000000996A900298 in crash.exe: 0xC0000005: Access violation executing location 0x000000996A900298.

Doesn't matter whether I was adding some variables before or after I call ->addFunc, the result is the same. I couldn't find any example with JitRuntime being not on the stack. With the current situation it seems to be impossible to have the runtime and compiler objects on the heap. Or I possibly miss some detail on how to do it.

Thanks.

Compilation fails with GCC on Windows

Commit 1da103f broke compilation for GCC on Windows for cases where asmjit.h is included after C++ standard library headers. This is due to a redefinition of the NOMINMAX macro. (Also, on top of unconditionally defining it, you're unconditionally undefining it also! This may be unexpected in the case where someone has defined that macro, then includes asmjit, and still expects NOMINMAX to be defined.)

Thanks in advance.

Sample output from one of my projects:

gcc.compile.c++ bin\examples\gcc-mingw-4.9.0\debug\address-model-64\architecture-x86\threading-multi\inject\main.o
In file included from C:\Code\asmjit-master\src/asmjit/base.h:12:0,
from C:\Code\asmjit-master\src/asmjit/asmjit.h:312,
from include\memory/hadesmem/call.hpp:19,
from examples\inject\main.cpp:18:
C:\Code\asmjit-master\src/asmjit/build.h:281:0: error: "NOMINMAX" redefined [-Werror]

define NOMINMAX

^
In file included from c:\mingw64\lib\gcc\x86_64-w64-mingw32\4.9.0\include\c++\x86_64-w64-mingw32\bits\c++config.h:426:0,
from c:\mingw64\lib\gcc\x86_64-w64-mingw32\4.9.0\include\c++\utility:68,
from c:\mingw64\lib\gcc\x86_64-w64-mingw32\4.9.0\include\c++\algorithm:60,
from examples\inject\main.cpp:4:
c:\mingw64\lib\gcc\x86_64-w64-mingw32\4.9.0\include\c++\x86_64-w64-mingw32\bits\os_defines.h:45:0: note: this is the location of the previous definition
#define NOMINMAX 1
^
cc1plus.exe: all warnings being treated as errors

"g++"  -ftemplate-depth-128 -O0 -fno-inline -Wall -pedantic -Werror -g -mthreads -m64 -ansi -Wpedantic -Wextra -Weffc++ -Wshadow -Wconversion -Winit-self -Wmissing-include-dirs -Wstrict-aliasing -Wstrict-overflow=5 -Wno-effc++ -Wold-style-cast -Wnon-virtual-dtor -Woverloaded-virtual -Winvalid-pch -Wno-multichar -ftrapv -std=c++1y -DASMJIT_BUILD_X64 -DASMJIT_BUILD_X86 -DASMJIT_STATIC -DBOOST_FILESYSTEM_NO_DEPRECATED -DBOOST_SYSTEM_NO_DEPRECATED -DBOOST_USE_WINDOWS_H -DPUGIXML_HEADER_ONLY -DPUGIXML_WCHAR_MODE -DSTRICT -DSTRICT_TYPED_ITEMIDS -DUNICODE -DWINVER=_WIN32_WINNT_VISTA -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D_WIN32_WINNT=_WIN32_WINNT_VISTA  -I"C:\Code\asmjit-master\src" -I"C:\Code\modular-boost" -I"C:\Code\pugixml-trunk\src" -I"C:\Code\tclap-master\include" -I"C:\Code\udis86-trunk" -I"include\memory" -c -o "bin\examples\gcc-mingw-4.9.0\debug\address-model-64\architecture-x86\threading-multi\inject\main.o" "examples\inject\main.cpp"

...failed gcc.compile.c++ bin\examples\gcc-mingw-4.9.0\debug\address-model-64\architecture-x86\threading-multi\inject\main.o...

ErrorUtil::asString loops indefinitely

I have an AsmJit program that loops forever. When I popped it into gdb, it showed it stayed stuck in asString. I noticed this in findPackedString (which is called by asString) in error.cpp:

while (i < id) {
    while (p[0])
      p++;
    p++;
  }

Is it because i never gets incremented? Is the second p++ supposed to be i++?

Labels are not (fully) relocated if bound before used

I was recently upgrading a project of mine to the latest asmjit (previously used the one from Google Code) and made it to the point where everything compiles successfully but there's a problem at runtime, specifically with dword_ptr and labels.

I made a test program to demonstrate it:

bug.cpp:

#include <asmjit/asmjit.h>

#ifdef OLD_ASMJIT
  using namespace AsmJit;
#else
  using namespace asmjit;
  using namespace asmjit::x86;
#endif

int main() {
  #ifdef OLD_ASMJIT
    X86Assembler _;
  #else
    JitRuntime runtime;
    X86Assembler _(&runtime);
  #endif

  Label label = _.newLabel();

  _.mov(eax, 0xdeadbeef);
  _.ret();

  _.bind(label);
  _.mov(eax, 0x11223344);
  _.ret();

  size_t offset = _.getCodeSize();
  _.lea(eax, dword_ptr(label));
  _.jmp(eax);

  void *code = _.make();
  void *func = static_cast<uint8_t*>(code) + offset;

  // Should return 0x11223344
  int ret = asmjit_cast<int(*)()>(func)();

  #ifdef OLD_ASMJIT
    MemoryManager::getGlobal()->free(code);
  #else
    runtime.release(code);
  #endif

  return ret;
}

CMakeLists.txt:

project(bug)
cmake_minimum_required(VERSION 3.0)

option(OLD_ASMJIT TRUE)

add_definitions(-DASMJIT_API=)
if(OLD_ASMJIT)
  add_definitions(-DOLD_ASMJIT)
endif()

set(ASMJIT_STATIC TRUE)

if(OLD_ASMJIT)
  add_subdirectory(asmjit-old/asmjit)
else()
  add_subdirectory(asmjit)
endif()

if(OLD_ASMJIT)
  include_directories(asmjit-old/asmjit/src)
else()
  include_directories(asmjit/src)
endif()

add_executable(bug bug.cpp)
target_link_libraries(bug asmjit)

The program was designed to work with both old and new asmjit. As you can see, it makes a simple function with X86Assembler and then calls it and returns the result.

If you compile it with the old version of asmjit it will jump back to labeland return 0x11223344, as expected. However, with the new (current) version jumps to the start of code and therefore returns 0xdeadbeef.

If it helps, I've done some debugging and found that the offset variable in X86Assembler::_relocCode() is 0 instead of the real offset. I guess that means something is missing in X86Assembler_emit().

Update:

Found a fix, see PR #53.

Trampoline issue

Hey there,

I'm having some trouble with the trampolines, it appears as its emitting a pointless jump that looks like its supposed to jump around the data generated for the trampoline however the position of it is incorrect.

Thats the following code used:

__declspec(noinline) void* testFunc()
{
    static int x = 0;
    return (void*)&x;
}

int main(int argc, char* argv[])
{
    using namespace asmjit;
    using namespace asmjit::host;

    asmjit::JitRuntime runtime;
    asmjit::x64::Assembler a(&runtime);

    a.push(rax);
    a.pop(rax);
    a.jmp(&testFunc);

    LPVOID lpMem = VirtualAlloc(nullptr, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    a.relocCode(lpMem);

    ((void*(*)())lpMem)();

    return 0;
}

Thats the what output is:

00000000000D0000  push        rax  
00000000000D0001  pop         rax  
00000000000D0002  jmp         00000000000D0007  ; Jump around data?
00000000000D0007  jmp         qword ptr [testFuncPtr]
testFuncPtr:
; 95 20 2a 3f 01 00 00 00
; I'm assuming the jump is supposed to get around this data.
00000000000D000D  xchg        eax,ebp  
00000000000D000E  and         byte ptr [rdx],ch  
00000000000D0010  ?? ?? 
00000000000D0011  add         dword ptr [rax],eax  

JECXZ is missing, should be included ?

JECXZ can only be encoded with 8-bit displacement, which is generally unsafe, because it's difficult to expect the loop body size, especially when writing code for both x86 and x64.

The question is, should it be included anyway if it can be risky?

Something strange with many XmmVar objects

Hi! Sorry if I'm idiot myself, and I can't explain the bug properly. It seems to occur occasionally, only on relatively "heavy" things.

I tried to write this code:
https://github.com/Nekotekina/rpcs3/blob/180f8aac5d2d64c79703503fb7c3e504640d9f9a/rpcs3/Emu/Cell/SPURecompiler.h#L2854

If I uncomment this code and remove "wrapper", some "heavy" thing stops working. But relatively easy things are not affected.

I tried to catch all input and output values using "wrapper", but bug disappeared. All values were similar to "correct" ones. It also passes some easy autotest. So I couldn't find any situation my algorithm fails on. Well, I'm not sure, but I can say that adding specific call() with setArg() changed its behaviour but shouldn't.

Now I decided to add 16 XmmVar variables once when Compiler object is created, instead of local ones in every function, and things got even worse.

EDIT: Found that I was using "void" instead of "FnVoid", going to check it...

Some variables not marked as dead by liveness analysis

Some variables that use less bytes than a register capacity are not marked as dead by liveness analysis, because the operation doesn't change the whole register.

For example cvttsi2sd instruction will not mark xmm variable as dead if declared as kVarTypeXmmSd, but it should.

Solution would be to improve instruction tables so there is information on how many bytes of destination register are overwritten and liveness analysis can use this information to make better job.

bug with if-else

Test cases for testx86.cpp:

  1. the following will work once you replace in X86X64Context::switchState

// Ignore if both states are equal.
if (cur == src)
with
if (cur == src || src == NULL)
I know this is the bad way, but it works.

struct X86Test_IfElseInt : public X86Test {
X86Test_IfElseInt() : X86Test("[IfElse] If-else statement") {}

static void add(PodVector<X86Test*>& tests) {
    tests.append(new X86Test_IfElseInt());
}

virtual void compile(Compiler& c) {
    c.addFunc(kFuncConvHost, FuncBuilder2<int,int,int>());


    GpVar v1(c,kVarTypeInt32);
    GpVar v2(c,kVarTypeInt32);
    Label l1(c), l2(c);

    c.setArg(0, v1);
    c.setArg(1, v2);

    c.cmp(v1, v2);
    c.jg(l1);
    c.mov(v1, imm(1));
    c.jmp(l2);
    c.bind(l1);
    c.mov(v1, imm(2));
    c.bind(l2);
    c.ret(v1);
    c.endFunc();
}

virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) 
{
    typedef int(*Func)(int,int);
    Func func = asmjit_cast<Func>(_func);
    return (func(5,0) == 2) && (func(0,5) == 1);
}

};

  1. the following code will fail on analyze().
    Commenting out removeUnreachableCode() in compile() helps a little, but then it fails anyway.

struct X86Test_IfElseInt2 : public X86Test {
X86Test_IfElseInt2() : X86Test("[IfElse] If-else statement 2") {}

static void add(PodVector<X86Test*>& tests) {
    tests.append(new X86Test_IfElseInt2());
}

virtual void compile(Compiler& c) {
    c.addFunc(kFuncConvHost, FuncBuilder2<int, int, int>());


    GpVar v1(c, kVarTypeInt32);
    GpVar v2(c, kVarTypeInt32);
    Label l1(c), l2(c), l3(c), l4(c);

    c.setArg(0, v1);
    c.setArg(1, v2);

    c.jmp(l1);
    c.bind(l2);
    c.jmp(l4);
    c.bind(l1);


    c.cmp(v1, v2);
    c.jg(l1);
    c.mov(v1, imm(1));
    c.jmp(l2);
    c.bind(l3);
    c.mov(v1, imm(2));
    c.jmp(l2);

    c.bind(l4);

    c.ret(v1);
    c.endFunc();
}

virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect)
{
    typedef int(*Func)(int, int);
    Func func = asmjit_cast<Func>(_func);
    return (func(2, 1) == 2) && (func(1, 2) == 1);
}

};

There are some additional problems when comparing and working with floating-point values with Xmm variables. I have to do a redundant mov operation inside each if-else brench, otherwise it fails on assertion:
Assertion failed: vd->getState() == kVarStateReg, file x86context_p.h, line 254
probably because I modified code as in example 1.
I can't provide example for this compatible with testx86.cpp, because for x86 I don't know how to make movs between GpVar and XmmVar.

Update docs

I was looking through the docs and noticed some issues. For example, on the page for X86X64Compiler, I found the following issues:

  • It says to use the free method of the MemoryManager object returned by getGlobal, when in fact it should be the release method.
  • Wherever FuncBuilder is supposed to be used, it says BuildFunction.

In addition, the class JitRuntime is missing. In addition, there are probably more issues that I haven't noticed.

'_InterlockedCompareExchange': identifier not found in cputicks.cpp

I'm trying to compile AsmJIT with VS2012 express and it fails to find identifier.
Manual 'Go to definition' finds it.
Compile log:

1>------ Rebuild All started: Project: ZERO_CHECK, Configuration: Debug Win32 ------
1>  Checking Build System
1>  CMake does not need to re-run because C:/coding/libs/asmjit/build_vs2012/CMakeFiles/generate.stamp is up-to-date.
2>------ Rebuild All started: Project: asmjit, Configuration: Debug Win32 ------
2>  Building Custom Rule C:/coding/libs/asmjit/CMakeLists.txt
2>  CMake does not need to re-run because C:\coding\libs\asmjit\build_vs2012\CMakeFiles\generate.stamp is up-to-date.
2>  assembler.cpp
2>  codegen.cpp
2>  compiler.cpp
2>  constpool.cpp
2>  context.cpp
2>  cpuinfo.cpp
2>  cputicks.cpp
2>  error.cpp
2>..\src\asmjit\base\cputicks.cpp(51): error C3861: '_InterlockedCompareExchange': identifier not found
2>..\src\asmjit\base\cputicks.cpp(57): error C3861: '_InterlockedCompareExchange': identifier not found
2>..\src\asmjit\base\cputicks.cpp(64): error C3861: '_InterlockedCompareExchange': identifier not found
2>  func.cpp
2>  globals.cpp
2>  intutil.cpp
2>  logger.cpp
2>  operand.cpp
2>  podvector.cpp
2>  runtime.cpp
2>  string.cpp
2>  vmem.cpp
2>  zone.cpp
2>  x86assembler.cpp
2>  x86compiler.cpp
2>  x86context.cpp
2>  x86cpuinfo.cpp
2>  x86func.cpp
2>  x86inst.cpp
2>  x86operand.cpp
2>  x86regs.cpp
2>  x86util.cpp
========== Rebuild All: 1 succeeded, 1 failed, 0 skipped ==========

Problem with the use of registers

Hello,
the following piece of code that used to work just fine using the pre-1.0 branch seems (I'm no x86 expert tbh, I work with ARM devices most of the time) to produce wrong code that leads to segfaults. In the generated code AsmJit uses the rax register that wasn't initialized before while the pointer to the structure is in rbx.

JIT_COMMENT("S_DST_R15"); \
GpVar SPSR = c.newGpVar(EX_GPD); \
GpVar tmp = c.newGpVar(EX_GPD); \
c.mov(SPSR, cpu_ptr(SPSR.val)); \
c.mov(tmp, SPSR); \
c.and_(tmp, 0x1F); \
X86X64CallNode* ctx = c.call((void*)armcpu_switchMode, kFuncConvX64U, FuncBuilder2<     void, void*, u8>()); \
ctx->setArg(0, bb_cpu); \
ctx->setArg(1, tmp); \
c.mov(cpu_ptr(CPSR.val), SPSR); \
c.and_(SPSR, (1<<5)); \
c.shr(SPSR, 5); \
c.lea(tmp, ptr_abs(0xFFFFFFFC, SPSR.r32(), 1)); \
c.and_(tmp, reg_ptr(15)); \
c.mov(cpu_ptr(next_instruction), tmp); \
c.unuse(tmp); \
JIT_COMMENT("end S_DST_R15"); \

where cpu_ptr is a dword_ptr pointing into a structure.
#define cpu_ptr(x) dword_ptr(bb_cpu, offsetof(armcpu_t, x))

Assemble to preallocated memory

Hi, feature request: I would like the assembler to have an option where it assembles directly to memory that I as the user have allocated.

My use case is a profiler that diverts return addresses on the stack to customized landing pads in rwx memory. I'm putting the landing pads together by hand now but that's tedious and error prone so I would like to use asmjit for that.

I'll be happy to work on it. I was thinking alloc/realloc/release callbacks but if there's a better approach, just let me know.

MOV [RSP+4], DWORD - DWORD missing in generated code

The line of C++ code is:
assembler.mov(asmjit::X86Mem(assembler.zsp, 4), asmjit::Imm(0x11113333));
But the generated code is only (4 bytes):
C7 44 24 04

The immediate value is missing.

EDIT:
That's also happening for the x86 version.

EDIT 2:
Okay it's solved by specifying the size parameter for the X86Mem constructor.
But why does the size parameter have a default value of 0 in the first place?
Being able to omit it doesn't seem to be right in that case.

tostopcode.cpp crash with VS2013 x64

When running testopcode.cpp, compiled with the default options, I get this BT

    ntdll.dll!00007ffb0dc69a7a()    Unknown
    ntdll.dll!00007ffb0dc68374()    Unknown
    msvcr120.dll!00007ffafdaa03c1() Unknown
>   asmjit.dll!asmjit::X86Assembler_emit<2>(asmjit::Assembler * self_, unsigned int code, const asmjit::Operand * o0, const asmjit::Operand * o1, const asmjit::Operand * o2, const asmjit::Operand * o3) Line 4197 C++
    asmjit.dll!asmjit::Assembler::emit(unsigned int code) Line 328  C++
    testopcode.exe!asmjit::X86Assembler::ret() Line 1249    C++
    testopcode.exe!asmgen::opcode(asmjit::X86Assembler & a) Line 38 C++
    testopcode.exe!main(int argc, char * * argv) Line 37    C++

AsmJit crashes with functions with char argument

Sample:

#include <asmjit/asmjit.h>

using namespace asmjit;
using namespace asmjit::x86;

int main() {
    JitRuntime runtime;
    X86Compiler c{&runtime};
    c.addFunc(kFuncConvHost, FuncBuilder1<int, char>{});

    // removing the next two lines makes no difference
    X86GpVar x{c, kVarTypeInt8, "x"};
    c.setArg(0, x);

    c.endFunc();
    c.make();
    return 0;
}

Output:

Assertion failed: aType < kX86VarTypeCount
, file src/asmjit/x86/x86compiler.cpp, line 145
Aborted (core dumped)

In release mode, it segfaults. It doesn't matter what I put in between. If I change the char argument to an int, it works perfectly.

movsxd substitute under x86

I'm not sure about the whole asmjit concept: should I ifdef it manually and write specific code? Otherwise it won't compile with x86.

How to write portable code?

I'm working on an application that needs to work on Linux, Mac, and Windows, both 32 and 64 bit. That covers several different ABIs. I'm trying to figure out how I can write my code in a way that will work on all of them.

I first wrote it on Mac and got everything working. Then I tried it on 64 bit Linux and that worked fine. But then I tried Windows (64 bit, but compiling a 32 bit executable) and it crashed. Then I tried 32 bit Linux and it also failed.

I believe this is due to differences in ABIs. For example, 64 bit platfoms use Xmm registers for floating point values, but most 32 bit platforms use Fp registers. But AsmJit requires me to use a completely different type of variable depending on which one is going to be used. As far as I can tell, there's no way to tell it, "This is a floating point variable. Use whatever type of register is appropriate."

How can I write my code in a way that will work on all platforms?

FlushInstructionCache not called (Windows)

Is it really intended, that FlushInstructionCache is never called under Windows?
So is it only there for the ARM version of Windows?

void JitRuntime::flush(void* p, size_t size) {
  // Only useful on non-x86 architectures.
#if !defined(ASMJIT_HOST_X86) && !defined(ASMJIT_HOST_X64)

  // Windows has built-in support in kernel32.dll.
#if defined(ASMJIT_OS_WINDOWS)
  ::FlushInstructionCache(_memMgr.getProcessHandle(), p, size);
#endif // ASMJIT_OS_WINDOWS

#endif // !ASMJIT_HOST_X86 && !ASMJIT_HOST_X64
}

Structured exception handling

Hi! I think, there is some issue on Windows x64 that stack cannot be unwinded if an exception occurs in dynamically generated code... And it seems that RtlAddFunctionTable call is needed. I can't catch exceptions using _set_se_translator, and probably it's the reason that MSVC can't display callstack in debugger when entering JIT code.

http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms680588(v=vs.85).aspx

I don't fully understand it, seems it requires some data that is hard to retrieve from X86Compiler...

mov label address

Is it possible to mov a label address into a register or to a memory location with asmjit?
For a hooking lib I need to replace a return address on the stack with the address of a label.

fatal error: ../base/defs.h: No such file or directory

Trying to build AsmJit with Code::Blocks and MinGW GCC 4.8.2 and I keep getting this error:

||=== Build: Win32 Debug in JitTests (compiler: GNU GCC Compiler) ===|
source\Jit\x86\x86defs.h|14|fatal error: Jit/base/defs.h: No such file or directory|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

Double checked and that file doesn't exist. I have a slightly different directory structure but that shouldn't be the problem considering that the file doesn't exist.

Imm crops bits

Not working:

uint64_t imageBase = 0x000000013f780000
mov(rax, imageBase)

Result: 
mov rax,3F590000h  

Working:

uint64_t imageBase = 0x000000013f780000
mov(*rax, Imm(imageBase));

Result:
mov         rax,13FB00000h  

Compiling bytecode from C++ strings.

I am wondering, if it would be possible to add a function to compile Intel ASM syntax formatted strings to functions. I'm not sure as to how long it would take to add such a feature, but such a feature would be greatly appreciated.

Unknown symbol BaseAssembler

When I try to compile on Windows, it fails with an error about the unknown symbol "BaseAssembler" that appears in winremoteruntime.h and winremoteruntime.cpp. A search through the source code verifies that the symbol doesn't appear anywhere except in those two files, and neither of them defines it.

Crash when in 32 bit mode

The following example generates a function to compute sqrt(2). It works correctly when compiled in 64 bit mode, but crashes when compiled in 32 bit mode.

void test() {
    JitRuntime runtime;
    X86Compiler c(&runtime);
    c.addFunc(kFuncConvHost, FuncBuilder0<double>());
    X86XmmVar argVar = c.newXmmVar(kX86VarTypeXmmSd);
    X86XmmVar resultVar = c.newXmmVar(kX86VarTypeXmmSd);
    X86GpVar argPointer(c);
    double two = 2.0;
    c.mov(argPointer, imm_ptr(&two));
    c.movsd(argVar, x86::ptr(argPointer, 0, 0));
    X86GpVar fn(c, kVarTypeIntPtr);
    double (*function)(double) = sqrt;
    c.mov(fn, imm_ptr((void*) function));
    X86CallNode* call = c.call(fn, kFuncConvHost, FuncBuilder1<double, double>());
    call->setArg(0, argVar);
    call->setRet(0, resultVar);
    c.ret(resultVar);
    c.endFunc();
    void* jitCode = c.make();
    printf("%g\n", ((double (*)()) jitCode)());
}

Consider changing build systems

Ok...

I still remember an issue where you complained that CMake's language never works like you'd expect. I hate having to download a 20-dozen-file program and building it just to use AsmJit.

It also seems like the CMake script has LOTS of boilerplate (for instance, the Asmjit_Add_* macros).

So...I was wondering if you'd look into using another build system such as fbuild, Boost.Build, Waf, Gyp, or maybe even shudder SCons shudder.

Thoughts? I have experience using all of the above except SCons (and somewhat Gyp), so I could help with whatever you need.

As a point of interest, Boost.Build has built-in support for selecting between a static and a shared library.

error: 'GpReg' does not name a type

Trying to build AsmJit with Code::Blocks and MinGW GCC 4.8.2 and I keep getting this error:

||=== Build: Win32 Debug in JitTests (compiler: GNU GCC Compiler) ===|
source\Jit\x86\x86regs.h|340|error: 'GpReg' does not name a type|
source\Jit\x86\x86regs.h|342|error: 'GpReg' does not name a type|
source\Jit\x86\x86regs.h|344|error: 'GpReg' does not name a type|
source\Jit\x86\x86regs.h|346|error: 'GpReg' does not name a type|
source\Jit\x86\x86regs.h|348|error: 'GpReg' does not name a type|
source\Jit\x86\x86regs.h|350|error: 'GpReg' does not name a type|
source\Jit\x86\x86regs.h|352|error: 'GpReg' does not name a type|
source\Jit\x86\x86regs.h|354|error: 'GpReg' does not name a type|
D:\Projects\JitTests\source\Jit\x86\x86assembler.cpp||In instantiation of 'asmjit::Error asmjit::x86x64::X86X64Assembler_emit(asmjit::x86x64::X86X64Assembler*, uint32_t, const asmjit::Operand*, const asmjit::Operand*, const asmjit::Operand*, const asmjit::Operand*) [with int Arch = 1; asmjit::Error = unsigned int; uint32_t = unsigned int]':|
D:\Projects\JitTests\source\Jit\x86\x86assembler.cpp|4156|required from here|
D:\Projects\JitTests\source\Jit\x86\x86assembler.cpp|1514|warning: suggest parentheses around '&&' within '||' [-Wparentheses]|
||=== Build failed: 8 error(s), 3 warning(s) (0 minute(s), 2 second(s)) ===|

The struct is declared in "(asmjit source dir)/x86/x86defs.h" but it's not included.

It's impossible to generate jumps to arbitrary positions

As stated in the title, it's impossible at the moment to make asmjit generate a jump opcode pointing to something different than a label.
The pushf / ret combo is just an hack, the 0xE9 + offset way should be used instead.

mov rax, qword ptr gs:[0x30]

The instruction in the title above is impossible to generate. I'm trying to setup a Mem object and say setSegment(gs)

It produces:

MOV RAX,QWORD PTR GS:[RDI+30]

I don't see how the RDI is getting there.

Liveness analysis doesn't handle jumps properly

The following log demonstrates the issue:

L0:
; Prolog
push rbx                            ;
push rbp                            ;
push rsi                            ;
push rdi                            ;
; Body
mov rax, qword ptr [rcx+88]         ; mov dPtr, [worker+88]      r.w    ..
mov ebx, dword ptr [rdx+100]        ; mov h, [ras+100]           .r.w   ..
mov rbp, rax                        ; mov dStride, dPtr          ..r.w  ..
mov esi, dword ptr [rdx+96]         ; mov w, [ras+96]            .r...w ..
imul rax, ebx                       ; imul dPtr, h               ..xr.. ..
mov rdi, [rcx+64]                   ; mov pattern, [worker+64]   r.....w..
cvtsi2sd xmm0, ebx                  ; cvtsi2sd yt, h             ...r...x.
cvtsi2sd xmm1, esi                  ; cvtsi2sd pt, w             .....r..x
movsd xmm2, [rdi+48]                ; movsd dy, [pattern+48]     ......r..w
movsd xmm3, [rdi+40]                ; movsd dx, [pattern+40]     ......r...w
mulsd xmm0, xmm2                    ; mulsd yt, dy               .......x.r.
mulsd xmm1, xmm3                    ; mulsd pt, dx               ........x.r
addsd xmm0, [rdi+32]                ; addsd yt, [pattern+32]     ......rx...
addsd xmm0, xmm1                    ; addsd yt, pt               .......xr..
mov r8, [rdi+24]                    ; mov table, [pattern+24]    ......R....w
movsd xmm1, xmm0                    ; movsd pt, yt               ...... rx...
neg ebx                             ; neg h                      ...x.. .....
lea rax, qword ptr [rax+rsi*4]      ; lea dPtr, [dPtr+w*4]       ..x..r .....
neg esi                             ; neg w                      .....x .....
add rax, qword ptr [rcx+72]         ; add dPtr, [worker+72]      R.x... .....
add esi, dword ptr [rdx+104]        ; add w, [ras+104]            r...x .....
add ebx, dword ptr [rdx+108]        ; add h, [ras+108]            R.x.. .....
lea ecx, [0+esi*4]                  ; lea x, [0+w*4]               ...r .....w
sub rbp, ecx                        ; sub dStride, x               ..x. .....R
mov [rsp-24], rbp                   ; [Spill] dStride
mov ecx, esi                        ; mov x, w                     ...r .....w
L2:
cvttsd2si edx, xmm1                 ; cvttsd2si index, pt          .... .r....w
addsd xmm1, xmm3                    ; addsd pt, dx                 .... .x.r...
shr edx, 8                          ; shr index, 8                 .... ......x
and edx, 255                        ; and index, 255               .... ......x
mov edx, dword ptr [r8+rdx*4]       ; mov index, [table+index*4]   .... ....r.x
mov dword ptr [rax], edx            ; mov [dPtr], index            r... ......R
sub ecx, 1                          ; sub x, 1                     .... .....x
lea rax, [rax+4]                    ; lea dPtr, [dPtr+4]           x... ......
short jnz L2                        ; jnz L2                       .... ......
sub ebx, 1                          ; sub h, 1                     .x.. .....
jz L3                               ; jz L3                        .... .....
add rax, qword ptr [rsp-24]         ; add dPtr, [dStride]          x.R. .....
addsd xmm0, xmm2                    ; addsd yt, dy                 .. . x.R..
movsd xmm1, xmm0                    ; movsd pt, yt                 .. . Rx ..
mov ecx, esi                        ; mov x, w                     .. R  . ..w
mov esi, [rsp-16]                   ; [Load] w (INVALID, w shouldn't be dead here)
movsd xmm0, [rsp-32]                ; [Load] yt (INVALID, yt shouldn't be dead here)
movsd xmm2, [rsp-40]                ; [Load] dy (INVALID, dy shouldn't be dead here)
short jmp L2                        ; jmp L2                       ..    . ...
L3:
L1:
; Epilog
pop rdi                             ;
pop rsi                             ;
pop rbp                             ;
pop rbx                             ;
ret                                 ;

Stdcall stack issues

Hi,

I am trying to call a WINAPI function from assembly but there seems to be a stack issue, the stack is not pushed accordingly by the compiler thus when the callee pops it ends up too low down the stack.

Here is a snippet to reproduce :

void* __stdcall test(int a)
{
    return (void*)&a;
}

x86x64::GpVar v1(c, kVarTypeInt32);
x86x64::GpVar v2(c, kVarTypeInt32);
x86x64::GpVar r(c, kVarTypeIntPtr);
x86x64::GpVar fn(c, kVarTypeIntPtr, "fn");
c.mov(fn, imm_ptr((void*)test));

x86x64::X86X64CallNode* pCallNode = c.call(fn, x86x64::kFuncConvStdCall, FuncBuilder2<intptr_t, int32_t, int32_t>());
pCallNode->setArg(0, v1);
pCallNode->setArg(1, v2);
pCallNode->setRet(0, r);

In the mean time I just push the stack myself before the call to return to the right address :
c.push(v1);

Cheers !

Passing pointer to function

Perhaps I'm just doing something stupid, but if so, I can't figure out what it is. I'm just trying to invoke a function, passing a pointer as an argument. I define a simple function:

static void testFn(void* x) {
    printf("x=%p\n", x);
}

And then I invoke it as follows:

X86GpVar fn(c, kVarTypeIntPtr, "testFn");
c.mov(fn, imm_ptr((void*)testFn));
X86CallNode* call = c.call(fn, kFuncConvHost, FuncBuilder1<Void, void*>());
void* x = (void*) 0x12345;
call->setArg(0, imm_ptr(x));

I'd expect that to print out "x=0x12345". But it doesn't. Instead it prints "x=0x7ff651c06120". What is going on?

This is on Mac OS X 10.9.4 compiling with clang.

Allow FuncBuilder to take argument sizes

I'm working on a set of Python bindings for AsmJit. The problem is with the FuncBuilder classes. They takes the types as template arguments. This must be determined at compile time. My idea is to let it take argument sizes, i.e.: DynFuncBuilder(sizeof(int), sizeof(char)) is equivalent to FuncBuilder<int,char>(). That way, it can be called from within Python, since it's easy to get the type sizes using compile-time constants.

Inconsistent alignment of x86x64::GpReg

Environment: MSVC 2013 compiler, x86 and x64 release builds, static asmjit linkage, default compiler settings.

GpReg definition in x86regs.cpp uses ASMJIT_REGS_INIT macro, thus GpReg is expanded into this (alignment of 4):

struct GpReg  { Operand::InitRegOp data; };

At the other hand, general declaration in x86operand.h has alignment of 8:

struct GpReg : public X86Reg {
...

Xmm constants

Hi again! Can you help a bit? I don't understand how to create some xmm constants in compiler, and use them in optimal way.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.