News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

DLL to LIB unresolved external symbol

Started by 2B||!2B, November 05, 2018, 04:39:40 PM

Previous topic - Next topic

2B||!2B

Hi,

I have tried the tool Dll2lib from http://www.binary-soft.com/ to convert my Delphi 7 DLL to a static library.

However, no matter what i try, i always get linker error

error LNK2001: unresolved external symbol _AddNumbers@8

My delphi dll looks like this

library MyDLL;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }

uses
//ShareMem,
  SysUtils,
  Classes,
  Windows,
  Controls,
  Forms,
  ImgList,
  Unit1 in 'Unit1.pas' {Form1};

  function AddNumbers(a:Integer;b:Integer):Integer;stdcall;forward;





exports  AddNumbers;



{$R *.res}



function AddNumbers(a:Integer;b:Integer):Integer  ;  stdcall;




begin
  Result  := a + b;

end;
end.


MASM calling


includelib MyDLL.lib ;The one generated by dll2lib.
AddNumbers   PROTO :DWORD,:DWORD
invoke AddNumbers,1,2


I have also tried this one here http://www.ionicwind.com/forums/index.php?topic=1361.0
I got the same result about linking error.

Does anyone know if this is possible at all?

jj2007

Write a little module that contains AddNumbers, and link the obj file together with the obj file obtained from the DLL.

2B||!2B

The problem is that Delphi does not generate COFF obj file format but rather OMF obj format.
I have already converted it to COFF obj file with objconv tool. When i link this converted obj file, it still unable to resolve the external symbols.

jj2007

Quote from: 2B||!2B on November 05, 2018, 08:59:37 PMWhen i link this converted obj file, it still unable to resolve the external symbols.

Well... do you link it with a module that does contain the correctly prototyped AddNumbers? Try something like this:
.486                                      ; create 32 bit code
.model flat, stdcall                      ; 32 bit memory model

.code
AddNumbers proc int1, int2
  mov eax, int1
  add eax, int2
  ret
AddNumbers endp
end

sinsi

Try dumping the .lib to see how AddNumbers is declared. Maybe this will work?

_imp__AddNumbers@8 PROTO :dword,:dword
AddNumbers TEXTEQU <_imp__AddNumbers@8>


Mikl__

Hi, to be or not to be!
look here I think that much will be clear without translation, but in the extreme case, you can use the online service Google Translator

2B||!2B

#6
Quote from: jj2007 on November 05, 2018, 09:09:16 PM
Quote from: 2B||!2B on November 05, 2018, 08:59:37 PMWhen i link this converted obj file, it still unable to resolve the external symbols.

Well... do you link it with a module that does contain the correctly prototyped AddNumbers? Try something like this:
.486                                      ; create 32 bit code
.model flat, stdcall                      ; 32 bit memory model

.code
AddNumbers proc int1, int2
  mov eax, int1
  add eax, int2
  ret
AddNumbers endp
end


Yes, i did. Both .lib and obj gives the same linking error.


Quote from: sinsi on November 05, 2018, 09:24:54 PM
Try dumping the .lib to see how AddNumbers is declared. Maybe this will work?

_imp__AddNumbers@8 PROTO :dword,:dword
AddNumbers TEXTEQU <_imp__AddNumbers@8>


It does not work. It also shows the linking error with this function name but rather with double @8


Quote from: Mikl__ on November 05, 2018, 09:40:17 PM
Hi, to be or not to be!
look here I think that much will be clear without translation, but in the extreme case, you can use the online service Google Translator

Hey Mikl__,

Thanks for your link. I will have to read this carefully after translating it. See if i can get anywhere.


I have attached the example if someone might want to take a look at it.
It contains the dll and the static library.

MyDLL.lib - generated by dll2lib

TimoVJL

#7
Delphi dll exports undecorated function names, so converter can't know that decorated name.

EDIT:library MyDLL;

function AddNumbers(a:Integer;b:Integer):Integer;stdcall;forward;

exports
  AddNumbers, AddNumbers name '_AddNumbers@8';

function AddNumbers(a:Integer;b:Integer):Integer  ;  stdcall;
begin
  Result  := a + b;
end;
end.

EDIT: Dll to Dll can use dll's import library.
May the source be with you

sinsi

You may have more than one problem.

Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

MyDLL.lib(MyDLL.obj) : warning LNK4078: multiple ".edata" sections found with different attributes (50100040)
MyDLL.lib(MyDLL.obj) : warning LNK4078: multiple ".rsrc" sections found with different attributes (50100040)
LINK : fatal error LNK1104: cannot open file "LIBC.lib"


Added this code

prAddNumbers TYPEDEF PROTO STDCALL  :DWORD,:DWORD
PAddNumbers TYPEDEF PTR prAddNumbers
EXTERNDEF AddNumbers:PAddNumbers

No complaints about AddNumbers

edit: using "includelib libc.lib" then complains about a missing oldnames.lib (libc is in the masm32\lib folder but oldnames isn't)

hutch--

I guess it depends on the type of lib you want to get from the DLL. I would imagine that am import library would be no big deal if you can match the calling convention but a static library derived from a DLL is far more problematic in what you have to do to get it to work. The conversion tool has to be able to identify the start and end of each procedure, correctly identify any function it imports from system DLLs and get all of the OFFSETs right.

An old friend of mine years ago (Jeremy Collake) was writing tools like this but they were always problematic as the form of DLLs is very diverse, particularly if you are using Borland compilers which differ from Microsoft compilers.

aw27

I use Delphi since immemorial times, last version I purchased was XE2 which supports the COFF format. Previous versions use the OMF as you know. If this helps in any way, I have never been able to make a proper OMF to COFF conversion using any utility including objconv. There is an article in CodeProject that may help you somehow.

Vortex

Hi  2B||!2B,

The OMF format is an antique specification dating from the late 70s. It's possible to employ DLLs like "static libraries" The trick is to write your own custom PE loader.

2B||!2B

Quote from: TimoVJL on November 05, 2018, 11:05:42 PM
Delphi dll exports undecorated function names, so converter can't know that decorated name.

EDIT:library MyDLL;

function AddNumbers(a:Integer;b:Integer):Integer;stdcall;forward;

exports
  AddNumbers, AddNumbers name 'AddNumbers@8';

function AddNumbers(a:Integer;b:Integer):Integer  ;  stdcall;
begin
  Result  := a + b;
end;
end.


I don't think this is the problem. I have tried to use the name AddNumbers@8 but it still has the same linking error.

Quote from: sinsi on November 05, 2018, 11:14:51 PM
You may have more than one problem.

Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

MyDLL.lib(MyDLL.obj) : warning LNK4078: multiple ".edata" sections found with different attributes (50100040)
MyDLL.lib(MyDLL.obj) : warning LNK4078: multiple ".rsrc" sections found with different attributes (50100040)
LINK : fatal error LNK1104: cannot open file "LIBC.lib"


Added this code

prAddNumbers TYPEDEF PROTO STDCALL  :DWORD,:DWORD
PAddNumbers TYPEDEF PTR prAddNumbers
EXTERNDEF AddNumbers:PAddNumbers

No complaints about AddNumbers

edit: using "includelib libc.lib" then complains about a missing oldnames.lib (libc is in the masm32\lib folder but oldnames isn't)

Hi sinsi,

Very good way of fixing this  :greenclp:
oldnames.lib is found in C:\Program Files\Microsoft Visual Studio\VC98\Lib if you have the VC6.0
It worked fine with me without the need of linking libc and oldnames.lib. However, there is one issue
the compiled exe turned out to use a call to a pointer rather than a direct call to the function using the Invoke keyword.

00401000 >  6A 0A           PUSH 0A
00401002    6A 0A           PUSH 0A
00401004    FF15 B2104000   CALL DWORD PTR DS:[4010B2]



But at 4010B2 is the function itself not a pointer to function

4010B2 - AddNumbers successfully compiled
004010B2    55              PUSH EBP
004010B3    8BEC            MOV EBP,ESP
004010B5    8B45 08         MOV EAX,DWORD PTR SS:[EBP+8]
004010B8    0345 0C         ADD EAX,DWORD PTR SS:[EBP+C]
004010BB    5D              POP EBP                                  ; kernel32.7742EE6C
004010BC    C2 0800         RETN 8





Quote from: hutch-- on November 06, 2018, 01:19:02 AM
I guess it depends on the type of lib you want to get from the DLL. I would imagine that am import library would be no big deal if you can match the calling convention but a static library derived from a DLL is far more problematic in what you have to do to get it to work. The conversion tool has to be able to identify the start and end of each procedure, correctly identify any function it imports from system DLLs and get all of the OFFSETs right.

An old friend of mine years ago (Jeremy Collake) was writing tools like this but they were always problematic as the form of DLLs is very diverse, particularly if you are using Borland compilers which differ from Microsoft compilers.

Hi hutch,

I think you are right. Delphi is very diverse in it's way of laying out the resources, the classes, and the forms.
Take a look here https://stackoverflow.com/questions/16892601/omf-format-to-coff-format


Quote from: AW on November 06, 2018, 03:30:56 AM
I use Delphi since immemorial times, last version I purchased was XE2 which supports the COFF format. Previous versions use the OMF as you know. If this helps in any way, I have never been able to make a proper OMF to COFF conversion using any utility including objconv. There is an article in CodeProject that may help you somehow.

Hi AW,

Thanks for the link.
Yes, you are right. I found Delphi 7 To be different in many ways. Haven't used Delphi X2
See the stackoverflow link i posted above to hatch.

Quote from: Vortex on November 06, 2018, 05:08:50 AM
Hi  2B||!2B,

The OMF format is an antique specification dating from the late 70s. It's possible to employ DLLs like "static libraries" The trick is to write your own custom PE loader.

Hi Vortex,

Do you mean loading the DLL directly to memory and then resolve imports/exports/relocs etc and then call the functions directly in memory?

Vortex

QuoteDo you mean loading the DLL directly to memory and then resolve imports/exports/relocs etc and then call the functions directly in memory?

Exactly. You can check the DLLmem example in the attachment.


TimoVJL

#14
Quote from: 2B||!2B on November 06, 2018, 07:24:39 AM
Quote from: TimoVJL on November 05, 2018, 11:05:42 PM
Delphi dll exports undecorated function names, so converter can't know that decorated name.

EDIT:library MyDLL;

function AddNumbers(a:Integer;b:Integer):Integer;stdcall;forward;

exports
  AddNumbers, AddNumbers name 'AddNumbers@8';

function AddNumbers(a:Integer;b:Integer):Integer  ;  stdcall;
begin
  Result  := a + b;
end;
end.


I don't think this is the problem. I have tried to use the name AddNumbers@8 but it still has the same linking error.
My bad,
exports
  AddNumbers, AddNumbers name '_AddNumbers@8';
I made a test ;)
EDIT: Dll2Lib support import lib for decorated names.
EDIT: A test program in C:#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "msvcrt.lib")
//#pragma comment(lib, "MyDll.lib")
#pragma comment(lib, "MyDllS.lib")
int __stdcall AddNumbers(int, int);
void mainCRTStartup(void) {exit(main());}
int __cdecl main(void)
{
int n = AddNumbers(1,2);
printf("n=%d\n", n);
return 0;
}
May the source be with you