Embedding Binary Code in newLISP

updated 2013-10-29

The following hack shows how to embed binary code in newLISP for execution just like any other function call in newLISP. The trick is to create a built-in function symbol and point it to the code to execute. The code should be written to 'C' calling conventions of the platform newLISP is running on.

The following example assumes a x86 like CPU (args on the stack) and will not work on all platforms.

1. The code to execute

The following lines show x86 assembly for a function taking two integers and returning the sum of both:

 55       push ebp
 8B EC    mov  ebp, esp
 8B 45 08 mov  eax, [ebp+08]
 03 45 0C add  eax, [ebp+0c]
 5D       pop  ebp
 C3       ret

; for Win32/stdcall change last line
 C2 08 00 ret 

Create a string containing the binary code. Variable foo-code must not be reassigned:

(set 'foo-code (pack "ccccccccccc" 
    0x55 0x8B 0xEC 0x8B 0x45 0x08 
    0x03 0x45 0x0C 0x5D 0xC3)) 

2. Get a function template from a built-in function

(set 'foo print)

3. Change the type to a library function

; on WIN32 stdcall
(cpymem (pack "ld" 8456) (first (dump foo)) 4)

; on LINUX/UNIX cdecl
(cpymem (pack "ld" 4360) (first (dump foo)) 4) 

4. Point the function to the binary code

This is done copying the address of the bin-data into the cell contents field of foo
at offset 12:

(cpymem (pack "ld" (address foo-code)) 
        (+ (first (dump foo)) 12) 4)

5. Set name ptr to correct function name

This copies a ptr to the function name into the auxilary cell field of foo.
Variable foo-name must not be reassigned:

(set 'foo-name "foo")
(cpymem (pack "ld" foo-name) 
        (+ (first (dump foo)) 8) 4)

6. Putting it all together platform independent

(set 'foo-code (append
    (pack "bbbbbbbbbb" 0x55 0x8B 0xEC 0x8B 0x45 0x08 0x03 0x45 0x0C 0x5D)
    (if (= ostype "Win32") (pack "bbb" 0xC2 0x08 0x00) (pack "b" 0xC3))))
(set 'foo print)
(cpymem (pack "ld" (if (= ostype "Win32") 8456 4360)) (first (dump foo)) 4)
(cpymem (pack "ld" (address foo-code)) (+ (first (dump foo)) 12) 4)
(set 'foo-name "foo")
(cpymem (pack "ld" foo-name) (+ (first (dump foo)) 8) 4)

; execute
(foo 3 4) => 7