Unresolved external symbol when creating a DLL

Started by sparhawk, February 03, 2007, 01:16:21 PM

Previous topic - Next topic

sparhawk

I have an external DLL where I don't have a sourcecod for. Since we need to modify some behaviour I'm now trying to implement a kind of wrapper which should suplement the original DLL. Now I ran into the following problems:

First problem is problably name mangling. There are functions in the original dll named like @@Objectname@functionname. At first I tried to create such a name with Visual Studio 6.0 but it doesn't accept it. Now I tried it with Masm32 and I have a similar problem. When I compile and link, then I get an unresolved symbol on that name. I have another procedure with a normal looking name, which works fine. I tried to do this with externdef but I constantly get errors because I don't really found any consistent description of the syntax. :(

the code looks like this:

Include file contains this:

_text segment para public 'CODE' use32

externdef C ProcedureName:near

_text ends


source file contains this:


_text segment para public 'CODE' use32
org 40100h
assume cs:_text
assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing

option proc:private

start PROC hInst:DWORD, PARA1:DWORD, PARA2:DWORD
MOV EAX, TRUE
RET
start ENDP


ProcedureName proto C

MOV EAX, 1
RET

_text ends

end start


It assembles without errors, but at linktime I get this error: error LNK2001: unresolved external symbol ProcedureName

So can somebody provide me with a working sample of how that should be used, or point me in the right direction where I can find info. A working sample would be the best, so I know for sure what it must look like, because I found several manuals explaining externdef but I don't get what I'm doing wrong from them.

Thanks!

Vortex

Hi sparhawk,

Welcome on board.

Here is a quick Masm example about creating and using functions with complicated name mangling.

sampleDLL.asm :

.386
.model flat,stdcall
option casemap :none

include \masm32\include\windows.inc

.code

LibMain PROC instance:DWORD,reason:DWORD,unused:DWORD

mov eax,TRUE
ret

LibMain ENDP

sum PROC C x:DWORD,y:DWORD ; procedures should be always defined between
; the PROC \ ENDP pair.
mov eax,x
add eax,y
ret

sum ENDP

ProcedureName PROC C

mov eax,1
ret

ProcedureName ENDP

@@Objectname@functionname PROC SYSCALL x:DWORD,y:DWORD

mov eax,x ; You can use the SYSCALL convention to specify
sub eax,y ; complicated C++ decorations.
ret ; stack balance maintained by the assembler

@@Objectname@functionname ENDP

@@Objectname@anotherfunc PROC SYSCALL x:DWORD,y:DWORD

mov eax,x
add eax,y
ret 8

@@Objectname@anotherfunc ENDP

END LibMain ; LibMain is the entry point of the DLL


Demo.asm :

.386
.model flat,stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
includelib sampleDLL.lib

sum PROTO C :DWORD,:DWORD
ProcedureName PROTO C
@@Objectname@functionname PROTO SYSCALL :DWORD,:DWORD
Objectname_functionname EQU <@@Objectname@functionname>
@@Objectname@anotherfunc PROTO SYSCALL
Objectname_anotherfunc EQU <pr2 PTR @@Objectname@anotherfunc>
; pr2 PTR to define Objectname_anotherfunc as STDCALL
.code

start:

invoke sum,10,20
invoke ProcedureName
invoke Objectname_functionname,30,10
invoke Objectname_anotherfunc,10,20
invoke ExitProcess,0

END start


You can examine Demo.exe under Ollydbg to see how different calling conventions are dealing with the stack.

[attachment deleted by admin]

sparhawk

Quote from: Vortex on February 04, 2007, 02:46:54 PM
Welcome on board.

Thanks! :)

QuoteHere is a quick Masm example about creating and using functions with complicated name mangling.

That's really appreciated. I'm trying it as soon as I get back home tonight. :)


This is the part that I don't understand:
Quote
ProcedureName PROC C

   mov   eax,1
   ret

ProcedureName ENDP

@@Objectname@functionname PROC SYSCALL x:DWORD,y:DWORD

   mov   eax,x               ; You can use the SYSCALL convention to specify
   sub   eax,y               ; complicated C++ decorations.
   ret                     ; stack balance maintained by the assembler

@@Objectname@functionname ENDP

When I look at my code there is not much difference there. But it always balks at @@Objectname@functionname to export this functionname into the DLL. When I examine the resulting DLL, then ProcedureName has been exported but @@Objectname@functionname not.

QuoteYou can examine Demo.exe under Ollydbg to see how different calling conventions are dealing with the stack.

Calling conventions are not my problem. :) But it was quite some time since I last used assembly, and I'm a bit rusty when it comes down to the sourcecode syntax.

sparhawk

WOOT!  :U

It works now. I still get a linker error because of "unresolved external symbol __DllMainCRTStartup@12" which I don't really understand, because I removed all references to C. It seems that the linker automatically tries to link the C runtime startup code, which I don't need in this case anyway. I can compare this to my project at home, because there this doesn't happen, so I seem to have missed some configuration option somewhere.

But I don't really understand the difference between my code and yours. When I started I didn't use any fancy options and used only the procedure names just like in your example. Only after this did not work, I started to look for other things like this external and such. So why does it work now? Anyway, thanks for your help! :)

Vortex

Hello sparhawk,

Concerning the problem with decorated functions, you should check my module definition file coming with the attachment :

LIBRARY sampleDLL
EXPORTS
sum
ProcedureName
@@Objectname@functionname
@@Objectname@anotherfunc


You need to specify the entry point of your DLL to avoid the error message :

unresolved external symbol __DllMainCRTStartup@12

The entry point is specified by the statement END LibMain

QuoteIt seems that the linker automatically tries to link the C runtime startup code

Unless you don't specify it, Masm never uses C run-time libraries by default, could you post your source code here?

Here is how my DLL exports all the functions :


    ordinal hint RVA      name

          1    0 00001028 @@Objectname@anotherfunc
          2    1 0000101D @@Objectname@functionname
          3    2 00001017 ProcedureName
          4    3 0000100C sum


To get this list :

\masm32\bin\dumpbin /EXPORTS yourdll.dll

sparhawk

Quote from: Vortex on February 05, 2007, 06:20:00 PM
LIBRARY sampleDLL
EXPORTS
sum
ProcedureName
@@Objectname@functionname
@@Objectname@anotherfunc


I wrote such a def file already. As I said above it works fine now. :)

Quote
QuoteIt seems that the linker automatically tries to link the C runtime startup code

Unless you don't specify it, Masm never uses C run-time libraries by default, could you post your source code here?

The sourcecode is exactly the one you posted. But I'm using the Visual Studio environment as my IDE and I created an empty project for a DLL where the parameters to the linker are preconfigured by it. Since I use this IDE all the time, it's quite convenient, so I created the sourcefile and used custom build to assemble it using masm. Still I have done this with other projects as well, only with EXE, and there it didn't complain about the main() or something, so either it silently included that startup by itself, or I hit the right switch so that it ignores it. :)

QuoteHere is how my DLL exports all the functions :


    ordinal hint RVA      name

          1    0 00001028 @@Objectname@anotherfunc
          2    1 0000101D @@Objectname@functionname
          3    2 00001017 ProcedureName
          4    3 0000100C sum


To get this list :

\masm32\bin\dumpbin /EXPORTS yourdll.dll

Yes, that works fine now. I checked it in dependency walker and it looked exactly as I expected it. I resolved this issue with the CRTStartup now by including a small dummy cpp file that provides that function. I took the full sourcecode that you posted above, so I wonder that it didn't complain about LibMain conflicting with that __DllMainCRTStartup@12 because LibMain should also be an entrypoint, but __DllMainCRTStartup@12 probably supercedes the other one.

P1

Gerhard,

Welcome Aboard   :U

I noticed you are involved in a number of projects.  Is this going towards one of them?

Regards,  P1  :8)

sparhawk

Hi P1. :) If you mean the darkmod project, this is unrelated to it.I have done some things with assembly before, but nowadays it's more of a hobby, then actually doing much with it anymore. but it's quite handy to still know these things as it somtimes helps to work around bugs and problems where a vendor can not or doesn't want to fix his original software for whatever reason.

P1

Quote from: sparhawk on February 05, 2007, 10:33:24 PMbut it's quite handy to still know these things as it somtimes helps to work around bugs and problems where a vendor can not or doesn't want to fix his original software for whatever reason.
Been there, done that.  I'm the staff resource to make software behave.

Humbly dealing with other programmers/support personel, is my cross to bear, when my comments or suggestions go over their heads.  I can't work for everyone.  Aren't we paying them for support ???   Do I get a refund for fixing your software ???    :eek

Regards,  P1   :8)

sparhawk

Quote from: P1 on February 06, 2007, 05:47:57 PM
Been there, done that.  I'm the staff resource to make software behave.

Humbly dealing with other programmers/support personel, is my cross to bear, when my comments or suggestions go over their heads.  I can't work for everyone.  Aren't we paying them for support ???   Do I get a refund for fixing your software ???    :eek

Regards,  P1   :8)

I know what you mean. :) I always avoided work where I had to deal directly with customers, but even with fellow programmers it's sometimes hard. We had paid a lot of money for a MS subscripiton, and when we run across a problem it was luckily documented in MSDN - but wrongly. So I had to use assembly get access to the internal data structures to make it work. But to save MS, I also had a case where my only chance to find a bug was using SoftICE (it had to do with debugging a COM interface), and when we contacted MS I suprisingly found a hotline employee who actually know more than just reading me from the manual that I alreadh had studied up and down. It took some time, but there was such a woman who really knew her stuff. :)