News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

how to access an integer variable in dll

Started by markallyn, December 31, 2017, 06:17:06 AM

Previous topic - Next topic

markallyn

Hello everyone,

I have written a simple dll in which there is an integer data item along with several arithmetic functions.  I'm trying to access the integer variable in the dll from the calling program.  The linker complains that the integer variable is undefined.  I use a PUBLIC/EXTERN pair for the integer in the dll and caller respectively.  The .def file EXPORTS section explicitly defines the exported data item and is identified as such with dumpbin /exports command.  The arithmetic functions work correctly when they are called. 

What do I need to do to get correct linkage to the .dll data item? 

Thanks,
Mark Allyn

hutch--

Mark,

Post at least some code or its guess work otherwise.

jj2007

There are two options in the DLL:

a) Externdef:
MyQwords QWORD 123456789123456789, 223456789123456789
EXTERNDEF MyQwords:QWORD


b) a fake proc in the .data section (tested in 32-bit land, not sure if it works with ML64):
.data
MyDwords proc syscall export
dd 111111111, 222222222, 333333333
MyDwords endp


In the calling code, use LoadLibrary + GetProcAddress.

markallyn

Hutch, JJ,

Hutch: I should have mentioned at the end of my post that I would post code if folks thought it useful.  I forgot to put that line into the text.  Apologies.  Will do so once my grandson has gone home.  Difficult at the moment.

JJ:  After putting the post up, I stopped trying to access the data item implicitly.  I did an explicit LoadLibrary call and all worked perfectly.  So, I drew (the probablly incorrect) conclusion that one cannot load data items from a dll using an implicit load.  I'll look more closely at what you have done after aforementioned grandson vacates.

Regards,
Marrk

hutch--

Mark,

Here is one technique to get values from a DLL. A DLL procedure is called passing an array to it and the array is filled with the values that are set in the DLL code. A simple dialog interface where I have marked the code that loads and calls the DLL procedure and the DLL is simple enough. There are other ways to get this data but this one works fine and you can get as many items as you like.

Sounds like the young fella is a genuine demon, means he is a good one.  :biggrin:

sinsi

Like this maybe?

;in the DLL
.data
public MyVar
MyVar dd 12345678h


;in the caller
externdef _imp__MyVar:dword

.code
  mov eax,_imp__MyVar
  mov eax,[eax]


Or have a dll exported function called GetMyVar

  mov eax,MyVar
  ret

🍺🍺🍺

markallyn

Hello Sinsi and everyone,

I tried your first method and couldn't get it to work.  In the attached .dll and caller I tried also to use EXTERNDEF in both the .dll and caller.  That didn't work either.  Here's the code for the .dll

Quote
include \masm32\include64\masm64rt.inc
externdef myint:QWORD

.data
myint   qword   040h

.code
DllEntry   PROC   hInstDLL:HINSTANCE, reason:QWORD, reserved:QWORD
mov   rax, TRUE
ret
DllEntry   ENDP

add2ints   PROC    var1:QWORD, var2:QWORD            
   mov   rax, var1
   mov   rdx, var2
   add   rax, rdx
   ret
add2ints   ENDP


mult2ints   PROC   var1:QWORD, var2:QWORD
   mov    rax, var1
   mov    rdx, var2
   imul    rax, rdx
   ret
mult2ints   ENDP

END   

...And here is the code for the caller:

Quote
include \masm32\include64\masm64rt.inc
;includelib   mymathfuncs.lib

add2ints PROTO :QWORD, :QWORD
mult2ints PROTO :QWORD, :QWORD
printf   PROTO :QWORD, :VARARG\

EXTERNDEF   myint:QWORD

.data
int1   QWORD   10h
int2    QWORD   30h
frmt1   BYTE   "The result of the addition is %d",13,10,0
strname BYTE   "mymathfuncs",0
dataname BYTE   "myint",0

.data?
libname   QWORD   ?

.code
main   PROC


   ;invoke   LoadLibrary, addr strname
   ;mov   rcx, rax
   ;invoke   GetProcAddress, rcx, addr dataname   
   ;mov   rcx, rax
   ;mov   libname, rax
   ;mov   rcx, qword ptr[rax]
   lea   rcx, myint
   mov   rcx, qword ptr[rcx]
   mov   rdx, int1
   invoke   add2ints, rcx, rdx
   mov   rdx, rax
   invoke   printf, ADDR frmt1, rdx
   invoke   FreeLibrary, libname

   ret
main   ENDP
END

As I say this doesn't work.  Note the commented-out section of code in the caller.  If one un-comments this the resulting explicit LoadLibrary call finds MYINT successfully.  I have included .zip files for both of these programs along with a little bat file to make them.

Your second method is very clever indeed.  I wish I had though of it.  If I recall my smattering of C++ there is a similar technique used in classes for data declared private.

Regards,
Mark


markallyn

For some reason the two .asm files did not get included in the previous post.  Trying again.

Mark

sinsi

Here is a working? copy of accessing myint
🍺🍺🍺

markallyn

Good evening, Sinsi,

After posting the code on the forum I wentt back and discovered that I had messed up the caller with two bad instructions.  Don't know how it happened, but it did.  So,, the correct caller is this:
Quote
include \masm32\include64\masm64rt.inc
includelib   mymathfuncs.lib

add2ints PROTO :QWORD, :QWORD
mult2ints PROTO :QWORD, :QWORD
printf   PROTO :QWORD, :VARARG\



.data
int1   QWORD   10h
int2    QWORD   30h
frmt1   BYTE   "The result of the addition is %d",13,10,0
strname BYTE   "mymathfuncs",0
dataname BYTE   "myint",0

.data?
libname   QWORD   ?

.code
main   PROC


   invoke   LoadLibrary, addr strname
   mov   rcx, rax
   invoke   GetProcAddress, rcx, addr dataname   
   mov   rcx, rax
   mov   libname, rax
   mov   rcx, qword ptr[rcx]
   mov   rdx, int1
   invoke   add2ints, rcx, rdx
   mov   rdx, rax
   invoke   printf, ADDR frmt1, rdx
   invoke   FreeLibrary, libname

   ret
main   ENDP
END

I will have a look at your .zip file to see what you did.  I also want to duplicate your use of a .dll function to access the .data section.

Thanks,
Mark Allyn

markallyn

Good evening, again, Sinsi,

OK, I see what you did to make EXTERNDEF work.  Now I have a beginner's question.  How did you know to prefix myint with __imp_?  Is this standard for all exported data and functions in a DLL? 

Thanks again,
Mark Allyn

sinsi

Good morning Mark,

I didn't like the usual way the linker usually does imports - a call to a jump to an address, I preferred just a call to an address.
To do that you use the _imp__ version from the lib
🍺🍺🍺

six_L

hi,markallyn
here is another mothod
option casemap:none
option win64:7

include \masm\asm64\UASM\UASM64\include\windows.inc

includelib \masm\asm64\UASM\UASM64\Lib\user32.lib
includelib \masm\asm64\UASM\UASM64\Lib\kernel32.lib

ICO_MAIN equ 1000
DLG_MAIN equ 100
IDC_CLEAR equ 101
IDC_ADD equ 102
IDC_SUB equ 103
IDC_MUL equ 104
IDC_DIV equ 105
IDC_INPUT1 equ 106
IDC_INPUT2 equ 107
IDC_RESULT1 equ 108
IDC_RESULT2 equ 109
IDC_RESULT3 equ 110
IDC_RESULT4 equ 111
IDC_RESULT0 equ 112

_Padd2ints typedef proto :qword,:qword
_Psub2ints typedef proto :qword,:qword
_Pmult2ints typedef proto :qword,:qword
_Pdiv2ints typedef proto :qword,:qword

Padd2ints typedef ptr _Padd2ints
Psub2ints typedef ptr _Psub2ints
Pmult2ints typedef ptr _Pmult2ints
Pdiv2ints typedef ptr _Pdiv2ints

.data?
hInstance dq ?
hWinMain dq ?
hCalc_1dll dq ?
lPadd2ints Padd2ints ?
lPsub2ints Psub2ints ?
lPmult2ints Pmult2ints ?
lPdiv2ints Pdiv2ints ?
Addr_myint dq ?
myint dq ?

.code

atodq proc uses rsi rdi String:QWORD
; ----------------------------------------
; Convert decimal string into qword value
; return value in rax
; ----------------------------------------

xor rax, rax
mov rsi, [String]
xor rcx, rcx
xor rdx, rdx
mov al, [rsi]
inc rsi
cmp al, "-"
jne proceed
mov al, [rsi]
not rdx
inc rsi
jmp proceed
@@:
sub al, 30h
lea rcx, qword ptr [rcx+4*rcx]
lea rcx, qword ptr [rax+2*rcx]
mov al, [rsi]
inc rsi
proceed:
or al, al
jne @B
lea rax, qword ptr [rdx+rcx]
xor rax, rdx
ret

atodq endp

_GetArithmeticResult proc uses rbx AriFlag:QWORD
local Idc_result:dword
local num1Buf[64]:byte
local num2Buf[64]:byte
local OutBuf[128]:byte

invoke RtlZeroMemory,ADDR num1Buf, sizeof num1Buf
invoke RtlZeroMemory,ADDR num2Buf, sizeof num2Buf
invoke RtlZeroMemory,ADDR OutBuf, sizeof OutBuf
invoke GetDlgItemText,hWinMain,IDC_INPUT1,ADDR num1Buf,sizeof num1Buf
invoke GetDlgItemText,hWinMain,IDC_INPUT2,ADDR num2Buf,sizeof num2Buf

invoke atodq,addr num1Buf
mov rbx,rax
invoke atodq,addr num2Buf
.if AriFlag==1
invoke lPadd2ints,rbx,rax
mov Idc_result,IDC_RESULT1
.elseif AriFlag==2
invoke lPsub2ints,rbx,rax
mov Idc_result,IDC_RESULT2
.elseif AriFlag==3
invoke lPmult2ints,rbx,rax
mov Idc_result,IDC_RESULT3
.elseif AriFlag==4
invoke lPdiv2ints,rbx,rax
mov Idc_result,IDC_RESULT4
.else
invoke MessageBox,NULL,CStr("AriFlag Failed"),CStr("_GetArithmeticResult"),MB_OK
jmp @Exit
.endif

invoke wsprintf,addr OutBuf,CStr("%d"),rax
invoke SetDlgItemText,hWinMain,Idc_result,addr OutBuf

mov rax,Addr_myint
mov rcx,[rax]
mov myint,rcx
invoke RtlZeroMemory,ADDR OutBuf, sizeof OutBuf
invoke wsprintf,addr OutBuf,CStr("%d"),myint
invoke SetDlgItemText,hWinMain,IDC_RESULT0,addr OutBuf
@Exit:
ret

_GetArithmeticResult endp

_ProcDlgMain proc hWnd:qword,wMsg:dword,wParam:qword,lParam:qword

mov eax,wMsg
.if eax == WM_INITDIALOG
push hWnd
pop hWinMain
invoke LoadIcon,hInstance,ICO_MAIN
invoke SendMessage,hWnd,WM_SETICON,ICON_BIG,eax
invoke LoadLibrary,CStr("calc_1.dll")
.if eax
mov hCalc_1dll,rax
invoke GetProcAddress,hCalc_1dll,CStr("add2ints")
mov lPadd2ints,rax
invoke GetProcAddress,hCalc_1dll,CStr("sub2ints")
mov lPsub2ints,rax
invoke GetProcAddress,hCalc_1dll,CStr("mult2ints")
mov lPmult2ints,rax
invoke GetProcAddress,hCalc_1dll,CStr("div2ints")
mov lPdiv2ints,rax

invoke GetProcAddress,hCalc_1dll,CStr("myint")
mov Addr_myint,rax
.else
invoke MessageBox,NULL,CStr("calc_1.dll load Failed"),CStr("LoadLibrary"),MB_OK
.endif

.elseif eax == WM_COMMAND
mov rax,wParam
.if ax == IDC_CLEAR
invoke SetDlgItemText,hWnd,IDC_INPUT1,NULL
invoke SetDlgItemText,hWnd,IDC_INPUT2,NULL
invoke SetDlgItemText,hWnd,IDC_RESULT0,NULL
invoke SetDlgItemText,hWnd,IDC_RESULT1,NULL
invoke SetDlgItemText,hWnd,IDC_RESULT2,NULL
invoke SetDlgItemText,hWnd,IDC_RESULT3,NULL
invoke SetDlgItemText,hWnd,IDC_RESULT4,NULL
.elseif ax == IDC_ADD
invoke _GetArithmeticResult,1
.elseif ax == IDC_SUB
invoke _GetArithmeticResult,2
.elseif ax == IDC_MUL
invoke _GetArithmeticResult,3
.elseif ax == IDC_DIV
invoke _GetArithmeticResult,4
.endif
.elseif eax == WM_CLOSE
invoke FreeLibrary,hCalc_1dll
invoke EndDialog,hWnd,NULL
.else
mov rax,FALSE
ret
.endif
mov rax,TRUE
ret

_ProcDlgMain endp

start Proc
invoke GetModuleHandle,NULL
mov hInstance,rax

invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL

invoke ExitProcess,NULL
start Endp


end



    \UASM64\bin\uasm64 -c -win64 %name%.bat
    \UASM64\bin\rc %name%.rc
    \UASM64\bin\link /ENTRY:start /SUBSYSTEM:windows /MACHINE:X64 %name%.obj %name%.res


option casemap:none
option win64:7

include \UASM64\include\windows.inc

includelib \UASM64\Lib\user32.lib
includelib \UASM64\Lib\kernel32.lib

.data?
public  myint
myint   qword   ?

.code

DllEntry PROC hInstDLL:HINSTANCE, reason:QWORD, @reserved:QWORD
mov myint,0h
mov rax, TRUE
ret
DllEntry ENDP

add2ints PROC var1:QWORD, var2:QWORD           
mov myint,0fh
mov rax, var1
mov rdx, var2
add rax, rdx
ret
add2ints ENDP

sub2ints PROC var1:QWORD, var2:QWORD           
mov myint,0ah
mov rax, var1
mov rdx, var2
sub rax, rdx
ret
sub2ints ENDP

mult2ints PROC var1:QWORD, var2:QWORD
mov myint,08h
mov rax, var1
mov rcx, var2
xor rdx, rdx
imul    rcx
ret
mult2ints ENDP

div2ints PROC var1:QWORD, var2:QWORD
mov myint,0ffffh
mov rax, var1
mov rcx, var2
xor rdx,rdx
idiv    rcx
ret
div2ints ENDP


end DllEntry


    \UASM64\bin\uasm64 -c -win64 %name%.bat
    \UASM64\bin\link /subsystem:windows /section:.bss,S /Def:%name%.def /Dll %name%.obj



LIBRARY calc
EXPORTS myint
EXPORTS add2ints
EXPORTS sub2ints
EXPORTS mult2ints
EXPORTS div2ints


#include <\UASM64\include\resource.h>

#define ICO_MAIN 1000
#define DLG_MAIN 100
#define IDC_CLEAR 101
#define IDC_ADD 102
#define IDC_SUB 103
#define IDC_MUL 104
#define IDC_DIV 105
#define IDC_INPUT1 106
#define IDC_INPUT2 107
#define IDC_RESULT1 108
#define IDC_RESULT2 109
#define IDC_RESULT3 110
#define IDC_RESULT4 111
#define IDC_RESULT0 112

ICO_MAIN ICON "Charfx.ico"

DLG_MAIN DIALOG 0, 0, 234, 95
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Test_calc"
FONT 10, "Calibri"
{
LTEXT "Num1", -1, 42, 9, 40, 10
EDITTEXT IDC_INPUT1, 42, 18, 60, 14,ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP 
LTEXT "Num2", -1, 132, 9, 105, 10
EDITTEXT IDC_INPUT2, 132, 18, 60, 14,ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP
PUSHBUTTON "Add(&a)", IDC_ADD, 14, 44, 30, 12
EDITTEXT IDC_RESULT1, 2, 58, 50, 14,ES_AUTOHSCROLL | ES_READONLY | WS_BORDER | WS_TABSTOP 
PUSHBUTTON "Sub(&b)", IDC_SUB, 73, 44, 30, 12
EDITTEXT IDC_RESULT2, 62, 58, 50, 14,ES_AUTOHSCROLL | ES_READONLY | WS_BORDER | WS_TABSTOP 
PUSHBUTTON "Mul(&m)", IDC_MUL, 133, 44, 30, 12
EDITTEXT IDC_RESULT3, 122, 58, 50, 14,ES_AUTOHSCROLL | ES_READONLY | WS_BORDER | WS_TABSTOP 
PUSHBUTTON "Div(&d)", IDC_DIV, 193, 44, 30, 12
EDITTEXT IDC_RESULT4, 182, 58, 50, 14,ES_AUTOHSCROLL | ES_READONLY | WS_BORDER | WS_TABSTOP 

LTEXT "Myint:", -1, 2, 81, 20, 10
EDITTEXT IDC_RESULT0, 24, 78, 40, 14,ES_AUTOHSCROLL | ES_READONLY | WS_BORDER | WS_TABSTOP 
PUSHBUTTON "Clear(&c)", IDC_CLEAR, 191, 78, 40, 14
}
Say you, Say me, Say the codes together for ever.

markallyn

Sinsi and six_L,

Sinsi,

Perhaps you would be willing to clarify how the linker works.  When I use your EXTERNDEF technique and examine the object file for callmathfuncs with dumpbin /symbols command __imp_myint is shown in the output.  Interestingly, (to me anyway), the __imp prefix is not applied to the two functions in the .dll (multints, addints).  I;m guessing (literally) that this has to do with the use of the PROTO directive in the assembly language file.  I guess a test of this would be to use the EXTERNDEF technique with the two functions and see what the .obj file looks like.  I imagine that if I substitute EXTERNDEFs for the two PROTOs I can't use the INVOKE command....

six_L:  Your response was very comprehensive.  I need more time to thoroughly understand it. 

I've been out of pocket for two days and wasn't able to get back to you folks as soon as I would have liked.

Regards,
Mark

markallyn

Sinsi, six_L,

So I tested my EXTERNDEF question.  If I use EXTERNDEF to define a function -- in this case, mult2ints -- as EXTERNDEF __imp_mult2ints:PROC, then indeed in the callmathfuncs.obj file mult2ints shows up as __imp_mult2ints.  Interesting. 

Regards,
Mark Allyn