I made a proof-of-concept method call patcher: https://github.com/micktu/RimWorld-BuildProductive/blob/master/Source/MethodCallPatcher.cs (https://github.com/micktu/RimWorld-BuildProductive/blob/master/Source/MethodCallPatcher.cs)
What it does is it looks for every call to a specific method in other method's body and replaces it with a method of your choice.
Because there's no way I'm aware of to either to force Mono JIT compilation or to check if the method was compiled, it repeatedly scans the method over time until it finds what it needs. As it's just looping through a few hundreds bytes per tick with direct memory access it's not very taxing; funny thing is, method body does exist before the actual method is compiled, but I'm not sure about what it contains.
This enables more kinds of injections into methods; I'll provide an example of a better detour method than CCL has currently.
- Read the first bunch of instructions from the source method and save them*;
- Place a JMP to target method;
- Allocate some executable memory, place preserved instructions there, followed by a JMP to the source method, to the next instruction after JMP to target;
- Patch the call to the source method in target method body with a call to our allocated buffer.
* Implies every method is consistent with its first instructions, more research needed.
Et voila, we have a detour that can actually call the base method.
This looks very promising, am I correct in assuming that this would allow one to attach events* to method calls? E.g. leave the original call intact, but do something extra when called? With access to the original arguments + instance data?
(I'm aware it's not really an event, but you get the gist).
Yeah, pretty much that, you can make hooks/callbacks. That's exactly what I had in mind.
I didn't post an actual usage sample, but in my case, I inject a command before gizmo rendering. Wanted to use it to inject commands into existing Thing classes.
internal static void GizmoGridDrawer_DrawGizmoGrid(IEnumerable<Gizmo> gizmos, float startX, out Gizmo mouseoverGizmo)
{
Command_Action command_Action = new Command_Action();
command_Action.defaultLabel = "Test Icon";
command_Action.action = delegate
{
};
(gizmos as List<Gizmo>).Add(command_Action);
GizmoGridDrawer.DrawGizmoGrid(gizmos, startX, out mouseoverGizmo);
}
Quote from: Micktu on August 05, 2016, 02:59:26 AM...a better detour method than CCL has currently.
That's a rather opinionated and biased statement. That it's constantly scanning makes it no "better" in my opinion just different.
The only problem with this I see is that you need to scan every single method to trap all cases as opposed to CCLs current implementation which traps all cases with one change.
Anyway, it sounds promising for certain cases and look forward to seeing some actual working code using this.
The current method does not allow to return to the original method. For me it's essential to be able to call the original, i.e. produce an actual hook that does not require to copy-paste decompiled code into the target method, which is the case in CCL right now. It will break constantly and will require a meticulous update on every application update. To sum it up, it doesn't really work.
The snippet above is the sampe of actual tested-to-be-working code I'll be using to inject commands into things.
CCLs detouring method does not allow calls to base.method, correct. Doing so will cause a stack overflow due to the call being resolved back into the detour, correct. The solution, which isn't great, is to include the entire method bodies of all base.method calls into the detour, correct.
However, scanning every method in every DLL plus the game executable 10/sec to patch call sites to trap all calls to your detour is also not the best method and will certainly impose a large performance penalty.
I'm not saying I dislike your idea just that it's sub-optimal for blanket cases. For "I only want to redirect this one methods calls" situation, it's very good.
>scanning every method in every DLL plus the game executable
No, it was never meant to work this way, this is intended to patch calls in a single method. Above I described how to use it with some additions to existing CCL method to make an actual working hook. Basically, you're not patching the game's method, but you're patching your own so you don't get stuck in an infinite loop if you try and call the base one, and return properly.
Anyway, no, there's no real performance impact, the scan might take a few microseconds per frame and that's all. And it stops when it has been patched. I benchmarked a single scan, it takes 1.5-3 microseconds on my PC.
For example, if all required scans for all mods would take 50us, it's still like 0.3% of a tick, which is completely negligible in my opinion. An I'm not even doing it every tick.
Quote from: 1000101 on August 05, 2016, 04:46:57 AMI'm not saying I dislike your idea just that it's sub-optimal for blanket cases. For "I only want to redirect this one methods calls" situation, it's very good.
Key statements, important.
Maybe I'm bad at explaining things. It's not the complete solution, it's a part of a "blanket" solution that can replace the current hook method.
So, let me phrase this in simple(r) terms to see if I understand it.
Let's say we have two methods, Vanilla.Foo( object x ), and MyMod.Bar( object x ). I want to call Bar() whenever Foo() is called.
I'd call your code to create me a patch, which starts the following process in your code;
- Every x ticks, Foo() is scanned to see if the JIT has been compiled yet.
- If Foo() was compiled, we store the first few instructions in Foo(), then override them with a call to Bar().
- We also create a 'new' method, Boo(), that consists of Foo's stored instructions, and a jump back into Foo() ['behind' the jump to Bar(), so we don't end up in an infinite loop].
- Finally, any call to Foo() from Bar() is amended to instead call Boo() [since calling Foo() would cause an infinite loop].
That sounds pretty cool. I have a few (noob) questions though;
- How sure are you that the first few instructions in Foo() won't be affected by relative memory addresses?
- Are you checking the length of Foo() when patching?
- And finally, assuming Foo() can be reliably preserved, would you mind implementing a rudimentary event based system around this? I'm envisioning OnCall( MethodInfo( Foo), delegate( pars ) ) kind of schemes, as well as PreCall and PostCall hooks to intercept and change arguments and return values on their way to and from Foo().
Assuming E and the other CCL people are on board and it all works reliably cross-platform, I think it'd be a very good idea to get this in CCL. Having multiple mods implement these techniques independently, and possibly targeting the same methods is going to be quite the mess.
Also, regarding waiting for JIT compilation. If I understand the process correctly, the main difference between your approach and CCL's is that you salvage the detoured method (which is awesome if it works). What I don't understand is why CCL doesn't have to wait for JIT, and you apparently do. I mean, presumably if the method wasn't compiled and CCL injects the detour jump, compilation would override that. So either we're never run into not yet compiled code, or there's something else going on (probably me misunderstanding something).
Your explanation got a couple of thing backwards, but it's not a big deal.
>How sure are you that the first few instructions in Foo() won't be affected by relative memory addresses?
Because the stack will be in the same state as it's supposed to be when we will get there.
>Are you checking the length of Foo() when patching?
No, I just scan till its return.
>would you mind implementing a rudimentary event based system around this
I'm not sure if I will need it, but anyone can do it, it's not complicated.
>What I don't understand is why CCL doesn't have to wait for JIT, and you apparently do.
I don't know, too. Perhaps it's not compilation I'm waiting for, but optimization, so the method gets static addresses I can patch; don't really know much about how JIT is supposed to work here. I'm investigating this at the moment.
Getting the methodinfo and subsequent method pointer is supposed to actually trigger the JIT itself which makes waiting for it a bit redundant. However, if this for some reason doesn't happen, then the injector needs to wait for it. In my experience I have never seen this happen though inside of mono (which is what RimWorld is using).
As to scanning until the return, what happens if it has branches which jump over the return or has multiple returns? Wouldn't getting the method length from the method info be a more reliable way to do this?
>Getting the methodinfo and subsequent method pointer is supposed to actually trigger the JIT
Yeah, I was aware, that's why I was wondering. Turned out to be optimization: the calls are not routed as static until it's executed once.
> if it has branches which jump over the return or has multiple returns?
No, it doesn't. It's just that I haven't seen anything like this in native JIT-compiled code. Have you?
>Wouldn't getting the method length from the method info be a more reliable way to do this?
Does it provide native function size? I didn't think it was possible. Can you point me in the right direction?
Anyway, I'm trying to drop the waiting method and just make it a reliable hook. Trying out a few ways currently.
Quote from: Micktu>Getting the methodinfo and subsequent method pointer is supposed to actually trigger the JIT
Yeah, I was aware, that's why I was wondering. Turned out to be optimization: the calls are not routed as static until it's executed once.
Under normal .Net that is true, but I've found that mono seems to compile it when getting the MethodInfo. I can't say this is true under all circumstances but the current detouring works under this assumption and that's the key thing - it works.
Quote from: Micktu> if it has branches which jump over the return or has multiple returns?
No, it doesn't. It's just that I haven't seen anything like this in native JIT-compiled code. Have you?
>Wouldn't getting the method length from the method info be a more reliable way to do this?
Does it provide native function size? I didn't think it was possible. Can you point me in the right direction?
I could have sworn there was a field for the length of the method but I could be wrong. I just checked the MSDN and there is no field listed, I might be getting my wires crossed.
Quote from: MicktuAnyway, I'm trying to drop the waiting method and just make it a reliable hook. Trying out a few ways currently.
CCL will still need it's current detouring method as it requires a guarunteed detour during it's module initializer. Those particular detours don't rely on calling any base methods so they don't need to worry about their destruction. However, a "cleaner" detouring would be nice for "regular" usage which preserves the original or at least makes it accessible.
I don't have 1/10th the coding knowledge you guys have... so posting this here as it might be semi-relevant.
For most moddable games, someone eventually comes out with a performance meter of some kind. Is there one for Rimworld?
I'm looking for, or willing to learn how to make, a dll to monitor the frequency (to start with) mod methods fire.
To paint a picture - a mod is supposed to fire when a pawn's mood changes, yet fires needlessly on every pawn item interaction?
The extension of this would be to determine how long each time each mod activation consumes.
From the code changes I follow on github, I know you guys are aware of the need to optimize your own code. Was just wondering if there is a way to determine the impact of other peoples code ingame. Thanks for any replies.
So after a day and some of some hardcore ass-in-chair action I've managed to produce another solution that is dumb and brilliant at the same time.
Basically, it acts as an override: if the method was called from some distant galaxy, it calls your hook/detour/whateveryoucallit. However, if it's called from YOUR method, it calls the base method. It still relies on guessing the boundaries of your method once, but now I have a pretty good idea how to make it reliable.
It's really really hacky, I'll publish it once I tidy it up a little bit.
Quote from: biship on August 06, 2016, 06:09:49 AM
I don't have 1/10th the coding knowledge you guys have... so posting this here as it might be semi-relevant.
For most moddable games, someone eventually comes out with a performance meter of some kind. Is there one for Rimworld?
I'm looking for, or willing to learn how to make, a dll to monitor the frequency (to start with) mod methods fire.
To paint a picture - a mod is supposed to fire when a pawn's mood changes, yet fires needlessly on every pawn item interaction?
The extension of this would be to determine how long each time each mod activation consumes.
From the code changes I follow on github, I know you guys are aware of the need to optimize your own code. Was just wondering if there is a way to determine the impact of other peoples code ingame. Thanks for any replies.
This is not really relevant to the current discussion, please create a new thread for it. :)
Then, I don't have a 1/10th the clue what this thread is about. :)
So I'll drop this monstrosity here: https://github.com/micktu/RimWorld-BuildProductive/blob/injection/Source/HookInjector.cs (https://github.com/micktu/RimWorld-BuildProductive/blob/injection/Source/HookInjector.cs)
There's still a lot of refactoring and testing to do, but the idea is there.
It lets me do this:
(https://monosnap.com/file/Be0aLaGD62RirXl7Nqxx5WBoLkI6vq.png)
To get this:
(https://monosnap.com/file/jREt2QDlB6khWS980zwO9qyfqY4unv.png)
I'll also make sure that it still works correctly even if the proc was already rerouted by other mods using CCL.
Was it worth the effort? Not sure. Also thing like this risks hella lot of maintenance even if it's stable.
method is good.
there is no reason to reject again and again things you don't like for some personal reasons.
After browsing Mono sources for a while I've found that the correct method to find generated code size is to hook into Mono JIT's mono_destroy_compile (MonoCompile *cfg). The MonoCompile struct is supposed to contain code length then, it will be freed afterwards, and the info forever lost. Not doing it at the moment though.
Yep, that was correct.
(https://monosnap.com/file/d831P72vFYRl7F6ssOtOrsm4e7sqs9.png)
Highlighted is the function pointer, followed by code_size and code_len fields, containing correct values (I don't know why both fields are needed, the compiler seems to care about code_len in the end).
A cute small function injected before mono_empty_compile() keeps track of last 256 functions compiled with their sizes.
(https://monosnap.com/file/8TX1BNVa9nDj4KXZ86kXHkGc7g03Go.png)
Aaand it worked. Prototype code here: https://github.com/micktu/RimWorld-BuildProductive/blob/injection/Source/MethodSizeHelper.cs (https://github.com/micktu/RimWorld-BuildProductive/blob/injection/Source/MethodSizeHelper.cs)
This thing is getting reliable. Let's make it work on x64 again.
this is bloat, proper way for calculation method size is:
[MethodImpl(MethodImplOptions.NoInlining)]
static public void MethodFastPrint(RuntimeMethodHandle hx)
{
void* fpraw = hx.GetFunctionPointer().ToPointer();
void* jitinforaw = mono_jit_info_table_find (mono_domain_get (), fpraw);
u_MonoJitInfo jitinfo = *(u_MonoJitInfo*)jitinforaw;
int size = jitinfo.code_size;
}
where
[DllImport("__Internal")]
static extern private unsafe void* mono_jit_info_table_find(void* MonoDomain, void* ptr2function);
[DllImport("__Internal")]
static extern private unsafe void* mono_domain_get ();
and memory map is
[StructLayout(LayoutKind.Explicit)] public unsafe struct u_MonoJitInfo
{
[FieldOffset(0) ] public int *dmethod;
[FieldOffset(8) ] public int *code_start;
[FieldOffset(16)] public int code_size;
}
linked table contains ALL methods ever compiled for domain, you don't need to inject anything to keep track of them, runtime already do it.
Thanks, I'll verify one I'll get to my PC.
Edit: Yes, that seems just about right! Let's implement.
Actually it wasn't bloat, it was only the beginning of bloat, considering I can't get away with a static address on *nix and have to dlinfo/dlsym modules etc. So it sucked.
This is so much better.
I believe you can use Mono.Cecil to do that but more easily.
Back when I was modding Planetbase, we did something similar to add event hooks to the game. I began to convert what I did for Planetbase to Rimworld, but since CCL already exists, I didn't continue.
The repo is available here. (https://github.com/Longwelwind/PhiScript) Basically, what it does is injecting MSIL code into the Assembly-CSharp.dll assembly to call the library that will load mods and offer them event hooks. It reads a XML file to know what kind of code to inject in the assembly. For example:
<Class Name="PlayDataLoader" Location="0">
<Method Name="LoadAllPlayData">
<Instruction OpCode="Call" Assembly="PhiScript" Type="PhiScript.Phi" Method="StaticLaunch" />
</Method>
</Class>
This configuration would inject a static call to a static method called "Phi" in a class called "PhiScript" in an assembly called "PhiScript" in the PlayDataLoader (one of the earliest called method in Rimworld), allowing me to catch this event and add behaviour for this.
The advantage of using Mono.Cecil is that it takes care of pretty much everything: calculating addresses, offsets, adding assemblies dependencies into the modified dependencies and such.
Cecil cannot patch assemblies at runtime. You can only get away with Cecil (and it works perfectly well) if you patch the assembly before loading it.
Anyway, we're beyond patching assemblies, we're patching native code here.
Quote from: Longwelwind on August 08, 2016, 08:39:23 AM
I believe you can use Mono.Cecil to do that but more easily.
Back when I was modding Planetbase, we did something similar to add event hooks to the game. I began to convert what I did for Planetbase to Rimworld, but since CCL already exists, I didn't continue.
The repo is available here. (https://github.com/Longwelwind/PhiScript) Basically, what it does is injecting MSIL code into the Assembly-CSharp.dll assembly to call the library that will load mods and offer them event hooks. It reads a XML file to know what kind of code to inject in the assembly. For example:
<Class Name="PlayDataLoader" Location="0">
<Method Name="LoadAllPlayData">
<Instruction OpCode="Call" Assembly="PhiScript" Type="PhiScript.Phi" Method="StaticLaunch" />
</Method>
</Class>
This configuration would inject a static call to a static method called "Phi" in a class called "PhiScript" in an assembly called "PhiScript" in the PlayDataLoader (one of the earliest called method in Rimworld), allowing me to catch this event and add behaviour for this.
The advantage of using Mono.Cecil is that it takes care of pretty much everything: calculating addresses, offsets, adding assemblies dependencies into the modified dependencies and such.
base files modifications is not allowed, read manual first.
So, thanks again, RawCode-sensei! It does work as expected.
Implemented like this so it should work on x64 out of the box (maybe will have to go with libmono instead of __Internal on *nix though):
[DllImport("__Internal")]
public static extern IntPtr mono_jit_info_table_find(IntPtr domain, IntPtr addr);
[DllImport("__Internal")]
public static extern IntPtr mono_domain_get();
[StructLayout(LayoutKind.Sequential)]
public struct MonoJitInfo
{
public IntPtr d;
public IntPtr n;
public IntPtr code_start;
public uint unwind_info;
public int code_size;
// The rest is omitted
}
var infoPtr = Platform.mono_jit_info_table_find(Platform.mono_domain_get(), targetPtr);
var ji = (Platform.MonoJitInfo)Marshal.PtrToStructure(infoPtr, typeof(Platform.MonoJitInfo));
Now I can finally get rid of terrible, terrible size scan code.
It's finished!
Tested on Windows, OSX, and Ubuntu x64 (and I assume x86 would work too). I also believe it's stable and reliable for most methods. Still can't hook into IEnumerable<> generators though.
It can also stack overrides on the same function multiple times (if multiple mods need to hook to the same thing), and correctly handles CCL-detoured methods, so you can hook to these too.
You need these files (these are direct links): HookInjector.cs (https://raw.githubusercontent.com/micktu/RimWorld-BuildProductive/injection/Source/HookInjector.cs) Platform.cs (https://raw.githubusercontent.com/micktu/RimWorld-BuildProductive/injection/Source/Platform.cs) AsmHelper.cs (https://raw.githubusercontent.com/micktu/RimWorld-BuildProductive/injection/Source/AsmHelper.cs) - they will be moved into master branch some time later.
Define your override:
internal static void PreLoadUtility_CheckVersionAndLoad(string path, ScribeMetaHeaderUtility.ScribeHeaderMode mode, Action loadAct)
{
Log.Message("!!! CheckVersionAndLoad");
PreLoadUtility.CheckVersionAndLoad(path, mode, loadAct);
}
And then hook it up:
HookPatcher = new HookInjector();
HookPatcher.Inject(typeof(PreLoadUtility), "CheckVersionAndLoad", typeof(VerseExtensions));
As you can see, if you don't specify the target method name, it defaults to YourClass.SourceClassName_SourceMethodName().
You don't need to create multiple injectors (although it won't break if you do), one is enough.
Interesting code.
It could use some polish and needs some work to match the coding style and structure before being added to CCL though.
I'm eager to see a complete working example. :)
>It could use some polish and needs some work to match the coding style and structure before being added to CCL though.
Nice joke, the polish and coding style of college students, right. Actually, you know what, don't touch the source code, I'll make it an assembly and you can use that if you wish.
>I'm eager to see a complete working example
So make it. Test it, mr. part of the community.
doh...
This is not about making blackbox assembly and giving it to other, it's about making code and explaining how it works, to allow other individuals to learn how it works.
In longrun, such activity will allow others to improve base work, just like it happened with my initial commit, improved by community to handle x64.
After researching changes, i managed to greatly improve base work, result is ABS hooks posted recently.
"Coding style" do matter, if base code implement "cryptic" features like indirect invocation, magic numbers, offsets instead of names, "var", "using" or homebrew lambdas.
Reason behind is simple - such code harder to understand and follow for others.
I have private builds that use "stuff" including "var" and 3 *random* letters as varname, but, i never post "raw" code on forum, because it looks like after obfuscation and impossible to follow.
Oh no no no, var is a production-quality blessing. I scold people for not using that, because BaseContainerInfoHandler baseContainerInfoHandler = new BaseContainerInfoHandler() is obviously fun and improves readability immensely. That's exactly why Java is unusable, as well as C++ before C++11.
I agree on everything else though, no magic number, no ambiguity. That thing was rewritten about 4 times, I'm sure every line is in its place besides a couple of line breaks and brackets. I went ways to actually make it clean and readable, and I'm satisfied with the result.
This is also the last time I argue about style.
Back on topic, what I overlooked is that you have to be able to Invoke() from inside of your stuff to call private base methods, but now you obviously end up in a stack overflow and crash. I'll make it do an extra check later.
After a little though I believe checking for Invoke wouldn't work, because there are other places that might want to Invoke your method if it's a delegate.
We need figure out a way to call private methods directly if possible, maybe through IL preprocessing. RawCode please try to think about it.
Or I'll make an alternative check that does not involve call stack. Someeting dumb like setting a flag when you enter your method and clearing it when you leave it. Not thread-safe of course.
So when I found out that on x64 stack alloc sometimes is a single instruction and can't be reliably replaced with a jump, I weighted different solutions and tried copying the whole method as a rescue. I assumed it's rare, and it was only small methods that can be this way and that it will work in most cases.
Turned out I was wrong, it's very common:
(http://take.ms/wXpm5)
And the methods can be huge:
(http://take.ms/YAFBX)
But the good news is that it works perfectly well. It is even is able to resolve its trampolines successfully in its new location (thanks mono programmers).
Unfortunately this won't work on x86 because of relative addressing that has to be handled, and that increases complexity too much to be nice. But then again, it's not a problem on x86 because I'm yet to see a stack alloc pattern that's shorter than 5 bytes.
By the way I'm still patching with relative jumps in x64 because the chances that memory pages will end up 2Gb apart are maybe one in a thousand years.
I never hit any issues with recursive calling, i need some kind of example to implement a fix.
Also stack allocation for methods is not issue at all, just like methods below 5 bytes.
You can change stack allocation for hooked methods, it does not matter as long as you restore stack pointer correctly before return, in other case runtime crash due to jump into invalid memory offset.
(return opcode is actually pop and jmp, call is push and jmp, i abused this feature to implement indirect invocation - last method of ABS hook)
Methods below 5 bytes ALWAYS inlined (only exception is noinline flag), you can't hook them anyway, ever if you manage to hook them, this won't have any effect with exception to reflection based invocations.
And yes, methods can be very large, especially methods with exception handling (also they have return opcode in unexpected locations)
>I never hit any issues with recursive calling, i need some kind of example to implement a fix.
It's obvious: I check for return address. If you Invoke, the return address is not the function you're checking against, but mono_runtime_invoke's address. Therefore your function gets called again and you crash with stack overflow.
>Also stack allocation for methods is not issue at all, just like methods below 5 bytes.
It's not, reliable detection of what can be copied and replaced is. It's not trivial unless you write your own disassembler thing to analyze the instructions. Which is a good solution, but it increases complexity manyfold.
>And yes, methods can be very large, especially methods with exception handling (also they have return opcode in unexpected locations)
What I meant is that I assumed that methods that do not make use of stack variables are usually small, and this turns out to not be true.
Anyway, the current working example is now up on workshop, imma cross my fingers and hope it works for everyone. The source is at https://github.com/micktu/RimWorld-BuildProductive (https://github.com/micktu/RimWorld-BuildProductive) if you want to take a look at usage.
Another problem I stumbled upon is that sometimes hooking into certain methods ends up in segfault on stack allocation for no apparent reason in random places within execution chain. E.g you can't hook to Designator.DesignateThing(), it's called from a Command's delegate, and I think it happens when the hooked method is called from within a delegate. Hope I arrive at a better explanation later. Ah, and it only happens with x64 compiler. I'll try some things like adding prolog to such functions, or maybe try to wrap them in a delegate of my own and see if it works.
QuoteIt's obvious: I check for return address. If you Invoke, the return address is not the function you're checking against, but mono_runtime_invoke's address. Therefore your function gets called again and you crash with stack overflow.
its your fault, same will happen if you manage to hook constructor or allocator, if pointer does not belong to managed method, you should not modify it.
So there have been dozens of new installs, and nobody complained yet, so I assume the method is working an stable. Feel free to use it people, it's the Injection folder in the repo.
I'll make it handle invokes properly later.