Skip to content

New Features for exlaunch + marshmallow - #6

Open
Werechang wants to merge 11 commits into
LynxDev2:masterfrom
Werechang:master
Open

New Features for exlaunch + marshmallow#6
Werechang wants to merge 11 commits into
LynxDev2:masterfrom
Werechang:master

Conversation

@Werechang

Copy link
Copy Markdown
Contributor

This pr still needs some testing which I'll do in the next days.

NZCV access in inline hooks

The NZCV flags are now available in inline hooks. The only reason is that it got thrashed in older versions of exlaunch
so it needed to be backed up anyway.

struct MyInlineHook : public exl::hook::impl::InlineHook<MyInlineHook> {
    static void Callback(exl::hook::InlineCtx* ctx) {
        mallow::log::logLine("N: %i Z: %i C: %i V: %i", ctx->NZCV.N, ctx->NZCV.Z, ctx->NZCV.C, ctx->NZCV.V);
        // NZCV isn't thrashed anymore
        if (...) ...
    }
};

Branched inline hooks

The branched inline hook allows you to jump to different spots in the code. This is useful when hooking a loop to
achieve equivalent results to continue or break or to branch to the right
spot in nested control structures.

struct MyBranchedInlineHook : public exl::hook::impl::InlineHook<MyBranchedInlineHook> {
    // enum is optional, can be used as a readable index
    enum Branch {
        NotTaken,
        Taken
    };
    static constexpr ptrdiff_t Branches[] = { 0x0, 0x6b8 };

    // Return index into Branches array
    static uint8_t Callback(exl::hook::InlineCtx* ctx) {
        if (...) {
            return Taken;
        }
        return NotTaken;
    }
};
...
void init() {
    MyBranchedInlineHook::InstallAtOffset(0x100);
}

The branched inline hook requires Callback to return a uint8_t type, and take a valid inline context type
parameter (meaning inline float context works too). It needs a static constexpr ptrdiff_t[] with the values being 4
aligned.

C++20 Concepts for inline hooks

As foreshadowed in the text above, inline hook constraints are now concept based to be more readable and easier to use.

Extended and safe instruction API

A few instruction types were added:

  • Conditional branches with direct implementations for b.eq and b.ne
  • Fixed bitwise OR register with immediate, meaning that it is available now
  • Unsigned bitfield move, which is an alias for LSL/LSR imm, UBFIZ, UBFX, UXTB and UXTH

And all instruction parameters are now compile time checked to capture register width mix-ups and immediate sizes being
too big. The error messages aren't very intuitive to read, but that is still better than exlaunch silently running into
unexpected behavior.

Error handling, logging and readability

Instead of relying on exlaunch's error codes the user now receives log messages which help better to track errors down.
The user is notified within the log if exlaunch has to resort to hook patches which possibly cause unexpected behavior.
Register thrashes usually come with that and are also logged.
These warnings usually happen when the exlaunch module is too far away from the target module.

Symbol + Offset hooking

Hook::InstallAtSymbol now takes a Symbol instead of a const char* which can be constructed with the _sym
literal. The class implements operator+ to support the symbol + offset hook. Trampoline and Replace hooks still use
the old method with const char* to preserve backwards compatibility.

ExampleTrampolineHook::InstallAtSymbol("_ZN10StageScene7controlEv"_sym);
ExampleInlineHook::InstallAtSymbol("_ZN10StageScene7controlEv"_sym + 0x2a4);

This change unfortunately breaks the old API for inline hooks by removing the option for const char* symbols.
It was removed for the reason that const char* and ptrdiff_t can be added, but it leads to an invalid symbol.
Users might then forget _sym and write InstallAtSymbol("MySym" + 0x4), which is invalid.
An implicit conversion from const char* to Symbol wouldn't have worked since the plus operator gets evaluated before
the expression is converted.

Exlaunch internal changes + bugfixes

  • Fix: X17 is now thrashed in less cases. The user is warned in the cases it isn't.
  • Fix: InlineFloatCtx had a really bad layout which is now fixed.
  • Fix: The NZCV register is now saved in inline hooks (see here).
  • The inline hook jit is now dynamically managed so that space isn't wasted
  • Some inline impl code got moved into inline_impl.hpp because it has templates now
  • The old inline_impl.hpp is now named inline_ctx.hpp

General TODOs

These are things I will probably do in the future which won't be a part of this merge request.

  • Concepts for trampoline and replace hooks
  • Dynamic trampoline jit
  • Make hooks instance based -> same hook installed at multiple offsets
  • Add more instructions

@Werechang Werechang left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will fix these things now and hope that this should be it

Comment thread libs/exlaunch/exl/hook/inline.hpp Outdated
Comment thread libs/exlaunch/exl/hook/nx64/inline_ctx.hpp Outdated
Comment thread libs/exlaunch/exl/hook/nx64/inline_ctx.hpp Outdated
Comment thread libs/exlaunch/exl/hook/nx64/inline_impl.hpp Outdated
Comment thread libs/marshmallow/mallow/init/initLogging.hpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant