News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Duplicate PUBLIC sysmbols I didn't explicitly create.

Started by HiTechHiTouch, February 25, 2011, 06:05:57 AM

Previous topic - Next topic

HiTechHiTouch

I've got Delphi code calling a user plugin packaged in a DLL.  I have no source for the Delphi application, nor a sample plugin.  After a long debug session, I caught the call to the plugin and looked at the dis-assembley of the call sequence.  I believe I now know how Delphi passes parameters to called external programs.  It uses registers, similar to __FASTCALL, but not the same registers Microsoft uses.

Visual Studio 2010 C is my target language, but it does not understand the Delphi register calling convention.  Therefore I'm working on a tiny assembly language stub between Delphi and C, designed to alter the stack from Delphi to __STDCALL.

The stub is GetPluginInfo, included below.  The C routine it connects to is GetPluginInfo2.  Note that nowhere have I used either name with a leading underscore.

When the linker gets the MASM and the C objects, it reports a duplicate symbol error.  It seems MASM has defined another symbol, same as my entry point, but with an underscore in front.

Here's the linker messages:

PartnameCstub.obj :
error LNK2005: _GetPluginInfo already defined in PartnameCstub.obj
warning LNK4216: Exported entry point _GetPluginInfo


What's the story behind this symbol that I never put in my program?

(PS:  This is my very first stab at 386 assembler, and I've not tested this or stepped through with the debugger.  I expect you may find logic/coding errors where the instructions won't do what I think they will.)

Thanks!
----------------------
PartNameC.asm
----------------------
; GetPluginInfo Stub
;
;   Delphi calling convention is similar to __STDCALL, except that
;   the first parameters are passed in registers eax and ebx.
;
;   We will push those two onto the stack because Delphi did not,
;   and our C code __STDCALL function will be looking for them there.
;   Control then goes straight to our C function, which should pare
;   them off the stack before returning to Delphi.
;
;   Also, the return address is the last item on the stack, on top of
;   the parameters.  It will have to be moved up above the inserts.
;
;   Remember, the stack goes down to lower addresses.

.386
.model flat, c
.data
EXTERN GetPluginInfo2@8: ABS
GetPluginInfo2   DWORD   GetPluginInfo2@8
.code
;void __stdcall GetPluginInfo(PChar result, PChar value)
GetPluginInfo PROC EXPORT
   push   ebx         ; top two are now b, return ip
   mov      ebx,4[esp]   ; return address
   push   ebx         ; now have r-ip, b, r-ip
   mov      8[esp],eax   ; now r-ip, b, a
   mov      ebx,4[esp]   ; restore ebx
   jmp      GetPluginInfo2
GetPluginInfo ENDP
   END      GetPluginInfo

------------------
PartNameC.c
------------------
void extern __stdcall GetPluginInfo2(PChar result, PChar value)
{
    logit("GetPluginInfo ask for '%s' returning '%s'\n", value, result);
    return;
}
//---------------------------------------------------------------------------

MichaelW

#1
AFAIK the Borland/ Delphi fastcall convention uses the Pascal parameter order (left to right), with the first three parameters in EAX, EDX, and ECX.

And the compiler/assembler adds the leading underscore.

Could the source of the problem be that both modules have the same base name?

eschew obfuscation

clive

You're using .MODEL FLAT, C  which means when you use a generic PROC/ENDP it will add an underscore because that is how the C calling convention and function naming work.

Perhaps you want to use PROC STDCALL, or PROC PASCAL, or without any specific naming/epilogue/prologue code?
It could be a random act of randomness. Those happen a lot as well.