2

Well i basically inherited a bunch of code that i was told to fix because it used to work a few months ago but it doesn't at the moment. The program itself seems to be riddled with linking errors and i was able to fix some of them. However I have run across a LNK2019 unresolved external _imp error where some function utilized in the main is not resolved. due to the "_imp" i am assuming that it is a problem related to importing from .dll or .lib files.

First of all i have three .lib files which i believe am importing them correctly into VS2010 and i have configured the platform to be 64x. There is also .dll files that correspond with the .lib files. The .h file that contains the declaration for these error ridden functions contain something like

ILAPI void ILAPIENTRY ilDeleteImage(const ILuint Num);

unfortunately i would be guessing that the definition is defined in the .dll file which i did not write myself so i am unsure. But since this is code that worked before i believe that i am getting this error because the linker can't find the definition rather than def/decl not matching reason.

when i hover over the ILAPI it states: "ILAPI __declspec(dllimport)" My current guess is that the program imports the .lib files and the .lib files use the .dll files to get the definition of the functions. I believe that i am importing the .lib files since the compiler no longer keeps on telling me that it can't find specific .lib files. However i am concerned that it may not be connecting the the .dll files. I am some what unsure. I have opened the .lib files and the .lib files contain the names of the functions that are giving errors. I have also used the dependency walker program to look at my DLL files and it has been giving me some of the following errors:

Error: At least one module has an unresolved import due to a missing export function in an implicitly dependent module.

Error: Modules with different CPU types were found.

Based on other peoples comments i feel like i can ignore the 2nd error. But i am unsure of the first error. I am also unsure if that would be the root cause of the problem. It may or may not be.

I have also looked inside the .lib files using VS cmd and dependency walker and it seems like the names of the functions that can't be found are listed in one of the .lib and .dll.

In terms of configuration I am running on release mode x64 platform. I have added "DevIL.lib ILU.lib ILUT.lib " library functions in the proj -> prop -> linker -> commandline. I have also added the path for linker -> general -> additional library directory. I have also tried messing with input additional dependency but it has no effect. The .lib and .dll files are put in the same directory as well. In the proj property configuration i do not mention .dll anywhere (am i supposed to? I've tried in various locations but just creates more error) I understand that there are a ton of posts regarding link 2019 error but i have not had good luck so far in my search for my particular problem. I would appreciate any suggestions, comment, or a link where i may find a clue as in to why this is occuring

here is the linker command from log:

here is the linker command from the build log itself:

Link: C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\x86_amd64\link.exe /ERRORREPORT:PROMPT /OUT:"x64\Release\dff.exe" /VERBOSE /INCREMENTAL /NOLOGO /LIBPATH:C:\Users\Sub2\Desktop\dff\x64\Release /MANIFEST /ManifestFile:"x64\Release\dff.exe.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"C:\Users\Sub2\Desktop\dff\x64\Release\dff.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"x64\Release\dff.lib" /MACHINE:X64 x64\Release\dff.exe.embed.manifest.res x64\Release\acquisition.obj x64\Release\azmemutil.obj x64\Release\dff.obj x64\Release\fft.obj x64\Release\FocusMeasure.obj x64\Release\ge.obj x64\Release\stdafx.obj DevIL.lib ILU.lib ILUT.lib 1>LINK : warning LNK4075: ignoring '/INCREMENTAL' due to '/OPT:ICF' specification

    // This is from Win32's <wingdi.h> and <winnt.h>
    #if defined(__LCC__)
        #define ILAPI __stdcall
    #elif defined(_WIN32) //changed 20031221 to fix bug 840421
        #ifdef IL_STATIC_LIB
            #define ILAPI
        #else
            #ifdef _IL_BUILD_LIBRARY
                #define ILAPI __declspec(dllexport)
            #else
                #define ILAPI __declspec(dllimport)
            #endif
        #endif
    #elif __APPLE__
        #define ILAPI extern
    #else
        #define ILAPI
    #endif

Also:

    #define ILAPIENTRY __stdcall 

build log info when it gets close to error:

           Found KERNEL32_NULL_THUNK_DATA
             Referenced in kernel32.lib(KERNEL32.dll)
             Loaded kernel32.lib(KERNEL32.dll)
         Searching C:\Users\Sub2\Desktop\dff\x64\Release\DevIL.lib:
         Searching C:\Users\Sub2\Desktop\dff\x64\Release\ILU.lib:
         Searching C:\Users\Sub2\Desktop\dff\x64\Release\ILUT.lib:
         Searching C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\amd64\MSVCRT.lib:
         Searching C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\amd64\OLDNAMES.lib:
         Searching C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\amd64\msvcprt.lib:

     Finished searching libraries

     Finished pass 1


     Invoking CVTRES.EXE:
      /machine:amd64
      /verbose
      /out:"C:\Users\Sub2\AppData\Local\Temp\lnk92ED.tmp"
      /readonly
      "x64\Release\dff.exe.embed.manifest.res"
     Microsoft (R) Windows Resource To Object Converter Version 10.00.30319.01
     Copyright (C) Microsoft Corporation.  All rights reserved.

     adding resource. type:MANIFEST, name:1, language:0x0409, flags:0x30, size:2
 1>dff.obj : error LNK2019: unresolved external symbol __imp_iluGetImageInfo referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_iluImageParameter referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilDeleteImages referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilSaveImage referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_iluFlipImage referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_iluScale referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilTexImage referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilCopyPixels referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilGetError referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilLoadImage referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilBindImage referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilGenImages referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilInit referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilGetInteger referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilEnable referenced in function main
 1>dff.obj : error LNK2019: unresolved external symbol __imp_ilOriginFunc referenced in function main
 1>x64\Release\dff.exe : fatal error LNK1120: 16 unresolved externals
 1>Done Building Project "C:\Users\Sub2\Desktop\dff\dff.vcxproj" (rebuild target(s)) -- FAILED.

Build FAILED.

Just in case i have also tried writing #define _IL_BUILD_LIBRARY but has no effect.

user2427671
  • 205
  • 1
  • 3
  • 9
  • Can you add the full linker command that's being used to perform the link? You should find that in the build log somewhere. – greatwolf Jul 01 '13 at 23:44
  • Oh, can you also add what the preprocessed form of `ilDeleteImage` looks like for the source that's making the call? – greatwolf Jul 01 '13 at 23:46
  • here is the linker commandline that i pulled from the property: /OUT:"x64\Release\dff.exe" /VERBOSE /INCREMENTAL /NOLOGO /LIBPATH:"C:\Users\Sub2\Desktop\dff\x64\Release" /MANIFEST /ManifestFile:"x64\Release\dff.exe.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"C:\Users\Sub2\Desktop\dff\x64\Release\dff.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /PGD:"C:\Users\Sub2\Desktop\dff\x64\Release\dff.pgd" /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X64 /ERRORREPORT:QUEUE – user2427671 Jul 01 '13 at 23:48
  • well i believe ilDeleteImage is defined in the DLL/.lib so i can't see the actual definition of it if thats what your asking. Sry i'm some what new to this dll thing – user2427671 Jul 01 '13 at 23:51
  • here is the linker command from the build log itself: posted on the problem – user2427671 Jul 01 '13 at 23:52
  • 1
    i provided more info via edit on when ILAPI is defined as declspec(dllimport) – user2427671 Jul 01 '13 at 23:56
  • Based on the new info, can you check that what the compiler actually sees is `__declspec(dllimport) void __stdcall ilDeleteImage(const ILuint Num);` *after* preprocessing? That's important because that has a direct impact on how the function will be decorated and ultimately what symbol the linker looks for. – greatwolf Jul 02 '13 at 00:08
  • mmmm what would be the most effective means of checking this? I am looking through my build log right now but it does not specify how the compiler is seeing the ilDeleteImage(). However there are lines where the following happens: Found "__declspec(dllimport) public: int __cdecl std::basic_streambuf >::sputc(char)" (__imp_?sputc@?$basic_streambuf@DU?$char_traits@D@std@@@std@@QEAAHD@Z) Referenced in dff.obj Referenced in fft.obj Loaded msvcprt.lib(MSVCP100.dll) – user2427671 Jul 02 '13 at 00:18
  • added more info about the build log – user2427671 Jul 02 '13 at 00:20
  • For msvc, you can use the `/P` switch for [this](http://msdn.microsoft.com/en-us/library/8z9z0bx6(v=vs.110).aspx). – greatwolf Jul 02 '13 at 00:22
  • okay i got the .i file and when i look through it the functions are defined as they are supposed to by the compiler: example- __declspec(dllimport) ILuint __stdcall ilCopyPixels(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data); – user2427671 Jul 02 '13 at 00:32
  • Can you open the dll's in question in dependency walker and list a few of the functions it exports, preferably the functions that's not resolving? Take note of how the function names actually appear in there. – greatwolf Jul 02 '13 at 00:35
  • well in the DevIL.dll one of the unresolving functions listed: ilCopyPixels is what is says for function in the dependency walker – user2427671 Jul 02 '13 at 00:41
  • Does it have any leading `_` underscores or any `@` appended to the function name? – greatwolf Jul 02 '13 at 00:43
  • i was also looking through the il.h, ilu.h (.h files where the unresolved functions are declared) but it seems to have "#ifdef __cplusplus extern "C" {" when i hover over __cplusplus it says #define __cplusplus 199711L. Would this have an effect by any chance? – user2427671 Jul 02 '13 at 00:45
  • no it does not have any _ or @ in the dependency walker names – user2427671 Jul 02 '13 at 00:45
  • very vast majority of the names listed do not have _ or @ on them. Only a very few of the functions seem to have this convention – user2427671 Jul 02 '13 at 00:47
  • The `extern "C"` is there to stop the c++ compiler from mangling the function names and judging from what you've described so far, the dll's in question exposes a C interface. What I'm not getting is why `ilCopyPixels` doesn't have an `extern "C"` in front after preprocessing. Or maybe that entire section is enclosed in a `extern "C" {` `}`? – greatwolf Jul 02 '13 at 00:50
  • so your saying when it is declared the function should've been preprocessed: extern "c" __declspec(dllimport) ILuint __stdcall ilCopyPixels(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data); or something like this – user2427671 Jul 02 '13 at 00:54
  • yes but check and make sure it's not already in an `extern "C" {` `}` block scope. – greatwolf Jul 02 '13 at 00:56
  • the entire section is closed in extern "C" :at the beginning of the .h file: #ifdef __cplusplus extern "C" { #endif towards the end of the .h file: #endif #ifdef __cplusplus }#endif – user2427671 Jul 02 '13 at 00:57
  • it seems that the entire block of declarations that contain the functions are within the extern "C" {} scope if the #ifdef__cplusplus goes through – user2427671 Jul 02 '13 at 00:59
  • Seems the problem is that the exported dll functions look like `__cdecl` but are actually `__stdcall`? If so, you might need a `.def` file to correct the symbols to look up during linking. – greatwolf Jul 02 '13 at 01:02
  • the thing i am most concerned about is that extern "C" happens if __cplusplus is defined but i do not see #def __cplusplus anywhere when i am searching through the solution. Is this a unneccessary concern? Is the __cplusplus automatically set when it is running in a c++ environment? or am i supposed to hard set this somewhere? – user2427671 Jul 02 '13 at 01:06
  • yes `__cplusplus` is predefined when compiling c++ source. – greatwolf Jul 02 '13 at 01:07
  • Other question, are the headers you're including coming from the original author of the dll's? Did that author include any `.def` files with the package? – greatwolf Jul 02 '13 at 01:10
  • so far i have no changed a single line of code from any of the original .h or .cpp files. I have been working with what i have been given and have been changing configurations to try to make this work. there were no .def files with the package. I received these files with a already built project that even included a readme on how to run the program. I followed the readme step by step but created linking errors thus i am where i am at the moment – user2427671 Jul 02 '13 at 01:17
  • the readme i recieved basically states to set up in release, 64 mode, ensure the libraries, dll are in the directory. Where to put all the files in (since path was pre-set) – user2427671 Jul 02 '13 at 01:18
  • wait, so you have the source files that was used to build the dll's you're linking against? atm, I'm mainly wondering why the exported functions look like `__cdecl` functions in the dll but the header declares them as being `__stdcall` call convention. This disagreement is likely where the unresolve error stems from. – greatwolf Jul 02 '13 at 01:20
  • lol unfortunately no i do not. I have the .dll files and .lib files. And i have the source file to build my exe using the .dll and .lib. The detailed specifications of the .dll and .lib to me would be a mystery. Regarding the export functions looking like __cdecl while header declaring them as __stdcall is it possible for me to just switch the __cdecl to __stdcall to resolve this conflict or is creating the .def file the only way to resolve this possible conflict. – user2427671 Jul 02 '13 at 01:28
  • I should probably type up a more detailed answer to cover all this but the answer is maybe. The question really comes down to, did the original author intend this to use `__cdecl` or `__stdcall` because they're not interchangable. I suppose you can just force it to be `__cdecl` and then see if your program crashes after. You can also disassemble one of the dll functions and check for cleanup code in the function epilogue. – greatwolf Jul 02 '13 at 01:31
  • hmmm i c. Unfortunately I do not know who made this. All i know is that someone in the past made it. There is also another person who ran this code successfully in the past (5 months ago) and used it for a product demo but he is currently away in a business trip. Personally im just on the verge of giving up and i literally would've given up by now if it wasn't for you responding today. But regarding the disassembly of the dll function. What am i to look for in particular that would give me a hint? Are there destructors or something that would mention __cdecl or __stdcall? – user2427671 Jul 02 '13 at 01:36
  • You start by picking an exported dll function that takes one or more arguments. You disassemble that function and look down the listing until that function returns. Usually it'll look something like `mov esp ebp; pop ebp`. Look for increments to the `esp` that indicates stack space is being freed by the current function before it returns to the caller. If you see that happening, it probably means this is a `__stdcall` function. – greatwolf Jul 02 '13 at 01:43
  • i'm trying to use dumpbin /exports [*].dll but it hink this is not giving me the type of data you mentioned. is there a good alternative to dumpbin or is there a better dumpbin command i can use for this? – user2427671 Jul 02 '13 at 02:02
  • well i tried dumpbin /DISASM for *.dll but i get almost no data just 2000 .rsrc, 202000 UPX0, B9000 UPX1 – user2427671 Jul 02 '13 at 02:06
  • CFF Explorer might help but I never had to actually locate for the specific function section of a .dll. The binary code that implements the functions will be in the `.text` section btw. – greatwolf Jul 02 '13 at 02:17
  • Under Export Directory, you'll find the exported functions listed. Look under the Function RVA column for the LSB of the address. Then go under Quick Disassembler click disassemble. Under the address column scroll down to the address where the last 2 bytes matches the bytes from the RVA of the function you want to inspect. – greatwolf Jul 02 '13 at 02:27
  • Tracking the functions though is a bit confusing i am not sure if i am doing it right. But "inc esp" does appear in the instruction – user2427671 Jul 02 '13 at 02:48
  • For the `ret` instruction do you see any number after it? Note that you're digging into the lower level guts of the dll -- looking at assembly isn't easy and it's often confusing if you're not use to it. So it may be easier to just compile, run it with `__cdecl` and see if it crash and burns. – greatwolf Jul 02 '13 at 03:00
  • well doing it as you have suggested it seems some of the unresolved functions do have "inc esp" like ilBindImage – user2427671 Jul 02 '13 at 03:07
  • can you add a pastebin for it – greatwolf Jul 02 '13 at 03:08
  • mmm okay, i guess ill just give that a try. I doubt i'll work. After that i give up. Thanks for the help however, i greatly appreciate it. – user2427671 Jul 02 '13 at 03:08
  • http://pastebin.com/. for the assembly you're seeing – greatwolf Jul 02 '13 at 03:12
  • ILAPI void ILAPIENTRY ilBindImage(ILuint Image); – user2427671 Jul 02 '13 at 03:13
  • http://pastebin.com/QHUyPaeJ here is a segment. Do you want the whole assembly though? – user2427671 Jul 02 '13 at 03:16
  • ahhh sorry but i have to relook i think i got the address function wrong or confused. brb lunch – user2427671 Jul 02 '13 at 03:17
  • That definitely doesn't look right. Better recheck the address. – greatwolf Jul 02 '13 at 03:23
  • well thanks for the help but i just decided to give up and work on a different project. And my superior did not really seem all that suprised that i couldn't find the answer since i've never worked with dll before. – user2427671 Jul 02 '13 at 09:12

2 Answers2

5

I'm adding an answer here to summarize a bit on the above comments, the probable root cause and finding a solution to the unresolved errors. I'll preface this by saying linkers tend to be dumb low level tools. If the symbols referenced in the object files don't match exactly with the library then the build process bails out with those unresolved errors. Therefore, the author of the dll library and clients using it will need to put in some effort to ensure the symbols agree.

Root Causes

Unresolved errors are usually caused by one of the follow:

  • Neither the project nor the libraries linked against implement the function for that symbol.
  • The libraries actually do implement the function but under a differing reference symbol.
  • The headers for the library aren't preprocessed or decorated correctly thereby causing #2.

The Hunt

Base on what the OP described the dll libraries linked against exposes a C API. It is unclear what calling convention is being followed by the library in question. The exported names in the dll contain plain undecorated function names suggesting a __cdecl convention. The provided corresponding headers, OTOH has a function like:

ILAPI void ILAPIENTRY ilDeleteImage(const ILuint Num);

which expands into this after preprocessing:

__declspec(dllimport) void __stdcall ilDeleteImage(const ILuint Num);

From this you can conclude three possible scenarios:

  1. The unresolved functions follow a __cdecl convention and the provided headers are wrong.
  2. The unresolved functions follow a __stdcall convention and the exported dll names are wrong.
  3. The functions follow __stdcall but are undecorated to look like __cdecl in the dll. This suggest that a .def file might have been used to build the dll in question.

A Sad State of Affair

Unfortunately, the function call convention followed in a win32 dll is in a confusing state of affairs. There's nothing in the language standard, C or C++, that addresses this ABI issue. See my other answer here. The toolchain vendor is free to decorate the names however they like but typcially for __cdecl functions it's plain undecorated or with a prefixed leading _ underscore.

WinAPI functions you find, like in kernel32.dll user32.dll gdi32.dll etc. are also undecorated but yet follow __stdcall. However, MSVC itself decorates __stdcall with a trailing ampersand with total bytes of the parameters(eg. ilDeleteImage@4) thus contributing to the confusion. To override how LINK decorates the functions, you have to provide a .def file that specifies the new name alias. See here for more details.

Finding the Real Convention

Assuming you don't have access to the source used to build the dll, there are two approachs I can think of to identify the real convention used.

Create a minimal test application that calls into the dll functions as if it uses __cdecl and see if it crashes and burns. This is the easier more straightforward method and you don't have to understand assembly to do it.

Second approach, you do the same but insert assembly breakpoints into your test application and run it through the debugger doing single step instructions. Make sure to choose a dll function taking at least one parameter. For example:

// pullin dll headers
// etc..

int main()
{
  __asm int 3;
  ilDeleteImage(0xdecafbad);
}

This will break and give control back to the debugger right before the dll function call. From here single step at the assembly level until you reach ilDeleteImage's function prologue.

 ; function prologue
 push   ebp
 mov    ebp, esp
 ; function implemention
 ; more opcodes here
 ; ...

 ; function epilogue
 mov    esp, ebp
 pop    ebp
 ret    0x8

Check what form of ret is being used on function return. The number argument following the ret mnemonic indicates how much to increment the esp stack pointer. Any number >0 suggestes a __stdcall function. The hypothical disassembly above shows a __stdcall function freeing 8 bytes on the stack which also hints that this function takes 2 arguments.

Community
  • 1
  • 1
greatwolf
  • 20,287
  • 13
  • 71
  • 105
0

I had this compile error while building a project using external static libraries, QDBM and PCRE:

_main.obj : error LNK2001: unresolved external symbol __imp__dpversion
_main.obj : error LNK2001: unresolved external symbol __imp__regcomp

I had correctly configured these external projects to build static libraries, but I had forgotten to define the correct preprocessor defines in my own code, which used these libraries, to enable static linking.

So when they imported the headers from QDBM and PCRE, they added a __declspec(dllimport) that shouldn't be there (for static linking), so they were trying to import symbols from DLLs that didn't exist.

I added the missing preprocessor defines to my build system, which fixed the error:

-DQDBM_STATIC -DPCRE_STATIC

Which meant adding the following lines to my CMakeLists.txt file:

# Tell QDBM not to build itself as a DLL, because we want to link statically to it.
target_compile_definitions(qdbm PUBLIC -DQDBM_STATIC)
target_compile_definitions(lib_common PUBLIC -DPCRE_STATIC)
qris
  • 7,900
  • 3
  • 44
  • 47