Skip to content

Instantly share code, notes, and snippets.

@cosinusoidally
Last active January 2, 2017 07:11
Show Gist options
  • Save cosinusoidally/f05aca233b74acc3a1084a8cdd87add6 to your computer and use it in GitHub Desktop.
Save cosinusoidally/f05aca233b74acc3a1084a8cdd87add6 to your computer and use it in GitHub Desktop.
Horrible hacky code calling libChakraCore.so from Mozilla's jsshell
// get Spidermonkey from here:
// https://ftp.mozilla.org/pub/firefox/candidates/45.6.0esr-candidates/build1/jsshell-linux-x86_64.zip
// SHA512SUM and signature here:
// https://ftp.mozilla.org/pub/firefox/candidates/45.6.0esr-candidates/build1/linux-x86_64/en-US/firefox-45.6.0esr.checksums
// https://ftp.mozilla.org/pub/firefox/candidates/45.6.0esr-candidates/build1/linux-x86_64/en-US/firefox-45.6.0esr.checksums.asc
//
// set up Spidermonkey by unzipping it and adding it to your PATH and LD_LIBRARY_PATH:
// mkdir spidermonkey
// cd spidermonkey
// unzip ../jsshell-linux-x86_64.zip
// export PATH=${PWD}:$PATH
// export LD_LIBRARY_PATH=${PWD}
//
// run this script in the same dir as libChakraCore.so
p=print;
p("Note that this code is not really garbage collector safe.\nJsValueRefs should live on the C stack otherwise the GC can collect them prematurely.\nIn this program they live in the C heap.\nI have an idea how to work around this, but it is not yet implemented in this code");
p("This is based on https://github.com/Microsoft/Chakra-Samples/blob/0856ac51394acdb1aa519e28f187c3adf03bce60/ChakraCore%20Samples/Hello%20World/Python/helloWorld.py");
p("ga is a utility function for taking the address of a ctype cdata object");
ga=function(x){return ctypes.cast(x.address(),ctypes.uint64_t)};
p("Open libChakraCore.so:");
p(a=ctypes.open("./libChakraCore.so"));
p("Call DllMain to init the library:");
p(f = a.declare("DllMain", ctypes.default_abi, ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t));
p("Note DllMain returns a bool, so success is represented by 1. We should see 2 ones here:");
p(f(0,1,0));
p(f(0,2,0));
p("");
p("Note this assumes a 64bit system. I'm also being a bit fast and loose with types.\nYou'll notice I'm coercing most things to uint64 rather than pointer types etc.\nWorks fine (since pointers on 64 bits are 64 bits (obv)) and stops me having to keep all the types in order");
p("Need an array type to hold our JsValueRefs. Each time I need a new JsValueRefs I new a z");
p(z=ctypes.ArrayType(ctypes.uint64_t));
p();
p("First needs to create a runtime (JsCreateRuntime)");
p(g=a.declare("JsCreateRuntime", ctypes.default_abi, ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t));
p("Need a reference (w[0]) to hold the JsRuntimeHandle");
p(w=new z(1));
p(wa=ga(w));
p("Should start as zero");
p(w[0]);
p(g(0,0,wa));
p("Now should be a valid JsRuntimeHandle:");
p(w[0]);
p();
p("Now we need to create a context in the runtime (JsCreateContext):");
p(h=a.declare("JsCreateContext",ctypes.default_abi, ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t));
p("Need a referece to hold our context (x[0])");
p(x=new z(1));
p(xa=ga(x));
p("starts as a null");
p(x[0]);
p("create context");
p(h(w[0],xa));
p("context should now be valid");
p(x[0]);
p();
p("We must now set the context we cant to use with JsSetCurrentContext");
p(c=a.declare("JsSetCurrentContext",ctypes.default_abi, ctypes.uint64_t,ctypes.uint64_t));
p(c(x[0]));
p();
p("Next we will need to create a scriptname and add that name as a string inside the VM. We do this with JsCreateStringUtf8");
p(i=a.declare("JsCreateStringUtf8",ctypes.default_abi, ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t));
p("fn[0] will be our JsValueRef for our script name");
p(fn=new z(1));
p("fna is:");
p(fna=ga(fn));
p("s will be our script name");
p(s=ctypes.char.array()("script.js"));
p("sa is: ");
p(sa=ga(s));
p(s.length);
p("we then load s into the vm. fn[0] will start as zero:");
p(fn[0]);
p(i(sa,s.length,fna));
p("fn[0] will now be a valid JsValueRef");
p(fn[0]);
p();
p("We now need a string of javascript to execute. We call this sc");
p("sc as a buffer:");
p(sc=ctypes.char.array()("(()=>{return \'Hello world!\';})()"));
p("sc as a string:");
p(sc.readString());
p("address of sc");
p(sca=ga(sc));
p("length of sc:");
p(sc.length);
p("We need to load the string in to an external array buffer using JsCreateExternalArrayBuffer");
p(j=a.declare("JsCreateExternalArrayBuffer",ctypes.default_abi, ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t));
p("This is a external arraybuffer to reference the script source. Reference lives in ss[0]");
p(ss=new z(1));
p(ssa=ga(ss));
p(ss[0]);
p(j(sca,sc.length,0,0,ssa));
p(ss[0]);
p();
p("We are now ready to run the script with JsRun:");
p(k=a.declare("JsRun",ctypes.default_abi, ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t));
p("jr[0] is the reference to the result value");
p(jr=new z(1));
p(jra=ga(jr));
p(jr[0]);
p(k(ss[0],0,fn[0],0,jra));
p(jr[0]);
p();
p("Now we have run the script we need to print out the result. To do this we convert it to a string using JsConvertValueToString");
p(l=a.declare("JsConvertValueToString",ctypes.default_abi, ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t));
("Our result string will be referenced by jrs[0]");
p(jrs=new z(1));
p(jrsa=ga(jrs));
p(jrs[0]);
p(l(jr[0],jrsa));
p(jrs[0]);
p();
p("At this point our string is a JavaScript string. We need to convert it to a UTF8 string to print it. We use JsCopyStringUtf8 for this");
p(m=a.declare("JsCopyStringUtf8",ctypes.default_abi, ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t,ctypes.uint64_t));
p("sl[0] will hold our string length");
p(sl=new z(1));
p(sla=ga(sl));
p(sl[0]);
p(m(jrs[0],0,0,sla));
p(+sl[0].toString());
p("We now need to create a buffer to hold the result string. We call this rs");
p("Note the horrible +sl[0].toString() this is a hack to convert the ctypes.uint64_t to a js number fixme");
p(rs=ctypes.char.array(+sl[0].toString()+1)());
p(rsa=ga(rs));
p("rs should be blank, but the right size");
p(rs)
p("copy string into rs:")
p(m(jrs[0],rsa,+sl[0].toString()+1,0));
p("result rs as a buffer:");
p(rs);
p("after converting buffer rs into a js string");
p(rs.readString());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment