Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# ../data/source-python/entity_output/orangebox/hl2mp/CBaseEntityOutput.ini

[function]
[[fire_output]]
identifier_linux_x86_64 = 55 48 89 E5 41 57 41 56 41 55 41 54 53 48 81 EC 2A 2A 2A 2A 4C 8B 7F 18
16 changes: 14 additions & 2 deletions addons/source-python/packages/source-python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ def setup_data():
from memory.manager import manager
from paths import SP_DATA_PATH

try:
from _entities import _global_entity_list
except ImportError:
pass
else:
manager.global_pointers.setdefault(
'CGlobalEntityList', _global_entity_list)
manager.global_pointers.setdefault(
'GlobalEntityList', _global_entity_list)

import players
players.BaseClient = manager.create_type_from_dict(
'BaseClient',
Expand Down Expand Up @@ -450,6 +460,7 @@ def setup_versioning():
# =============================================================================
def setup_sqlite():
"""Pre-load libsqlite3.so.0 on Linux."""
from core import ARCHITECTURE
from core import PLATFORM
if PLATFORM != 'linux':
return
Expand All @@ -463,8 +474,9 @@ def setup_sqlite():
# version installed. This fixes the issue by loading the library into the
# memory using its absolute path.
# Using RPATH might be a better solution, but I don't get it working...
platform_dir = 'plat-linux64' if ARCHITECTURE == 'x86_64' else 'plat-linux'
ctypes.cdll.LoadLibrary(
BASE_PATH / 'Python3/plat-linux/libsqlite3.so.0')
BASE_PATH / 'Python3' / platform_dir / 'libsqlite3.so.0')


# =============================================================================
Expand Down Expand Up @@ -525,4 +537,4 @@ def flush(self):
'https://github.com/Source-Python-Dev-Team/Source.Python/issues/175. '
'Source.Python should continue working, but we would like to figure '
'out in which situations sys.stdout is None to be able to fix this '
'issue instead of applying a workaround.')
'issue instead of applying a workaround.')
4 changes: 3 additions & 1 deletion addons/source-python/packages/source-python/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
# >> ALL DECLARATION
# =============================================================================
__all__ = ('AutoUnload',
'ARCHITECTURE',
'BoostPythonClass',
'ConfigFile',
'GameConfigObj',
Expand Down Expand Up @@ -94,6 +95,7 @@

# Get the platform the server is on
PLATFORM = system().lower()
ARCHITECTURE = 'x86_64' if sys.maxsize > 2 ** 32 else 'x86'


# =============================================================================
Expand Down Expand Up @@ -438,4 +440,4 @@ def check_info_output(output):
if lines[-1].startswith('-'):
lines.pop()

return create_checksum(''.join(lines)) != checksum
return create_checksum(''.join(lines)) != checksum
22 changes: 15 additions & 7 deletions addons/source-python/packages/source-python/listeners/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,14 +694,22 @@ def _pre_fire_output(args):
# To remind us to add newly supported engines...
raise NotImplementedError('No hibernation function exposed.')

@PreHook(get_virtual_function(server_game_dll, _hibernation_function_name))
def _pre_hibernation_function(stack_data):
"""Called when the server is hibernating."""
if not stack_data[1]:
return
try:
_hibernation_function = get_virtual_function(
server_game_dll, _hibernation_function_name)
_hibernation_hook = PreHook(_hibernation_function)
except (OSError, ValueError) as error:
from warnings import warn
warn('Unable to install the hibernation hook: {0}'.format(error))
else:
@_hibernation_hook
def _pre_hibernation_function(stack_data):
"""Called when the server is hibernating."""
if not stack_data[1]:
return

# Disconnect all bots...
_disconnect_bots()
# Disconnect all bots...
_disconnect_bots()


@OnLevelEnd
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

# Source.Python
# Core
from core import ARCHITECTURE
from core import PLATFORM
# Memory
from memory import Convention
Expand Down Expand Up @@ -392,7 +393,9 @@ def parse_data(manager, raw_data, keys):
for key, converter, default in keys:
# Get the OS specific key. If that fails, fall back to the shared
# key. If that fails too, use the default value
value = data.get(key + '_' + PLATFORM, data.get(key, default))
value = data.get(
key + '_' + PLATFORM + '_' + ARCHITECTURE,
data.get(key + '_' + PLATFORM, data.get(key, default)))

# If the value is NO_DEFAULT, the key is obviously missing
if value is NO_DEFAULT:
Expand Down
5 changes: 5 additions & 0 deletions addons/source-python/packages/source-python/memory/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,10 +771,15 @@ def create_global_pointers_from_file(self, f):

# Create the global pointer objects
for name, data in pointers:
if name in self.global_pointers:
continue
cls = self.get_class(name)
if cls is None:
raise NameError('Unknown class "{0}".'.format(name))

if cls.__name__ in self.global_pointers:
self.global_pointers[name] = self.global_pointers[cls.__name__]
continue
self.global_pointer(cls, *data)

def get_global_pointer(self, name):
Expand Down
52 changes: 52 additions & 0 deletions docs/linux-x86_64.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Linux x86-64 (HL2DM)

Linux x86-64 support is currently limited to the `hl2dm` branch. The existing
x86 build remains the default.

Build with:

```sh
cd src
./Build.sh hl2dm x86_64
```

The preserved 32-bit build remains available as:

```sh
cd src
./Build.sh hl2dm x86
```

The build accepts `SOURCEPYTHON_SDK` as a CMake cache path when the HL2SDK is
outside `src/hl2sdk/hl2dm`.

Architecture-specific dependencies are kept beside, rather than in place of,
the existing x86 dependencies:

```text
thirdparty/python_linux64/
thirdparty/boost/lib/linux64/
thirdparty/dyncall/lib/linux64/
thirdparty/DynamicHooks/lib/linux64/
thirdparty/AsmJit/lib/linux64/
```

The tested dependency baseline is CPython 3.13.2, Boost 1.87, the current
HL2DM branch of AlliedModders HL2SDK, and a DynamicHooks build containing the
Linux System V AMD64 backend.

The packaged runtime uses `Python3/plat-linux64`. Native optional packages in
the standard library are loaded from `Python3/lib-dynload-linux64`, leaving the
existing x86 `Python3/lib-dynload` directory untouched. Native optional
packages in the shared `site-packages` directory must be rebuilt for x86-64;
32-bit extension modules cannot be imported by the x86-64 runtime.

Post-hook callbacks that need function arguments must select the preserved
entry-register snapshot through `CHook::SetUsePreRegisters`. The legacy
`m_bUsePreRegisters` member remains available to the x86 backend, but it is not
the invocation-local selector used by the reentrant x86-64 backend.

The upstream x86 CPython `_ctypes` module still declares `libffi.so.7` as a
runtime dependency. Distributions that no longer provide that SONAME must
supply it separately for 32-bit deployments. This legacy dependency is not
used by the x86-64 `_ctypes` module and was not introduced by this port.
14 changes: 10 additions & 4 deletions src/Build.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env sh
#!/usr/bin/env bash

# Store the start directory for later reference
STARTDIR="$PWD"
Expand Down Expand Up @@ -131,14 +131,14 @@ CreateBuild () {
cd "$STARTDIR"

# Set the branch's build directory
BUILDDIR="$STARTDIR/Builds/Linux/$BRANCH"
BUILDDIR="$STARTDIR/Builds/Linux/$BRANCH-$ARCH"

# Does the build directory exist (make it if not)?
if [ ! -d "$BUILDDIR" ]; then
mkdir -p "$BUILDDIR"
fi

cmake . -B"$BUILDDIR" -DBRANCH=$BRANCH
cmake . -B"$BUILDDIR" -DBRANCH=$BRANCH -DSOURCEPYTHON_ARCH=$ARCH

# Navigate to the ../Builds/<Branch> directory
cd "$BUILDDIR"
Expand All @@ -152,7 +152,13 @@ CreateBuild () {
test ${PIPESTATUS[0]} -eq 0

}
if [ "$#" -eq "1" ]; then
ARCH=${2:-x86}
if [ "$ARCH" != "x86" ] && [ "$ARCH" != "x86_64" ]; then
echo "Usage: $0 [branch] [x86|x86_64]"
exit 2
fi

if [ "$#" -ge "1" ]; then
BRANCH=$1
CloneRepo
else
Expand Down
12 changes: 12 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@
CMake_Minimum_Required(VERSION 3.15)
project(source-python)

Set(SOURCEPYTHON_ARCH "x86" CACHE STRING "Target architecture (x86 or x86_64)")
Set_Property(CACHE SOURCEPYTHON_ARCH PROPERTY STRINGS x86 x86_64)
If(NOT SOURCEPYTHON_ARCH MATCHES "^(x86|x86_64)$")
Message(FATAL_ERROR "SOURCEPYTHON_ARCH must be x86 or x86_64")
EndIf()
If(SOURCEPYTHON_ARCH STREQUAL "x86_64")
If(NOT UNIX OR NOT BRANCH STREQUAL "hl2dm")
Message(FATAL_ERROR "x86_64 is currently supported only for Linux HL2DM")
EndIf()
Add_Definitions(-DSOURCEPYTHON_X86_64)
EndIf()

# ------------------------------------------------------------------
# Makefile includes.
# ------------------------------------------------------------------
Expand Down
19 changes: 18 additions & 1 deletion src/core/modules/memory/memory_function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@
#include "memory_wrap.h"

// DynamicHooks
#ifdef SOURCEPYTHON_X86_64
#include "conventions/x64GccSystemV.h"
#else
#include "conventions/x86MsCdecl.h"
#include "conventions/x86MsThiscall.h"
#include "conventions/x86MsStdcall.h"
#include "conventions/x86MsFastcall.h"
#include "conventions/x86GccCdecl.h"
#include "conventions/x86GccThiscall.h"
#endif

// Source.Python
#include "utilities/call_python.h"
Expand Down Expand Up @@ -71,11 +75,15 @@ int GetDynCallConvention(Convention_t eConv)
case CONV_CUSTOM: return -1;
case CONV_CDECL: return DC_CALL_C_DEFAULT;
case CONV_THISCALL:
#ifdef SOURCEPYTHON_X86_64
return DC_CALL_C_DEFAULT;
#else
#ifdef _WIN32
return DC_CALL_C_X86_WIN32_THIS_MS;
#else
return DC_CALL_C_X86_WIN32_THIS_GNU;
#endif
#endif
#ifdef _WIN32
case CONV_STDCALL: return DC_CALL_C_X86_WIN32_STD;
case CONV_FASTCALL: return DC_CALL_C_X86_WIN32_FAST_MS;
Expand All @@ -92,6 +100,14 @@ int GetDynCallConvention(Convention_t eConv)
// ============================================================================
ICallingConvention* MakeDynamicHooksConvention(Convention_t eConv, std::vector<DataType_t> vecArgTypes, DataType_t returnType, int iAlignment)
{
#ifdef SOURCEPYTHON_X86_64
switch (eConv)
{
case CONV_CDECL:
case CONV_THISCALL:
return new x64GccSystemV(vecArgTypes, returnType, iAlignment);
}
#else
#ifdef _WIN32
switch (eConv)
{
Expand All @@ -106,6 +122,7 @@ ICallingConvention* MakeDynamicHooksConvention(Convention_t eConv, std::vector<D
case CONV_CDECL: return new x86GccCdecl(vecArgTypes, returnType, iAlignment);
case CONV_THISCALL: return new x86GccThiscall(vecArgTypes, returnType, iAlignment);
}
#endif
#endif

BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Unsupported calling convention.")
Expand Down Expand Up @@ -483,4 +500,4 @@ void CFunction::DeleteHook()
// Set the calling convention to NULL, because DynamicHooks will delete it otherwise.
pHook->m_pCallingConvention = NULL;
GetHookManager()->UnhookFunction((void *) m_ulAddr);
}
}
12 changes: 12 additions & 0 deletions src/core/modules/memory/memory_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,33 @@ class CStackData

void* GetReturnAddress()
{
#ifdef SOURCEPYTHON_X86_64
return m_pHook->GetCurrentReturnAddress();
#else
void* pESP = m_pHook->GetRegisters()->m_esp->GetValue<void*>();
if (m_pHook->m_RetAddr.count(pESP) == 0) {
return NULL;
}
return m_pHook->m_RetAddr[pESP].back();
#endif
}

bool GetUsePreRegister()
{
#ifdef SOURCEPYTHON_X86_64
return m_pHook->GetUsePreRegisters();
#else
return m_pHook->m_bUsePreRegisters;
#endif
}

void SetUsePreRegisters(bool value)
{
#ifdef SOURCEPYTHON_X86_64
m_pHook->SetUsePreRegisters(value);
#else
m_pHook->m_bUsePreRegisters = value;
#endif
}

protected:
Expand Down
Loading