Author Topic: Using a O2 DLL with apps generated with other compilers  (Read 18563 times)

0 Members and 5 Guests are viewing this topic.

efgee

  • Guest
Using a O2 DLL with apps generated with other compilers
« on: January 10, 2011, 02:24:15 PM »
Hello,
trying to use a DLL created with OxygenBasic in conjunction with programs programmed in other programming languages.
The only thing I use are normal functions like:
(independent or with oxygen.dll doesn't matter...)

Code: [Select]
 $ dll
  $ FileName dll_math_o2
  includepath "..\inc\"
  include "RTL32.inc"

function IsInitialized() as long export
function = (1)
end function

function MathAdd(N1 as long, N2 as long) as long export
function = (N1 + N2)
end function

function MathDiv(N1 as long, N2 as long) as long export
function = (N1 / N2)
end function

function MathMul(N1 as long, N2 as long) as long export
function = (N1 * N2)
end function

function MathSub(N1 as long, N2 as long) as long export
function = (N1 - N2)
end function

The first one I tried was a Purebasic program and it seems that dynamic loading of an OxygenBasic DLL does not work; DLLs created with other compilers work well though.

Has anyone had more luck?

Thanks
efgee

Charles Pegge

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #1 on: January 10, 2011, 03:22:47 PM »
Hi efgee,

It looks okay from here.
Was PureBasic able to load the DLL? LoadLibrary is a direct call to the Kernel.

Charles

Anywhere PE Viewer 0.17
Code: [Select]
C:\cevp\projects\opcode\OxygenBasic\Examples\UseRTL32\dll_math_o2.dll
Export table
Characteristics=0, TimeDateStamp=1294783729, MajorVersion=0, MinorVersion=0, Name=45104, Base=1, NumberOfFunctions=5, NumberOfNames=5, AddressOfFunctions=45124, AddressOfNames=45160, AddressOfNameOrdinals=45148,
TimeDateStamp:Tue Jan 11 22:08:49 GMT 2011
IsInitialized (Ordinal: 1, Entry Point RVA: 3440h (13,376))
MathAdd (Ordinal: 2, Entry Point RVA: 3470h (13,424))
MathDiv (Ordinal: 3, Entry Point RVA: 34b0h (13,488))
MathMul (Ordinal: 4, Entry Point RVA: 34f0h (13,552))
MathSub (Ordinal: 5, Entry Point RVA: 3530h (13,616))
Generated with Anywhere PE Viewer/APEVPX (http://www.ucware.com/)

« Last Edit: January 10, 2011, 03:26:45 PM by Charles Pegge »

Charles Pegge

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #2 on: January 10, 2011, 03:39:35 PM »

Program to test the DLL including header (Oxygen)

Code: [Select]

'  $ dll
'  $ FileName dll_math_o2
'  includepath "..\..\inc\"
'  include "RTL32.inc"

'NB automatic case sensitivity so you dont need to use ALIAS clauses in the extern block

extern lib "dll_math_o2.dll"

declare function IsInitialized() as long
declare function MathAdd(N1 as long, N2 as long) as long
declare function MathDiv(N1 as long, N2 as long) as long
declare function MathMul(N1 as long, N2 as long) as long
declare function MathSub(N1 as long, N2 as long) as long

end extern


print IsInitialized

print MathMul 3,4

efgee

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #3 on: January 10, 2011, 04:54:45 PM »
Hi efgee,
It looks okay from here.
Was PureBasic able to load the DLL? LoadLibrary is a direct call to the Kernel.

Yes the DLL was loaded and the "LibraryAddress" function gives the following address for the functions:

IsInitialized : $10003440
MathAdd : $10003470
MathDiv : $100034B0
MathMul : $100034F0
MathSub : $10003530

I suppose these addresses differ by $10000000 because the OS tries to map/relocate the functions.

One thing I don't understand is that a DLL normally has ".reloc" section but a Oxygen generated DLL has not...
(afaik the functions need to be relocateable...)

bye

Charles Pegge

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #4 on: January 10, 2011, 10:03:47 PM »
efgee,

Does PureBasic default to param passing byRef or ByVal? - just thinking about other sources of error.

The location should not matter. All Oxygen code is relocatable and does not require reloc sections to adjust absolute addresses.

I found that loading the dll in Oxygen (under Vista) gave the different locations almost every time.

print hex & IsInitialized

1F3440
203440
1D3440
1B3440
233440


Here is the DLL being used by thinBasic

Code: [Select]

declare function IsInitialized lib "dll_math_o2.dll" alias "IsInitialized" () as long
declare function MathAdd lib "dll_math_o2.dll" alias "MathAdd" (N1 as long, N2 as long) as long
declare function MathDiv lib "dll_math_o2.dll" alias "MathDiv" (N1 as long, N2 as long) as long
declare function MathMul lib "dll_math_o2.dll" alias "MathMul" (N1 as long, N2 as long) as long
declare function MathSub lib "dll_math_o2.dll" alias "MathSub" (N1 as long, N2 as long) as long

dim as long a,b
a=3 : b=4

msgbox 0,IsInitialized
msgbox 0,MathMul(a,b)


and with PowerBasic

Code: [Select]
'PowerBasic
$COMPILE EXE

DECLARE FUNCTION IsInitialized LIB "dll_math_o2.dll" ALIAS "IsInitialized" () AS LONG
DECLARE FUNCTION MathAdd LIB "dll_math_o2.dll" ALIAS "MathAdd" (N1 AS LONG, N2 AS LONG) AS LONG
DECLARE FUNCTION MathDiv LIB "dll_math_o2.dll" ALIAS "MathDiv" (N1 AS LONG, N2 AS LONG) AS LONG
DECLARE FUNCTION MathMul LIB "dll_math_o2.dll" ALIAS "MathMul" (N1 AS LONG, N2 AS LONG) AS LONG
DECLARE FUNCTION MathSub LIB "dll_math_o2.dll" ALIAS "MathSub" (N1 AS LONG, N2 AS LONG) AS LONG

FUNCTION PBMAIN()

DIM a AS LONG,b AS LONG
a=3 : b=4

MSGBOX STR$(IsInitialized)
MSGBOX STR$(MathMul(a,b))

END FUNCTION

Charles
« Last Edit: January 10, 2011, 10:35:31 PM by Charles Pegge »

efgee

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #5 on: January 11, 2011, 06:27:58 AM »
I think PureBasic uses byVal...  :-\

Do the "Declare Function" declarations in Oxygen, thinBasic and PowerBasic use "LoadLibrary"?
(so called late binding)
I assumed what they do is early binding...

With PureBasic I could also test early binding, but I have to find a program that generates a working static import library off the DLL.

Thanks
efgee

jack

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #6 on: January 11, 2011, 08:34:01 AM »
... but I have to find a program that generates a working static import library off the DLL.
since you have PureBasic you already have it, it's Polib.
you can either add C:\Program Files\PureBasic\Compilers to the path variable or copy your dll to Compilers folder
and then type the following command: polib yourdll.dll /machine:x86 /out:yourdll.lib
BTW, I use the LibDump utility found here http://www.gpoulose.com/ to view the lib exported functions, I know there's dependency walker
but for simple name dump prefer LibDump.
« Last Edit: January 11, 2011, 09:06:19 AM by jack »

Charles Pegge

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #7 on: January 11, 2011, 09:49:49 AM »

I would try specifying "byref" in the declarations - if it has already given you valid procaddresses then this is the usual problem.

Oxygen actually uses GetProcAddress for most of its binding. Only its bootstrap uses true early binding. - by which I mean having tables in the import section of the PE file that are initialised by the Operating system at load time.

In Oxygen all declarations associated with a library (& only those which are called in the program) are bunched together at the top of the code so they are resolved in one go before the rest of the program is executed. However there are several ways to late bind. A declared function may be assigned or reassigned a ProcAddress at any time.

Example:
Code: [Select]
declare function foo(byref a as long) as long
'...
& foo = GetProcAddress(BahLib,"foo")
if not & foo then
  print "sorry! can't locate function foo in BahLib" : '...
else
  print foo(42)
end if

Charles

efgee

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #8 on: January 11, 2011, 11:19:20 AM »
... but I have to find a program that generates a working static import library off the DLL.
since you have PureBasic you already have it, it's Polib.
you can either add C:\Program Files\PureBasic\Compilers to the path variable or copy your dll to Compilers folder
and then type the following command: polib yourdll.dll /machine:x86 /out:yourdll.lib
BTW, I use the LibDump utility found here http://www.gpoulose.com/ to view the lib exported functions, I know there's dependency walker
but for simple name dump prefer LibDump.

Ups, didn't think of that... thank you.

Ok, generated the static lib and wrote this in order to test it (PureBasic):
Code: [Select]
Import "g:\Bunion\examples\dll_math_o2.lib"
  IsInitialized()
  MathMul(n1.i, n2.i)
  MathDiv(n1.i, n2.i)
  MathAdd(n1.i, n2.i)
  MathSub(n1.i, n2.i)
EndImport

Debug IsInitialized()
Debug MathMul(4,2)
Debug MathDiv(4,2)
Debug MathAdd(4,2)
Debug MathSub(4,2)

The first function "IsInitialized" returns a 1 but the program crashes on the second function.
The debugger's error message is: Invalid memory access, (read error at address 4).

The address corresponds with the value of the first parameter - if I change the parameter to 6 the address becomes 6.

Strange...

EDIT
BTW: it's the same error as when the DLL is used with LoadLibrary (PureBasic command is OpenLibrary)
« Last Edit: January 11, 2011, 12:02:44 PM by efgee »

efgee

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #9 on: January 11, 2011, 12:05:22 PM »
...
The location should not matter. All Oxygen code is relocatable and does not require reloc sections to adjust absolute addresses.

How is this achieved?

That's the first time I hear that a DLL does not need a reloc section  :o

Charles Pegge

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #10 on: January 11, 2011, 12:39:36 PM »
How do you express 'byref' in the declaration? It needs to pass addresses not values.

Charles

jack

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #11 on: January 11, 2011, 12:43:21 PM »
efgee, I suggest you try ImportC and see if that works, Purebasic default calling convention is stdcall.

efgee

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #12 on: January 11, 2011, 01:04:10 PM »
efgee, I suggest you try ImportC and see if that works, Purebasic default calling convention is stdcall.

ImportC results in "one big fat crash".

Charles Pegge

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #13 on: January 11, 2011, 01:05:28 PM »
Relocatability is achieved by avoiding absolute addresses completely. Addresses are referenced either relatively (for direct jumps and calls) or by offset from a register. EBX contains the absolute address of the .bssdata - the start of the uninitialised data section. All function tables and static variables are mapped out as an offset from this base.

How does register EBX obtain an absolute address to .bssdata at runtime? In 32 bit mode its a little awkward but this is what I do:
Code: [Select]
call fwd here
.here
pop ebx 'get the absolute address of here
sub ebx,here 'deduct virtual address of here
add ebx,bssdata 'add virtual address of bssdata

In 64 bit mode it's so much simpler:
Code: [Select]
lea rip rbx,bssdata 'load effective address (Relative to Instruction Pointer) .bssdata
(The notation will differ in other assemblers)


Charles

« Last Edit: January 11, 2011, 01:19:09 PM by Charles Pegge »

efgee

  • Guest
Re: Using a O2 DLL with apps generated with other compilers
« Reply #14 on: January 11, 2011, 01:06:07 PM »
How do you express 'byref' in the declaration? It needs to pass addresses not values.

Charles
Well it is my understanding that doing an "Import" the parameter passing is always done byRef...
I could be wrong though.