Running pawn on 32bit and 64bit systems.

251 views
Skip to first unread message

Peter Ward

unread,
Jan 7, 2015, 1:45:20 PM1/7/15
to pawns...@googlegroups.com

For people making the transition to 64 bit systems, I thought I would share my solution to this problem.

I use pawn scripts in my iOS apps.
With Apple's latest requirement to support 64bit aarch64 by Feb 1 2015, my pawn scripting system was causing a lot of worry.

It took about 3 days, but I am now running pawn scripts in 32bit mode ( cell size = 32bits ) on both 32bit and 64bit architectures.
This solution works best for me because I don't want to maintain 2 different compiled scripts (one with 32bit cells, and one with 64bit cells).  Also, 32bit cells work best for my tasks ( storing s32 or u32 or floats ).
The biggest problem I had to overcome was storing pointers in cells.  To solve this, I'm compressing 64bit pointers down into 32bits using this scheme ( http://www.codeproject.com/Articles/28818/bit-pointers-in-a-bit-world )

Overall, this is working great for me.  All my scripts are running perfectly in both 32bit or 64bit builds :)

I used 2 helper functions to encode/decode pointers:
MemEncodePointer:  Encodes a pointer into a u32. For 32bit systems, this is just a cast.
MemDecodePointer: Decodes a u32 into a pointer. For 32bit systems, this is just a cast.


A few changes were also required to amx.c

This line: (amx_Callback)
    f=(AMX_NATIVE)func->address;
Becomes:
    f=(AMX_NATIVE)MemDecodePointer(func->address);

This line: (amx_Init)
      lib->address=(ucell)hlib;
Becomes:
      lib->address=(ucell)MemEncodePointer(hlib);

This line: ( amx_Register)
        func->address=(ucell)funcptr;
Becomes:
        func->address=(ucell)MemEncodePointer(funcptr);




Also, any calls to native functions which allocate objects, or return allocated objects to the script language, or pass allocated objects to native function,  must also encode pointers.

For example. A function I have:

// GUI_Base * GUIRoot_FindChild( gui *, childName[] );
static cell AMX_NATIVE_CALL n_GUIRoot_FindChild(AMX *amx, const cell *params)
{
    GUI * gui = (GUI*)params[1];
    char name[ 64 ];
    amx_GetString( name, (cell*)params[2], 0, 64);
    return (cell)gui->FindChild( name );
}

Becomes:

// GUI_Base * GUIRoot_FindChild( gui *, childName[] );
static cell AMX_NATIVE_CALL n_GUIRoot_FindChild(AMX *amx, const cell *params)
{
    GUI * gui = (GUI*) MemDecodePointer(params[1]); // decode a u32 into a pointer
    char name[ 64 ];
    amx_GetString( name, amx_Address(amx,params[2]), 0, 64);
    return (cell)  MemEncodePointer(gui->FindChild(name));
}

Jason Peterson

unread,
Apr 21, 2017, 2:28:27 PM4/21/17
to Pawn Scripting Language
Hi Peter, 

Thanks for the post, I know it is old but I am working with a similar issue.  Would you post your MemDecodePointer and MemEncodePointer functions?

Thanks,

--Jason

Peter Ward

unread,
Feb 14, 2018, 9:49:50 AM2/14/18
to Pawn Scripting Language
Sure. Sorry for long delay.  I don't check these groups frequently.

// assumes all memory addresses are 4byte aligned.
static inline void * MemDecodePointer(u32 e)
{
#ifdef __LP64__
uintptr_t ptr = (uintptr_t)e << 2;
return (void*)ptr;
#else
return (void*)e;
#endif
}

static inline u32 MemEncodePointer(void *ptr)
{
#ifdef __LP64__
  uintptr_t e = (uintptr_t)ptr >> 2;
  return (u32)e;
#else
return (u32)ptr;
#endif
}
Reply all
Reply to author
Forward
0 new messages