Skip to content

Commit 9fe3327

Browse files
committed
Little styling fixes
1 parent d434a17 commit 9fe3327

File tree

1 file changed

+10
-6
lines changed

1 file changed

+10
-6
lines changed

jekyll/_posts/2018-03-12-steam-api-calls-forwarding.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,14 @@ Judging by the log, our wrapper works (!) exactly until the function `SteamInter
4848

4949
I think that those who are familiar with ABI C ++ already understand the crash origin. The root of the problem is the calling conventions. The C ++ standard does not imply the binary compatibility of programs compiled by different compilers, and in our case the Windows game is compiled by MSVC, while native Steam - by GCC. This problem is not observed for all calls to functions in `steam_api.dll` since they follow the calling conventions for the C language. Once a game receives an instance of the `SteamClient` class from the native Steam and tries to invoke its method (which follows the thiscall convention from C++), an error occurs. To fix the problem, we firstly need to identify key differences in the thiscall calling convention for both of compilers.
5050

51-
MSVC | GCC
52-
---------|--------
53-
Puts an object pointer to the ECX register. | Expects an object pointer on top of the stack.
54-
Expects the stack cleanup by callee. | Expects the stack cleanup by caller.
51+
<table style="width:100%;border:1px solid black; text-align:center;">
52+
<tr><th>MSVC</th><th>GCC</th></tr>
53+
<hline />
54+
<tr><td>Puts an object pointer to the ECX register</td>
55+
<td>Expects an object pointer on top of the stack</td></tr>
56+
<tr><td>Expects the stack cleanup by callee</td>
57+
<td>Expects the stack cleanup by caller</td></tr>
58+
</table>
5559

5660
[[source](http://www.angelcode.com/dev/callconv/callconv.html#thiscall)]
5761

@@ -248,12 +252,12 @@ It does not look very simple, but it's only because we swung a lot at once. Ther
248252

249253
Now let's go to the most delicious part - to the code generation. Since we do not have complete information about method signatures, we will emulate instances of classes in C code, fortunately we only need to emulate the virtual method table. So, let's imagine that we have a file that describes the methods and classes of the Steam API as follows:
250254

251-
<pre>
255+
```
252256
!CAdapterSteamYYY0XX
253257
[+]<the stack depth for the first method>
254258
[+]<the stack depth for the second method>
255259
...
256-
</pre>
260+
```
257261

258262
The `+` sign is optional and will serve as an indicator of the hidden argument for the in-memory return.
259263
Such a file can be obtained by parsing `steamclient.so`. We should get a table from it. The keys of the table are lines following the `CAdapterSteamYYYY0XX` pattern, and the values are arrays of functions that call corresponding methods in the object, which is the field of the wrapper structure implicitly passed to them via the `ECX` register. It is not very convenient to write all this methods in assembler, especially considering that it would be nice to add some kind of journaling, so let's find the minimum assembler fragment:

0 commit comments

Comments
 (0)