Author Topic: Building DLL's  (Read 3298 times)

0 Members and 1 Guest are viewing this topic.

RobbeK

  • Guest
Building DLL's
« on: March 11, 2015, 04:17:34 AM »
Hi all, Charles ,

To keep everything together -- in the same editor --- (tB , O2 , newLISP) and make 02 interactive with newLISP a few questions about generating DDL's

1) the newLISP FFI

                     
Dim As String src Value "(define dll ""screen2win.dll"")
(import dll ""setscreen"")
(dolist (i (list ""setscreen"" ""pixel"" ""scr"" ""scrlock"" ""scrunlock""))
   (import dll i))
   
(setscreen 400 400 220 20) 
(struct 'outp ""long"" ""double"")

(import dll ""julia"" ""outp"" ""double"" ""double"" ""double"" ""double"" ""long"")
   
 

(define (kill-scr) (scr 0))   

(define (tst , fr)   
 (scrlock)
  (let ((i 0) (j 0) )
    (for (x -2.1 0.9 (div 3 400))
      (setq j 0)
      (++ i)
     (for (y -1.5 1.5 (div 3 400))
      (++ j)
      (setq fr (julia x y x y 16) )
        (pixel i j (* 10 (fr 1)) (* (fr 0) 14) 0)) ) ) 
   (scrunlock)     
   ) 

(define (test)  (time (tst)))

2) I wrote the DLL some time ago (both for Win and Linux) in Freebasic ::  a fragment

extern "Windows-MS"

type outp
 in as integer
 d as double
end type

     
 
public function julia ( byval x as double , byval y as double , byval rc as double , byval ic as double , _
         byval maxit as integer ) as outp export
         dim  ii as integer
         dim  as double tmp , orb
         dim  o as outp
         while ((ii < maxit) and (orb < 4))
           tmp=x
           x=rc+x*x-y*y
           y=ic+ 2*tmp*y
           orb=x*x+y*y
           ii += 1
         wend
         o.in=ii
         o.d=orb
         return o
end function

           
end extern

------------------------------------------------------------------------------------------------------

I started to convert to O2 -- but in the examples i both see

$dll  and #dll
$file and #file  ??

when must RTL32.inc included ??

can the UDT directly be declared in DLL in the same way as FreeBasic ??

thanks in advance , Rob  (the intention is -- keeping it together -- using oxygen preferably ran from tB )


.
« Last Edit: March 11, 2015, 05:45:06 AM by RobbeK »

Charles Pegge

  • Guest
Re: Building DLL's
« Reply #1 on: March 11, 2015, 05:46:57 AM »
Hi Rob,

There is a degree of wobble in the syntax, but if you need a DLL that follows freebasic/thinBasic syntax closely, then you can spit independent dlls something like this:

Code: OxygenBasic
  1.   % dll
  2.   % FileName  "t.dll"
  3.   includepath "$\inc\"
  4.   include     "RTL32.inc"
  5.  
  6.   extern export 'BLOCK FOR EXPORTED DLL FUNCTIONS
  7.  
  8.   type vector3f
  9.   =============
  10.   x as single
  11.   y as single
  12.   z as single
  13.   end type
  14.  
  15.   function square( byval n as double ) as double
  16.   ===============
  17.   return n*n
  18.   end function
  19.  
  20.   function AddVec3f( byref a as vector3f, byref b as vector3f, byref r as vector3f)
  21.   =================
  22.   r.x=a.x+b.x
  23.   r.y=a.y+b.y
  24.   r.z=a.z+b.z
  25.   end function
  26.  
  27.   end extern
  28.  

PS: thinBasic's string type is Oxygen's bstring type.

« Last Edit: March 11, 2015, 06:00:06 AM by Charles Pegge »

Charles Pegge

  • Guest
Re: Building DLL's
« Reply #2 on: March 11, 2015, 06:59:06 AM »
Taking your Julia function, which returns a UDT, requires a few changes:

  type outp
    in as integer
    d as double
  end type

...
  function julia( byval x as double , byval y as double ,
  byval rc as double , byval ic as double ,
  byval maxit as integer ) as outp ptr
  '
    dim  ii as integer
    dim  as double tmp , orb
    static o as outp
    while ((ii < maxit) and (orb < 4))
      tmp=x
      x=rc+x*x-y*y
      y=ic+ 2*tmp*y
      orb=x*x+y*y
      ii += 1
    wend
    o.in=ii
    o.d=orb
    return @o
  end function


calling:

  dim as outp byref o
  @o=julia 1,1,1,1,10

alternatively:

  let o=julia 1,1,1,1,10
« Last Edit: March 11, 2015, 07:08:03 AM by Charles Pegge »

RobbeK

  • Guest
Re: Building DLL's
« Reply #3 on: March 11, 2015, 10:19:48 AM »
Thanks Charles ,

@sym  should be no problem --  newLISP has a "pack" and "unpack" function  (to do things "ByRef")
 
the manual gives following possibilities :

c    a signed 8-bit number
b    an unsigned 8-bit number
d    a signed 16-bit short number
u    an unsigned 16-bit short number
ld    a signed 32-bit long number
lu    an unsigned 32-bit long number
Ld    a signed 64-bit long number
Lu    an unsigned 64-bit long number
f    a float in 32-bit representation
lf    a double float in 64-bit representation
sn    a string of n null padded ASCII characters
nn    n null characters
>    switch to big endian byte order
<    switch to little endian byte order

There may be a more direct way (?)   i.o. using a DLL also from the manual

=======================================================================================================

Copies int-bytes of memory from int-from-address to int-to-address. This function can be used for direct memory writing/reading or for hacking newLISP internals (e.g., type bits in newLISP cells, or building functions with binary executable code on the fly).

Note that this function should only be used when familiar with newLISP internals. cpymem can crash the system or make it unstable if used incorrectly.

(set 's "0123456789")

(cpymem "xxx" (+ (address s) 5) 3)

s  → "01234xxx89")

The example copies a string directly into a string variable.

The following example creates a new function from scratch, runs a piece of binary code, and adds up two numbers. This assembly language snippet shows the x86 (Intel CPU) code to add up two numbers and return the result:

 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

The binary representation is attached to a new function created in newLISP:

; set up 32-bit version of machine code
(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))))

; put a function cell template into foo, protect symbol from deletion
(constant 'foo print)

; put the correct type, either 'stdcall' or 'cdecl'
(cpymem (pack "ld" (if (= ostype "Win32") 8456 4360)) (first (dump foo)) 4)

; put the address of foo-code into the new function cell
(cpymem (pack "ld" (address foo-code)) (+ (first (dump foo)) 12) 4)

; take the name address from the foo symbol, copy into function cell
(set 'sym-name (first (unpack "lu" (+ (address 'foo) 8))))
(cpymem (pack "ld" sym-name) (+ (first (dump foo)) 8) 4)

; test the new function
(println "3 * 4 -> " (foo 3 4))

The last example will not work on all hardware platforms and OSs.

Use the dump function to retrieve binary addresses and the contents from newLISP cells.

==========================================what'd you think ??

best Rob  (oops , not intended occasional smilies )
« Last Edit: March 11, 2015, 11:27:52 AM by RobbeK »

Charles Pegge

  • Guest
Re: Building DLL's
« Reply #4 on: March 11, 2015, 02:05:22 PM »

Hi Rob,

That assembler snippet is very familiar to me. All integers, including pointers are returned in the eax register. If it is returning a pointer then one must ensure that the variable being pointed to, is not local, since locals are stored on the stack and usually get disallocated immediately on return.

Charles Pegge

  • Guest
Re: Building DLL's
« Reply #5 on: March 12, 2015, 02:45:51 AM »
This is what an Oxygen 32 bit external function actually looks like, in machine code:

Code: OxygenBasic
  1. function f(sys a,b) as sys
  2. return a+b
  3. end function
  4.  

o2 machine script:
Code: OxygenBasic
  1.                                 '  '_4
  2.                                '  'FUNCTION F
  3. E9 gf _over_                   '  jmp fwd _over_
  4. !10
  5. .f                              '  .f
  6. .f#sys#sys                      '  .f#sys#sys
  7. (                              '  (
  8. 53                             '  push ebx
  9. 56                             '  push esi
  10. 57                             '  push edi
  11. 50                             '  push eax
  12. E8 gl _mem                     '  call _mem
  13. 55                             '  push ebp
  14. 8B EC                          '  mov ebp,esp
  15. 83 C4 F0                       '  add esp,-16
  16. 8D 7D F0                       '  lea edi,[ebp-0x10]
  17. C7 07 00 00 00 00              '  mov [edi],0
  18. 8B 45 18                       '  mov eax,[ebp+0x18]
  19. 03 45 1C                       '  add eax,[ebp+0x1C]
  20. E9 gf _return_                 '  jmp fwd _return_
  21.                                '  '_6
  22. ._exit_                         '  ._exit_
  23. 8B 45 F0                       '  mov eax,[ebp-0x10]
  24. ._return_                       '  ._return_
  25. 8B E5                          '  mov esp,ebp
  26. 5D                             '  pop ebp
  27. 83 C4 04                       '  add esp,4
  28. 5F                             '  pop edi
  29. 5E                             '  pop esi
  30. 5B                             '  pop ebx
  31. C2 08 00                       '  ret 8
  32. )                              '  )
  33. ._over_                         '  ._over_
  34.                                '  '_7
  35.  

RobbeK

  • Guest
Re: Building DLL's
« Reply #6 on: March 14, 2015, 01:29:58 AM »
Thanks Charles, let's see i can stitch together some things ..

NewLISP first converts its code in an abstract syntax tree, kind of VM interpreted (as usual) in Lisp itself (it has (dotree ... ) etc ) -- it is very fast -- but some JIT code supplements would be wonderful !!  (iirc this was already done in the sixties  8)   )


best , Rob