I don't think that's my problem (they were already being called with this->). Both of my detours work flawlessly on Windows (well at least Pl_Continue or Pl_Handled)
The problem is that on Linux, UseHealingItems is not a _thiscall (actually it probably is, GCC just implements thiscall differently from Windows). In fact, it's not any calling convention I've ever seen before. IDA incorrectly labels Linux's UseHealingItems as _fastcall, because it has three args and RETN 4 - but none of the args are passed through ecx:edx, all three are passed on the stack. The RETN 4 is definitely unnecessary, because there's a SUB esp, 4 just after each call to compensate - and only in Linux. And only for this one forward (UseHealingItems). I checked CThrow::ActivateAbility in Linux and it does not do this unnecessary RETN 4.
EDIT: I mentioned above that I checked Martijn's .so. The UseHealingItems detour does not do the RETN 4 that Linux's UseHealingItems does. And it does not SUB esp, 4 after the trampoline, like every other caller to UseHealingItems. This will undoubtedly corrupt the stack.
I also checked my FindScavengeItem forward, and I believe it would probably work on Linux just fine, since FindScavengeItem does not do the unnecessary RETN 4. But I have no Linux server to test this stuff on, nor do I have a Linux environment set up to build the extension.
EDIT2: I saw you just checked in a change to UseHealingItems. That was my original detour when I first wrote it. I got the names wrong on the arguments and only found out recently what that mysterious last argument was - I'm pretty sure it's the hidden struct returned-by-value that psychonic was talking about - but without that extra argument you will crash the server (trust me, I tried this on Windows for a few days before I would commit the source code changes). Windows UseHealingItems does a RETN 8, which with _thiscall means two args + thisptr. If you only provide one arg + thisptr, you will do RETN 4 at the end of your detour and corrupt the stack for the caller (RETN clears off the stack *after* popping into eip, so the caller's stack frame will by off by one push)
EDIT3: It seems that functions which return an Action<> in general have this awkward RETN 4 pattern with the hidden struct pointer. For example, SurvivorBot::ScavengeNearbyItems(float) is the same and it's called in the same places as UseHealingItems. I checked other forwards and they don't have this RETN 4 thing - seems like they all use plain old RET.
EDIT4: Eureka? psychonic had said, if you return a struct by value, the compiler will generate the same code on both platforms. I had originally thought of this in the neutral context of "random app I wrote"...but then I realized, my OnUseHealingItems forward was returning a void*! So the compiler saw no reason to do the fancy hidden struct pointer stuff.Therefore , I think what I should do instead is change the return type from void* to some struct I wrote (NOT pointer) which contains the same three fields as an Action in the SDK. And then I can return this struct by value and, hopefully, my assembly will look the same on both platforms, and I can get rid of that weird unused argument at last!
EDIT5: Making the detour return a struct-by-value seems to have worked. I no longer crash with one argument on Windows, and the disassembly looks correct. However, I have no build environment for Linux; if someone could get the latest source from google code and build the .so, I'll take a peek at it with IDA to see if it looks compatible with the Linux server.
EDIT6: Disawar compiled the Linux binary for me and I poked at it with IDA. Everything looks good! I'm seeing the awkward RETN 4 stuff at the end of my detour, and after I invoke the trampoline I see a SUB esp, 4. So I think the current source from Google Code should work for Linux now. Many thanks to psychonic for the tip about returning the struct-by-value.
__________________
Last edited by dcx2; 08-01-2013 at 19:50.
|