Porting to x64
Contents
Overview
Many plugins are already compatible with the x64 architecture, but many that manipulate game memory (such as with hooks or patches) will require extensive revisions to run under the new 64-bit servers. Overall, if your plugin:
- Uses the address natives or the Address type,
- Uses dhooks
- Uses sdkcalls or sdktools (not sdkhooks)
...you will need to update your plugin for 64 bits.
Extensions may be good to go with just a recompile for 64-bits, but some may need more extensives changes.
I'm having an issue!
In general, prototypes need to be exactly correct (including class statics like copy/destruct/constructors) as there are now significantly more quirks that will cause ABIs to be laid out differently.
Here are some things to check for that may be tripping you up:
- The type you thought was an int was actually a size_t!
- The type you put down as an int or pointer was actually a float!
- Handling pointers as ints when they should be void* or size_t (why would you do this??)
- The calling convention has changed. Make sure to account for this in detours and patches. Make sure your prototypes are exactly correct!
- In patches: Did you forget the 64-bit opcode prefix when assembling your patch? EAX and RAX are accessed using different opcode prefixes!
Linux Calling Convention Quirks
Linux uses the System-V x64 ABI. There are many great sources of documentation all over the internet: OSDev Wiki Wikipedia
- All calling conventions are now an up to 8-register fastcall depending on the types (!!)
- RCX can be a thisptr, first argument, or stack return pointer depending on the context
- Integer arguments and float arguments are passed in different registers! (generic for ints, SIMD registers for floats)
- Varargs are now more complex to call when floats are included in the vararg
The exact value of return types with C++ shenanigans (destructors, etc) still needs to be figured out by someone. However, in general.
- The return argument is always passed in RCX, and will bump the thisptr to RDX (todo: confirm this)
- Some return types that are 128-bits will be returned in both RAX and RDX??
MSVC Calling Convention Quirks
Microsoft has some excellent official documentation in their MSVC docs.
- All calling conventions are now a four-register fastcall
- RCX can be a thisptr OR the first arg! It is not always a thisptr now. RCX can also be the return value (see below), bumping the thisptr to RDX.
- Integer arguments and float arguments are passed in different registers! (generic for ints, SIMD registers for floats)
- All objects larger than 8 bytes are now passed exclusively by reference (even on the stack??)
- Float arguments passed to varargs need to be put in both the generic and SIMD register for the appropiate argument index. Varargs are still fastcalls... somehow...
- setjmp has new behavior and destroys objects as if the scope has been exited. (if you are using setjmp, good luck)
Return types also have their usual obscure shenanigans. More specifically,
- The return argument is always passed in RCX, and will bump the thisptr to RDX (todo: confirm this)
- Returns with all types larger than 8 bytes occur on the stack
- Returns with any type that has a user-defined base classes, virtual methods, constructor, destructor, or copy operation happens on the stack (regardless of size)
Porting Plugins
Gamedata
All signatures will need to be updated, and likely many offsets.
Gamedata key names
Arch/OS | Linux | Windows |
---|---|---|
x86 | linux | windows |
x64 | linux64 | windows64 |
Address Natives
New address natives that support 64-bits are still under development
DHooks
DHooks does not support 64-bits at all for the time being. It will need heavy revisions to work under the new architecture, starting with better SourceHook support for the 64-bit architecture (see: hookmangen)
SDKCalls
SDKCalls will need to be updated to learn how to accept a thisptr. However, all non-raw calls (eg, those to entities or gamerules that does not require a thisptr) should be fine as long as none of the arguments are 64-bits (including 64-bit ints!)