News:

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

Main Menu

Length Error when calling DLL from high level language

Started by markB, June 25, 2017, 05:40:16 AM

Previous topic - Next topic

markB

I have written a DLL in MASM to call from a high-level language.  The proc assembles correctly and the DLL is created and placed in the proper directory. 

When I call this DLL, I get the following error:  Length Error. 

Here is the PROC header for the MASM code.  It returns a pointer to the variable BlueLineConfig. 

_____

TM460_Pvtx_Values_Sub1 Proc USES ebp Last20EBands1:PTR DWord

mov ebp,Last20EBands1
BlueLineConfig dd 4 dup (0)
mov edi,OFFSET BlueLineConfig

mov eax,DWORD PTR[ebp+114]
mov ebx,DWORD PTR[ebp+108]

[remaining code]

* * *
mov eax,[edi]

RET

TM460_Pvtx_Values_Sub1 EndP

end LibMain
_____

This Proc takes only one input, an array of 140 elements, in DWord form.  I can't see why I would get a Length Error when I am passing exactly what I specified. 

Thanks very much for any help. 


aw27

Although I don't see more than a procedure of your "DLL", what you sport is amazing - it is the first time in my life I see someone save the ebp register in a USES clause. On the other hand I don't see you save any of the other registers that should be preserved across function calls.  :icon_rolleyes:

QuoteIt returns a pointer to the variable BlueLineConfig
You spelled correctly, but I still don't see what is BlueLineConfig doing in the middle of the code?


markB

Thanks for your reply.  Here is the entire code.  There is only one Proc.  I have changed it to push edi as well as ebp, but I still get the same Length Error when calling from the HLL. 


LibMain proc instance:DWORD,reason:DWORD,unused:DWORD

    .if reason == DLL_PROCESS_ATTACH
      mrm hInstance, instance       ; copy local to global
      mov eax, TRUE                 ; return TRUE so DLL will start

    .elseif reason == DLL_PROCESS_DETACH

    .elseif reason == DLL_THREAD_ATTACH

    .elseif reason == DLL_THREAD_DETACH

    .endif

    ret

LibMain endp

;***********

TM460_Pvtx_Values_Sub1 Proc USES edi ebp Last20EBands1:PTR DWord

mov ebp,Last20EBands1
BlueLineConfig dd 4 dup (0)
mov edi,OFFSET BlueLineConfig

;__________

mov eax,DWORD PTR[ebp+114]
mov ebx,DWORD PTR[ebp+108]

cmp eax,ebx

.IF eax > ebx
mov eax,1
mov [edi+0],ebx
.ENDIF
;__________

mov eax,DWORD PTR[ebp+114]
mov ebx,DWORD PTR[ebp+108]

cmp eax,ebx

.IF eax < ebx
mov eax,2
mov [edi+0],ebx
.ENDIF
;__________

mov eax,DWORD PTR[ebp+114]
mov ebx,DWORD PTR[ebp+108]

cmp eax,ebx

.IF eax == ebx
mov eax,0
mov [edi+0],ebx
.ENDIF

;__________

mov eax,DWORD PTR[ebp+120]
mov ebx,DWORD PTR[ebp+114]

cmp eax,ebx

.IF eax > ebx
mov eax,1
mov [edi+4],ebx
.ENDIF

;__________

mov eax,DWORD PTR[ebp+120]
mov ebx,DWORD PTR[ebp+114]

cmp eax,ebx

.IF eax < ebx
mov eax,2
mov [edi+4],ebx
.ENDIF

;__________

mov eax,DWORD PTR[ebp+120]
mov ebx,DWORD PTR[ebp+114]

cmp eax,ebx

.IF eax == ebx
mov eax,0
mov [edi+4],ebx
.ENDIF

;__________

mov eax,[edi]

RET

TM460_Pvtx_Values_Sub1 EndP

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end LibMain

jj2007

The dd 4 dup(0) inserts a series of add [eax], al into your code section. No problem if eax points to some reasonable memory location, but that is hardly what you intended 8)

Which language calls that DLL? And how do you know that [ebp+114] contains something useful?

aw27

Quote from: markB on June 25, 2017, 06:21:29 AM
Thanks for your reply.  Here is the entire code.  There is only one Proc.  I have changed it to push edi as well as ebp, but I still get the same Length Error when calling from the HLL. 
You must preserve all registers except eax, ecx and edx wish are assumed to be trashed inside the function.
So, save ebx.
It may not be enough to make your dll work, as mentioned there are other strange things in the code, namely BlueLineConfig must be moved to the .data sectiom, it is not doing anything in the code section and can't be even written to because Windows does not allow that for security reasons.

markB

I have pushed the registers eax - edx and popped them at the end, and the BlueLineConfig declaration has been moved to the .data section.  However, I am still returned a length error.  I do not know if the error refers to the data passed to the DLL or the data returned by it.  I am continuing to investigate. 



aw27

Quote from: markB on June 25, 2017, 07:34:46 AM
I have pushed the registers eax - edx and popped them at the end, and the BlueLineConfig declaration has been moved to the .data section.  However, I am still returned a length error.  I do not know if the error refers to the data passed to the DLL or the data returned by it.  I am continuing to investigate.
I told you to save ebx, why do you save the registers that don't need to be saved?
To track where the error comes from use  a debugger.

markB

I saved the other registers out of caution.  They are popped back at the end.  Earlier I had pushed only ebx, but I got the same error so I pushed the others.  Will that cause any problems? 

The HLL I am calling this from does not have a debugger.  I encounter the problem upon the call from the HLL to the DLL. 


jj2007

Quote from: jj2007 on June 25, 2017, 06:38:03 AMWhich language calls that DLL? And how do you know that [ebp+114] contains something useful?

markB

It's called from Python.  ebp+114 contains useful data -- the array passed has 140 integers (560 bytes). 


jj2007

Interesting. It is possible to call Python from Assembler (Printing a sinus via the FPU, the CRT, the GSL, and Python), but I never tried the other way round.

Re "ebp+114 contains useful data" - how did you test this? It is very unusual to have an array in this location, normally you would simply pass a pointer to the array on the stack (and yes, it would be somewhere at [ebp+x]).

Can you post a snippet that shows how you pass this array from Python to Masm?

HSE

Theoretically not needed if I remmember well, but you can try:

Replace:mov edi,OFFSET BlueLineConfig
by:lea edi, BlueLineConfig

lea store the complete location of BlueLineConfig, not only the offset (here I think only offset is necessary).
But you have to be sure in [ebp+114] and [ebp+108] are saved complete direccions and not only offset (this is what JJ is asking).

Ok, just what is coming in Last20EBands is relevant
Equations in Assembly: SmplMath

aw27

Quote from: markB on June 25, 2017, 07:34:46 AM
I do not know if the error refers to the data passed to the DLL or the data returned by it.  I am continuing to investigate.
I don't see any error reporting facility in the DLL, so it is Python reporting.

Quote
The HLL I am calling this from does not have a debugger.
It is always possible to debug a DLL, but is not straightforward. However, being or not being a DLL is irrelevant in this case, you can easily produce an all-masm test application.

EX:
.686
.model Flat, Stdcall
option Casemap :None 

.data
value dword[100]

.code

TM460_Pvtx_Values_Sub1 Proc USES edi ebp Last20EBands1:PTR DWord
   mov ebp, Last20EBands1
   ; etc, etc
   ret
TM460_Pvtx_Values_Sub1 endp

main PROC
   INVOKE TM460_Pvtx_Values_Sub1, addr value
   ret
main ENDP
END main

(Not tested, just to pass the idea)


markB

The Python call is:

thisdll = cdll.LoadLibrary("C:\\TM460.dll")
result= thisdll.GetValues(Last20EB1)
_____

The array passed to GetValues (Last20EB1) is a 140-element array of DWords. 

"It is very unusual to have an array in this location, normally you would simply pass a pointer to the array on the stack (and yes, it would be somewhere at [ebp+x])."
ebp is assigned to Last20EBands1 at the top of the MASM code:

TM460_Pvtx_Values_Sub1 Proc USES edi ebp Last20EBands1:PTR DWord

* * *

mov ebp,Last20EBands1

So the index to ebp+114 is an index to that location in the array that was passed in and assigned to ebp. 



jj2007

Quote from: markB on June 25, 2017, 09:43:05 AM
mov ebp,Last20EBands1

So the index to ebp+114 is an index to that location in the array that was passed in and assigned to ebp.

OK, that makes sense. I made a little test with Python 3.4.3 - is this roughly the syntax you are using?

import ctypes
hAlgos = ctypes.WinDLL("StringAlgos")
# Instring proc ; StartPos, lpSource, lpPattern, sMode
hAlgos.Instring.restype = ctypes.c_char_p
print('match: ')
print(hAlgos.Instring(1,"This is a string", "string", 0))


The StringAlgos.dll is attached.

You know that you can use Olly as Just In Time debugger? It works fine, and would allow to see what goes wrong under the hood. It's a can of worms btw, here is what happens when you return from the DLL:CPU Disasm
Address           Hex dump                     Command                            Comments
1D1ADDD7          ³.  FF55 1C                  call near [ebp+1C]                 ; dive into the DLL
1D1ADDDA          ³.  8B4D 0C                  mov ecx, [ebp+0C]
1D1ADDDD          ³.  8B09                     mov ecx, [ecx]
1D1ADDDF          ³.  8B09                     mov ecx, [ecx]


> thisdll.GetValues(Last20EB1)
Can you add a little console print to the DLL to see if [ebp+0],  [ebp+4],  [ebp+8] contain the expected values?