Page 2 of 2 FirstFirst 12
Results 26 to 30 of 30

Thread: Export strings to pascal

  1. #26
    Join Date
    Nov 2011
    Location
    England
    Posts
    3,066
    Mentioned
    290 Post(s)
    Quoted
    1088 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    So you bypass FFI by exporting the method with Params array and Results array? Looks similar to how Simba exports its internal functions. :O Actually didn't know you could do that..
    Bypass FFI by appending the method header with "native" then it will use the default importing system.

    https://github.com/nielsAD/lape/blob...types.pas#L145
    https://github.com/MerlijnWajer/Simb...read.pas#L1623

  2. #27
    Join Date
    Jul 2009
    Posts
    125
    Mentioned
    2 Post(s)
    Quoted
    54 Post(s)

    Default



    What is going on here, some kind of error huh.

  3. #28
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,590
    Mentioned
    395 Post(s)
    Quoted
    1595 Post(s)

    Default

    Quote Originally Posted by alar82 View Post


    What is going on here, some kind of error huh.
    As the author of this code, you need to use `regparm` which is only available in GCC, G++, Clang, Clang++.. Visual Studio does NOT support it..

    So to fix this, you need to IFDEF that code for visual studio but then also use:

    cpp Code:
    #ifndef TMEMORYMANAGER_HXX_INCLUDED
    #define TMEMORYMANAGER_HXX_INCLUDED

    #if !defined(_MSC_VER)
    #define DELPHI_CALLING_CONVENTION __attribute__((regparm(3)))

    typedef struct
    {
        std::uint32_t TotalAddressSpace;
        std::uint32_t TotalUncommited;
        std::uint32_t TotalCommited;
        std::uint32_t TotalAllocated;
        std::uint32_t TotalFree;
        std::uint32_t FreeSmall;
        std::uint32_t FreeBig;
        std::uint32_t Unused;
        std::uint32_t Overhead;
        std::uint32_t HeapErrorCode;
    } THeapStatus;

    typedef struct
    {
        std::uintptr_t MaxHeapSize;
        std::uintptr_t MaxHeapUsed;
        std::uintptr_t CurrHeapSize;
        std::uintptr_t CurrHeapUsed;
        std::uintptr_t CurrHeapFree;
    } TFPCHeapStatus;

    typedef struct
    {
        bool NeedLock;
        void* (*GetMem)(std::intptr_t size) DELPHI_CALLING_CONVENTION;
        std::intptr_t (*FreeMem)(void* &ptr) DELPHI_CALLING_CONVENTION;
        std::intptr_t (*FreeMemSize)(void* &ptr, std::intptr_t size) DELPHI_CALLING_CONVENTION;
        void* (*AllocMem)(std::intptr_t size) DELPHI_CALLING_CONVENTION;
        void* (*ReAllocMem)(void* &ptr, std::intptr_t size) DELPHI_CALLING_CONVENTION;
        std::intptr_t (*MemSize)(void* ptr) DELPHI_CALLING_CONVENTION;

        void (*InitThread)() DELPHI_CALLING_CONVENTION;
        void (*DoneThread)() DELPHI_CALLING_CONVENTION;
        void (*RelocateHeap)() DELPHI_CALLING_CONVENTION;
        THeapStatus (*GetHeapStatus)() DELPHI_CALLING_CONVENTION;
        TFPCHeapStatus (*GetFPCHeapStatus)() DELPHI_CALLING_CONVENTION;
    } TMemoryManager;


    typedef struct
    {
        bool NeedLock;
        void* (*GetMem)(std::intptr_t size) DELPHI_CALLING_CONVENTION;
        std::intptr_t (*FreeMem)(void* &ptr) DELPHI_CALLING_CONVENTION;
        std::intptr_t (*FreeMemSize)(void* &ptr, std::intptr_t size) DELPHI_CALLING_CONVENTION;
        void* (*AllocMem)(std::intptr_t size) DELPHI_CALLING_CONVENTION;
        void* (*ReAllocMem)(void* &ptr, std::intptr_t size) DELPHI_CALLING_CONVENTION;
        std::intptr_t (*MemSize)(void* ptr) DELPHI_CALLING_CONVENTION;

        void (*InitThread)() DELPHI_CALLING_CONVENTION;
        void (*DoneThread)() DELPHI_CALLING_CONVENTION;
        void (*RelocateHeap)() DELPHI_CALLING_CONVENTION;
        THeapStatus (*GetHeapStatus)() DELPHI_CALLING_CONVENTION;
        TFPCHeapStatus (*GetFPCHeapStatus)() DELPHI_CALLING_CONVENTION;
    } __attribute__((__packed__)) TCMemoryManager;
    #endif


    typedef struct
    {
        void (__cdecl *Sync)(void(__cdecl *synchronize_method)(void*), void* data);
    } __attribute__((__packed__)) TSimbaMethods;


    typedef struct
    {
        void* (__cdecl *GetMem)(std::size_t size);
        void (__cdecl *FreeMem)(void* ptr);
    } __attribute__((__packed__)) TSimbaMemoryAllocators;

    #endif // TMEMORYMANAGER_HXX_INCLUDED

    Then you have to do:

    cpp Code:
    #if !defined(_MSC_VER)
    TMemoryManager PLUGIN_MEMORY_MANAGER = {0};
    #endif

    TSimbaMethods PLUGIN_SYNC_METHODS = {0};
    TSimbaMemoryAllocators PLUGIN_MEMORY_ALLOCATORS = {0};

    #if !defined(_MSC_VER)
    void SetPluginMemManager(TMemoryManager MemMgr)
    {
        PLUGIN_MEMORY_MANAGER = MemMgr;
    }
    #endif

    void SetPluginSimbaMethods(TSimbaMethods Methods)
    {
        PLUGIN_SYNC_METHODS = Methods;
    }

    void SetPluginSimbaMemoryAllocators(TSimbaMemoryAllocators Allocators)
    {
        PLUGIN_MEMORY_ALLOCATORS = Allocators;
    }

    Then to allocate a string or array, I do:

    cpp Code:
    typedef struct
    {
        std::make_signed_t<std::size_t> refCount;
        std::make_signed_t<std::size_t> length;
        char data[];
    } __attribute__((__packed__)) PascalArray;

    #if defined(FPC2)
    typedef struct
    {
        std::make_signed_t<std::size_t> refCount;
        std::make_signed_t<std::size_t> length;
        char data[];
    } __attribute__((__packed__)) PascalString;
    #else
    typedef struct
    {
        std::uint16_t codePage;
        std::uint16_t elementSize;
        #if defined(__x86_64__)
        std::uint32_t dummy;
        #endif
        std::make_signed_t<std::size_t> refCount;
        std::make_signed_t<std::size_t> length;
        char data[];
    } __attribute__((__packed__)) PascalString;
    #endif // defined



    template<typename T, std::size_t size>
    struct __attribute__((__packed__)) StaticPascalArray
    {
        const std::make_signed_t<std::size_t> refCount = -1;
        const std::make_signed_t<std::size_t> length = size;
        T data[size] = {0};
    };

    template<typename T>
    int PascalHigh(T* Arr)
    {
        return reinterpret_cast<int*>(Arr)[-1];
    }

    template<typename T>
    int PascalLength(T* Arr)
    {
        return PascalHigh<T>(Arr) + 1;
    }

    template<typename T>
    T* AllocateArray(std::size_t size, std::size_t element_size = sizeof(T))
    {
        std::size_t new_size = (size * element_size) + sizeof(PascalArray);
        #if !defined(_MSC_VER)
        PascalArray* ptr = static_cast<PascalArray*>(PLUGIN_MEMORY_MANAGER.AllocMem(new_size));
        #else
        PascalArray* ptr = static_cast<PascalArray*>(PLUGIN_MEMORY_ALLOCATORS.GetMem(new_size));
        #endif
        ptr->refCount = 1;
        ptr->length = size - 1;
        return reinterpret_cast<T*>(++ptr);
    }

    template<typename T>
    T* AllocateString(std::size_t size, std::size_t element_size = sizeof(T))
    {
        std::size_t new_size = (size * element_size) + sizeof(PascalString);
        #if !defined(_MSC_VER)
        PascalString* ptr = static_cast<PascalString*>(PLUGIN_MEMORY_MANAGER.AllocMem(new_size + 1));
        #else
        PascalString* ptr = static_cast<PascalString*>(PLUGIN_MEMORY_ALLOCATORS.GetMem(new_size + 1));
        #endif
        ptr->refCount = 1;
        ptr->length = size;
        return reinterpret_cast<T*>(++ptr);
    }

    template<typename T>
    T* GetArray(void* ptr, std::size_t* size)
    {
        PascalArray* mem = static_cast<PascalArray*>(ptr);
        return reinterpret_cast<T*>((--mem)->data);
    }

    template<typename T>
    T* GetString(void* ptr)
    {
        PascalString* mem = static_cast<PascalString*>(ptr);
        return reinterpret_cast<T*>((--mem)->data);
    }


    Usage then becomes:

    cpp Code:
    int* IntArray = AllocateArray(100); //equivalent to SetLength(TIntegerArray, 100);
    char* CharArray = AllocateArray(100); //equivalent to SetLength(TCharArray, 100);

    char* StrArray = AllocateString(5);  //Allocates a string of length 5 in pascal.
    strcpy(StrArray, "Hello");

    //Array of array:
    int** Array2D = AllocateArray(4, sizeof(int)); //explicitly specify we want an array of array of integers (in this example, 4 x 5).
    for (int i = 0; i < 4; ++i)
    {
        Array2D[i] = AllocateArray(5);
        Array2D[i][0] = 1;
        Array2D[i][1] = 2;
        Array2D[i][2] = 3;
        Array2D[i][3] = 4;
        Array2D[i][4] = 5;  //Can also use memcpy or memset to set values..
    }

    //Alternatively:
    Array2D[0][0] = 0;
    Array2D[0][1] = 1;
    Array2D[0][2] = 2;
    //etc..

    Array2D[1][0] = 0;
    Array2D[1][1] = 1;
    Array2D[1][2] = 2;
    //etc..

    Array2D[2][0] = 0;
    Array2D[2][1] = 1;
    Array2D[2][2] = 2;
    //etc..

    You can always specialize the template to allocate array of arrays without specifying `sizeof(whateverType)` by doing: `sizeof(typename std::remove_pointer<T>::type)` instead.. but that's for another day.. Too lazy and most of my code works with this already so..


    To export functions, I use Simba's "NATIVE" keyword:

    cpp Code:
    static const char* PascalExports[] =
    {
        "SomeFunc", "Function SomeFunc(A: Int32; B: String; C: Char): Boolean; native;"
    }

    void SomeFunc(void** Params, void** Result)
    {
        int32_t A = ReadPointer(Params[0]);  //*static_cast<int32_t*>(Params[0])
        char* B = ReadPointer(Params[1]);    //*static_cast<char**>(Params[1])
        char C = ReadPointer(Params[2]);     //*static_cast<char*>(Params[2])

        WritePointer(Result, true);  //*static_cast<bool*>(Result) = true;
    }
    Last edited by Brandon; 01-31-2020 at 05:41 PM.
    I am Ggzz..

  4. #29
    Join Date
    Jul 2009
    Posts
    125
    Mentioned
    2 Post(s)
    Quoted
    54 Post(s)

    Default

    Code:
    if !defined(_MSC_VER)
    #define DELPHI_CALLING_CONVENTION __attribute__((regparm(3)))
    
    #endif
    Between those lines code is grayed out and then goes into red again. Do I have to do something extra?

  5. #30
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,590
    Mentioned
    395 Post(s)
    Quoted
    1595 Post(s)

    Default

    Quote Originally Posted by alar82 View Post
    Code:
    if !defined(_MSC_VER)
    #define DELPHI_CALLING_CONVENTION __attribute__((regparm(3)))
    
    #endif
    Between those lines code is grayed out and then goes into red again. Do I have to do something extra?

    It's greyed out on purpose because you won't be able to use those structs UNLESS you write assembly to call the functions using the `regparm` calling convention..

    So the code that's "outside" of the IFDEF is the new code to use. @Olly; exported it for us to use without having to use `TMemoryManager`.

    IE: https://github.com/MerlijnWajer/Simb...ment-436310146

    The code outside of that is using this.. instead of the TMemoryManager when it's available.
    I am Ggzz..

Page 2 of 2 FirstFirst 12

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •