@@ -418,6 +418,7 @@ X64ThunkEmitter::X64ThunkEmitter(X64Backend* backend, XbyakAllocator* allocator)
418418X64ThunkEmitter::~X64ThunkEmitter () {}
419419
420420HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk () {
421+ #if XE_PLATFORM_WIN32
421422 // rcx = target
422423 // rdx = arg0 (context)
423424 // r8 = arg1 (guest return address)
@@ -460,6 +461,53 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() {
460461 mov (rdx, qword[rsp + 8 * 2 ]);
461462 mov (r8, qword[rsp + 8 * 3 ]);
462463 ret ();
464+ #elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC
465+ // System-V ABI args:
466+ // rdi = target
467+ // rsi = arg0 (context)
468+ // rdx = arg1 (guest return address)
469+
470+ struct _code_offsets {
471+ size_t prolog;
472+ size_t prolog_stack_alloc;
473+ size_t body;
474+ size_t epilog;
475+ size_t tail;
476+ } code_offsets = {};
477+
478+ const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
479+
480+ code_offsets.prolog = getSize ();
481+
482+ // rsp + 0 = return address
483+ mov (qword[rsp + 8 * 3 ], rdx);
484+ mov (qword[rsp + 8 * 2 ], rsi);
485+ mov (qword[rsp + 8 * 1 ], rdi);
486+ sub (rsp, stack_size);
487+
488+ code_offsets.prolog_stack_alloc = getSize ();
489+ code_offsets.body = getSize ();
490+
491+ // Save nonvolatile registers.
492+ EmitSaveNonvolatileRegs ();
493+
494+ mov (rax, rdi);
495+ // mov(rsi, rsi); // context
496+ mov (rcx, rdx); // return address
497+ call (rax);
498+
499+ EmitLoadNonvolatileRegs ();
500+
501+ code_offsets.epilog = getSize ();
502+
503+ add (rsp, stack_size);
504+ mov (rdi, qword[rsp + 8 * 1 ]);
505+ mov (rsi, qword[rsp + 8 * 2 ]);
506+ mov (rdx, qword[rsp + 8 * 3 ]);
507+ ret ();
508+ #else
509+ assert_always (" Unknown platform ABI in host to guest thunk!" );
510+ #endif
463511
464512 code_offsets.tail = getSize ();
465513
@@ -479,6 +527,7 @@ HostToGuestThunk X64ThunkEmitter::EmitHostToGuestThunk() {
479527}
480528
481529GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk () {
530+ #if XE_PLATFORM_WIN32
482531 // rcx = target function
483532 // rdx = arg0
484533 // r8 = arg1
@@ -515,6 +564,57 @@ GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() {
515564
516565 add (rsp, stack_size);
517566 ret ();
567+ #elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC
568+ // This function is being called using the Microsoft ABI from CallNative
569+ // rcx = target function
570+ // rdx = arg0
571+ // r8 = arg1
572+ // r9 = arg2
573+
574+ // Must be translated to System-V ABI:
575+ // rdi = target function
576+ // rsi = arg0
577+ // rdx = arg1
578+ // rcx = arg2
579+ // r8, r9 - unused argument registers
580+
581+ struct _code_offsets {
582+ size_t prolog;
583+ size_t prolog_stack_alloc;
584+ size_t body;
585+ size_t epilog;
586+ size_t tail;
587+ } code_offsets = {};
588+
589+ const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
590+
591+ code_offsets.prolog = getSize ();
592+
593+ // rsp + 0 = return address
594+ sub (rsp, stack_size);
595+
596+ code_offsets.prolog_stack_alloc = getSize ();
597+ code_offsets.body = getSize ();
598+
599+ // Save off volatile registers.
600+ EmitSaveVolatileRegs ();
601+
602+ mov (rax, rcx); // function
603+ mov (rdi, GetContextReg ()); // context
604+ mov (rsi, rdx); // arg0
605+ mov (rdx, r8); // arg1
606+ mov (rcx, r9); // arg2
607+ call (rax);
608+
609+ EmitLoadVolatileRegs ();
610+
611+ code_offsets.epilog = getSize ();
612+
613+ add (rsp, stack_size);
614+ ret ();
615+ #else
616+ assert_always (" Unknown platform ABI in guest to host thunk!" )
617+ #endif
518618
519619 code_offsets.tail = getSize ();
520620
@@ -537,6 +637,7 @@ GuestToHostThunk X64ThunkEmitter::EmitGuestToHostThunk() {
537637uint64_t ResolveFunction (void * raw_context, uint64_t target_address);
538638
539639ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk () {
640+ #if XE_PLATFORM_WIN32
540641 // ebx = target PPC address
541642 // rcx = context
542643
@@ -572,6 +673,49 @@ ResolveFunctionThunk X64ThunkEmitter::EmitResolveFunctionThunk() {
572673
573674 add (rsp, stack_size);
574675 jmp (rax);
676+ #elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC
677+ // Function is called with the following params:
678+ // ebx = target PPC address
679+ // rsi = context
680+
681+ // System-V ABI args:
682+ // rdi = context
683+ // rsi = target PPC address
684+
685+ struct _code_offsets {
686+ size_t prolog;
687+ size_t prolog_stack_alloc;
688+ size_t body;
689+ size_t epilog;
690+ size_t tail;
691+ } code_offsets = {};
692+
693+ const size_t stack_size = StackLayout::THUNK_STACK_SIZE;
694+
695+ code_offsets.prolog = getSize ();
696+
697+ // rsp + 0 = return address
698+ sub (rsp, stack_size);
699+
700+ code_offsets.prolog_stack_alloc = getSize ();
701+ code_offsets.body = getSize ();
702+
703+ // Save volatile registers
704+ EmitSaveVolatileRegs ();
705+ mov (rdi, rsi); // context
706+ mov (rsi, rbx); // target PPC address
707+ mov (rax, reinterpret_cast <uint64_t >(&ResolveFunction));
708+ call (rax);
709+
710+ EmitLoadVolatileRegs ();
711+
712+ code_offsets.epilog = getSize ();
713+
714+ add (rsp, stack_size);
715+ jmp (rax);
716+ #else
717+ assert_always (" Unknown platform ABI in resolve function!" );
718+ #endif
575719
576720 code_offsets.tail = getSize ();
577721
0 commit comments