Looks like two options are available: use node-ffi, which supports loading a native dynamic link library and then calling things in cdecl (guess). The other is writing your own module, described here:
http://syskall.com/how-to-write-your-own-native-nodejs-extension/index.html/
Node-ffi is here: https://github.com/node-ffi/node-ffi. Let's create a dll for it:
In Visual studio new c++ project, dll type. Then:
#include "stdafx.h"
#include <iostream>
extern "C"
__declspec(dllexport) void stdoutput()
{
std::cout << "test output";
}
extern "C"
__declspec(dllexport) void crash()
{
__asm
{
int 3;
}
}
End result:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\dumpbin.exe c:\users\ledin_000\documents\visual studio 2013\Projects\sample_dll\Debug\sample_dll.dll
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\dumpbin.exe" /exports "c:\users\ledin_000\documents\visual studio 2013\Projects\sample_dll\Debug\sample_dll.dll"
...
ordinal hint RVA name
1 0 0001101E crash = @ILT+25(_crash)
2 1 000110DC stdoutput = @ILT+215(_stdoutput)
npm install node-ffi suggested to install module ffi.
At some point npm errorred out because I did not have C:\Users\<username>\AppData\Roaming\npm directory.
After that, compiles stuff using my visual studio. Interesting security consequences. So I have trust npm. It does do ssl connection to the servers where it downloads things from. Fiddler says.
Turns out my node installation is 64 bit. Kind of expected. So now: ::DebugBreak(); instead of the __asm sequence.
var ffi = require('ffi');
var funcs = ffi.Library('sample_dll.dll', {
'stdoutput': [ 'void', [ ] ],
'crash': [ 'void', [ ] ],
});
funcs.stdoutput();
funcs.crash()
Didn't crash. Why not?
I guess I need to execute it under debugger.
I will sleep for 20 seconds, to enable attach with visual studio.
JS does not have a sync sleep function, so npm install sleep.
Node populates C:\Program Files\nodejs\node_modules\sleep, so it is easy to look how a module looks like.
Somehow I cannot see a nice callstack when attaching and waiting for Debugbreak(). Debugbreak happens, but not with expected callstack.
So I do:
windbg node exp2.js
sxe ld sample_dll -- wait till loading of sample_dll happens.
x sample_dll!*crash* -- to see I have symbols, which I have in path.
then
bu sample_dll!crash
g
and...
0:000> k
Child-SP RetAddr Call Site
00000000`0035f4c8 00007ffe`15ff9dc3 sample_dll!crash [c:\users\<user>\documents\visual studio 2013\projects\sample_dll\sample_dll\sample_dll.cpp @ 15]
00000000`0035f4d0 00007ffe`15ff39b6 ffi_bindings!ffi_call_win64+0x77
00000000`0035f510 00007ffe`15ff26df ffi_bindings!ffi_call+0xa6 [c:\node_modules\ffi\deps\libffi\src\x86\ffi.c @ 421]
*** ERROR: Symbol file could not be found. Defaulted to export symbols for node.exe -
00000000`0035f570 00007ff7`5288bff4 ffi_bindings!FFI::FFICall+0x14f [c:\node_modules\ffi\src\ffi.cc @ 289]
00000000`0035f5f0 00007ff7`52889d56 node!uv_cancel+0x44674
...
In other words I crashed where I expected. No symbols for node though. I wonder where I could find them.
In either case, lesson here is that:
1) debugging native with node.js is easy.
2) writing native code as node module should be easy as well. Sample code is close and available.