How to use LPCWSTR with Go and Swig? - go

I'm trying to use a C library with Go using Swig. This is simplified code, I know I can use cgo but I need to use a function with a LPCWSTR argument with Swig.
I saw on https://github.com/AllenDang/w32/blob/c92a5d7c8fed59d96a94905c1a4070fdb79478c9/typedef.go that LPCWSTR is the equivalent of *uint16 so syscall.UTF16PtrFromString() seems to be what I need but I get an exception when I run the code.
I'm wondering if I'm supposed to use SwigcptrLPCWSTR or not.
libtest.c
#include <windows.h>
#include <stdio.h>
#include "libtest.h"
__stdcall void hello(const LPCWSTR s)
{
printf("hello: %ls\n", s);
}
libtest.h
#ifndef EXAMPLE_DLL_H
#define EXAMPLE_DLL_H
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef BUILDING_EXAMPLE_DLL
#define EXAMPLE_DLL __declspec(dllexport)
#else
#define EXAMPLE_DLL __declspec(dllimport)
#endif
void __stdcall EXAMPLE_DLL hello(const LPCWSTR s);
#ifdef __cplusplus
}
#endif
#endif
I build the lib and the DLL with :
gcc -c -DBUILDING_EXAMPLE_DLL libtest.c
gcc -shared -o libtest.dll libtest.o -Wl,--out-implib,libtest.a
main.swig
%module main
%{
#include "libtest.h"
%}
%include "windows.i"
%include "libtest.h"
main.go
package main
import (
"syscall"
"unsafe"
)
func main() {
p, err := syscall.UTF16PtrFromString("test")
if err != nil {
panic(err)
}
Hello(SwigcptrLPCWSTR(unsafe.Pointer(p)))
}
trace
Exception 0xc0000005 0x0 0xffffffffffffffff 0x7ffcc761f2e1
PC=0x7ffcc761f2e1
signal arrived during external code execution
main._Cfunc__wrap_hello_main_90cec49f7d68ac58(0xc082002110)
_/D_/lpcwstr/go/_obj/_cgo_gotypes.go:53 +0x38
main.Hello(0x500028, 0xc082002120)
_/D_/lpcwstr/go/_obj/main.go:63 +0x3c
main.main()
D:/lpcwstr/go/main.go:9 +0x96
goroutine 17 [syscall, locked to thread]:
runtime.goexit()
c:/go/src/runtime/asm_amd64.s:1696 +0x1
rax 0x6c007400690074
rbx 0x6c007400690074
rcx 0x7ffffffe
rdi 0x24fd73
rsi 0x7
rbp 0x24fb00
rsp 0x24fa00
r8 0xffffffffffffffff
r9 0x7ffcc75d0000
r10 0x0
r11 0x200
r12 0xffffffff
r13 0x24fd60
r14 0x10
r15 0x6264403a
rip 0x7ffcc761f2e1
rflags 0x10202
cs 0x33
fs 0x53
gs 0x2b

I suspect the issue you're seeing is because what you're passing into SWIG is a double pointer instead of just a pointer, i.e. wchar_t** instead of just wchar_t*.
I think this comes about because you call UTF16PtrFromString which takes the address of the UTF16 string and then subsequently call unsafe.Pointer(p) which I think again takes the address of its input.
From the go source code:
func UTF16PtrFromString(s string) (*uint16) {
a := UTF16FromString(s)
return &a[0]
}
So I think if you instead use:
func main() {
p, err := syscall.UTF16FromString("test") // Note the subtle change here
if err != nil {
panic(err)
}
Hello(SwigcptrLPCWSTR(unsafe.Pointer(p)))
}
It should work as intended.

Related

mmap() RWX page on MacOS (ARM64 architecture)?

I've been trying to map a page that both writable AND executable.
mov x0, 0 // start address
mov x1, 4096 // length
mov x2, 7 // rwx
mov x3, 0x1001 // flags
mov x4, -1 // file descriptor
mov x5, 0 // offset
movl x16, 0x200005c // mmap
svc 0
This gives me a 0xD error code (EACCESS, which the documentation unhelpfully blames on an invalid file descriptor, although same documentation says to use '-1'). I think the code is correct, it returns a valid mmap if I just pass 'r--' for permissions.
I know the same code works in Catalina and x64 architecture. I tested the same error happens when SIP mode is disabled.
For more context, I'm trying to port a FORTH implementation to MacOs/ARM64, and this FORTH, like many others, heavily uses self modifying code/assembling code at runtime. And the code that is doing the assembling/compiling resides in the middle of the newly created code (in fact part the compiler will be generated in machine language as part of running FORTH), so it's very hard/infeasible to separate the FORTH JIT compiler (if you call it that) from the generated code.
Now, I'd really don't want to end up with the answer: "Apple thinks they know better than you, no FORTH for you!", but that is what it looks like so far. Thanks for any help!
You need to toggle the thread between being writable or executable, it can not be both at the same time. I think it is actually possible to do both with the same memory using 2 different threads but I haven't tried.
Before you write to the memory you mmap, call this:
pthread_jit_write_protect_np(0);
sys_icache_invalidate(addr, size);
Then when you are done writing to it you can switch back again like this:
pthread_jit_write_protect_np(1);
sys_icache_invalidate(addr, size);
This is the full code I am using right now
#include <stdio.h>
#include <sys/mman.h>
#include <pthread.h>
#include <libkern/OSCacheControl.h>
#include <stdlib.h>
#include <stdint.h>
uint32_t* c_get_memory(uint32_t size) {
int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_JIT;
int fd = -1;
int offset = 0;
uint32_t* addr = 0;
addr = (uint32_t*)mmap(0, size, prot, flags, fd, offset);
if (addr == MAP_FAILED){
printf("failure detected\n");
exit(-1);
}
pthread_jit_write_protect_np(0);
sys_icache_invalidate(addr, size);
return addr;
}
void c_jit(uint32_t* addr, uint32_t size) {
pthread_jit_write_protect_np(1);
sys_icache_invalidate(addr, size);
void (*foo)(void) = (void (*)())addr;
foo();
}

How to use NewLazyDLL (golang) to custom dll export from c# to set parameters

I wrote a custom dll export in c# which is working in c
This is my c# code for dll export
[DllExport]
/* GetMSLResult from the parameter as lat, lon, and gps elevation */
public static double GetMSLResult(IntPtr lat, IntPtr lon, IntPtr gpsElevation) => Helper.GetMSL(Helper.GetGeoID(Helper.IntPtrToDouble(lat), Helper.IntPtrToDouble(lon)), Helper.IntPtrToDouble(gpsElevation));
which is working and expose via
dumpbin /exports ClassLibrary1.dll
Which has my procedure is present
Also as i test in c code its working as well
this is my
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
typedef int(*GetMSLResult)(const wchar_t* str, const wchar_t* str1);
int main()
{
auto dll = ::LoadLibrary(L"ClassLibrary1.dll"); // さっき作ったC# DLLの名前を指定する
{
auto result = reinterpret_cast<GetMSLResult>(::GetProcAddress(dll, "Count"));
wcout << result(L"34.00", L"40.00") << endl; // this returns 74.00
wcout << result(L"90.00", L"40.00") << endl; // this returns 130.00
}
if ( dll )
::FreeLibrary(dll); // 解放は忘れずに!!
return 0;
}
this is working successfully, in golang i created a test code to read the exported dll not imported dll.
I wrote a simple test in windows how to do it but it seems i got an error and exited when i try to call the function i want to return the value
package main
import (
"fmt"
"syscall"
"unsafe"
)
func main() {
h := syscall.NewLazyDLL("ClassLibrary1.dll")
proc := h.NewProc("GetGeoID")
a := string("32.00")
n, _, _ := proc.Call(uintptr(unsafe.Pointer(&a)))
//fmt.Printf("teast %v", n)
fmt.Printf("Hello dll function returns %d\n", n)
}
Currently this is my golang code.
In my GeoID expected two parameter which is lattitude and longitude
so in my code in golang
a := string("32.00")
b := string("32.00")
i want this to pass the parameter a and b to my dll procedure functions
so that i could be able to get a result.
n, _, _ := proc.Call(uintptr(unsafe.Pointer(&a)))
But currently i received this error
Exception 0xe0434352 0x80131537 0x0 0x766afd62
PC=0x766afd62
syscall.Syscall(0x6e35290e, 0x1, 0x11006108, 0x0, 0x0, 0x0, 0x0, 0x0)
C:/Go/src/runtime/syscall_windows.go:184 +0xbb
syscall.(*Proc).Call(0x11004100, 0x110120e0, 0x1, 0x1, 0x10, 0x4907e0, 0x1, 0x110120e0)
C:/Go/src/syscall/dll_windows.go:171 +0x10a
syscall.(*LazyProc).Call(0x11049aa0, 0x110120e0, 0x1, 0x1, 0x0, 0x44bc01, 0x11034000, 0x11034000)
C:/Go/src/syscall/dll_windows.go:333 +0x48
main.main()
C:/Users/christopher/developer/go/src/gotest/main.go:16 +0x103
eax 0x19fbc0
ebx 0x5
ecx 0x5
edx 0x0
edi 0x1
esi 0x19fc80
ebp 0x19fc18
esp 0x19fbc0
eip 0x766afd62
eflags 0x216
cs 0x23
fs 0x53
gs 0x2b
exit status 2
Is there any good way i can call my custom dll procedure or function
like GetAge(34, 56) and the result in golang? currently ive been using LoadDLL, NewLazyDLL and other stuff but i could not be able to achieve my goal, does somebody can suggest a good way to do it?

GCC How declare and link extern Kernel32.LIB functions with '#'

Kernel.LIB file content
_ExitProcess#4, _GetStdHandle#4, _WriteConsoleA#20
For use this, I've tested to declare :
void WINAPI ExitProcess(unsigned int ExitCode);
HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
bool WINAPI WriteConsole#20(HANDLE hConsoleOutput, const void *lpBuffer DWOR......)
But this not work. (undefined reference).
I've tested with "#n"
void WINAPI ExitProcess#4(unsigned int ExitCode);
HANDLE WINAPI GetStdHandle#4(DWORD nStdHandle);
bool WINAPI WriteConsole#20(HANDLE hConsoleOutput, const void *lpBuffer DWOR......)
But this syntax is not allowed.
I've found Linking to Kernel32.lib in assembler
This solution is good, but only for nasm so, my question is :
How do use this in C/C++ with G++/GCC ?
extern _ExitProcess#4, _GetStdHandle#4, _WriteConsoleA#20
%define ExitProcess _ExitProcess#4
%define GetStdHandle _GetStdHandle#4
%define WriteConsoleA _WriteConsoleA#20
Because " #4 #20 " was not allowed syntax in C/C++

Visual Studio 2013 x64 calling convention optimization for returning shared_ptr

I'm so confused because my disassembled code is different from my knowledge. As I know, first argument is passed by RCX and return value is stored at RAX. But below code use RCX as return value container and pass first argument by RDX. Why does this happen and what is the name of this way?
This is the cpp code I compile:
#include "stdafx.h"
#include <memory>
#include <map>
#include <iostream>
using namespace std;
class Zelon {
public:
int64_t kkk;
int64_t lll;
};
typedef shared_ptr<Zelon> ZelonPtr;
std::map<std::string, ZelonPtr> aMap;
shared_ptr<Zelon> Find(const std::string& f) {
auto it = aMap.find(f);
return it == aMap.end() ? nullptr : it->second;
}
int _tmain(int argc, _TCHAR* argv[]) {
std::string k = "zelon";
ZelonPtr result = Find(k);
if (result->kkk == 100) {
cout << "100" << endl;
}
return 0;
}
and this is the disassembled code:
ZelonPtr result = Find(k);
00007FF6FAC014DE lea rdx,[k]
00007FF6FAC014E3 lea rcx,[result]
00007FF6FAC014E8 call Find (07FF6FAC012B0h)
00007FF6FAC014ED nop
if (result->kkk == 100) {
00007FF6FAC014EE mov rax,qword ptr [result]
00007FF6FAC014F3 cmp qword ptr [rax],64h
This code is compiled in Visual Studio 2013 x64 Release Full optimization.
I got a answer from http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx
It's a method of 'Return Value Optimization', the use of hidden argument.

Bus error when calling Pause in OSX

section .text
global start
start:
mov eax, 29
int 80h
ret
I'm pretty sure that pause(void) is syscall 29, so why is this giving me Bus error: 10?
According to sys/syscall.h:
#define SYS_recvfrom 29
I would guess that recvfrom takes some other parameter, giving you the buss error.
If you are actually trying to call pause(void), a cursory examination of source seems to suggest that the definitions are something like the following:
syscalls.h:
#define SYS_sigsuspend 111
sigsuspend.c:
int
sigsuspend (
const sigset_t *sigmask_p
)
{
sigset_t mask;
if (sigmask_p)
mask = *sigmask_p;
else
sigemptyset(&mask);
return syscall (SYS_sigsuspend, mask);
}
sigcompat.c:
int sigpause(mask)
int mask;
{
return (sigsuspend((sigset_t *)&mask));
}
sigpause.c:
int
pause()
{
return sigpause(sigblock(0L));
}
So, while the pause(void) may not take any parameters, the syscall certainly does.
To call pause(void) from assembly, link with libc:
example.asm:
section .text
global start
start:
call pause
ret
Compile with as -o example.o example.asm and link with gcc -static -o a.out example.o

Resources