Diagnosing a problem with calling conventions

Date:July 6, 2004 / year-entry #268
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20040706-00/?p=38543
Comments:    3
Summary:A commenter asks for help with an unresolved external. One of my goals is to give you more insight into how things work so you can solve problems yourself. This particular problem - resolving the error "Undefined symbol: '__stdcall(0) pl_pvcam_init (_pl_pvcam_init@0)' referenced from '_main' in Acquisition.c:15" is one example of something you can solve with...

A commenter asks for help with an unresolved external. One of my goals is to give you more insight into how things work so you can solve problems yourself. This particular problem - resolving the error "Undefined symbol: '__stdcall(0) pl_pvcam_init (_pl_pvcam_init@0)' referenced from '_main' in Acquisition.c:15" is one example of something you can solve with the tips you've already learned.

First, let's look at the unresolved external itself. "_pl_pvcam_init@0". From the article this comment was posted to, you can see that the leading underscore and trailing @0 indicate that the function uses the __stdcall calling convention. (This is confirmed by the linker's undeciration of the name.)

So your function "_main" wants the function pl_pvcam_init with the __stdcall calling convention. But it's not found in the library even though you linked to it.

If you look inside the library itself, you'll find the desired symbols with some decoration. Decode that decoration. (My psychic powers tell me that when you do, you'll find that the decoration is "_pl_pvcam_init", which is the __cdecl calling convention.)

So now you see the problem. Your code is calling with the __stdcall calling convention, but the function actually uses the __cdecl calling convention. The calling conventions don't match up, so the linkage fails.

The solution, of course, is to fix the declaration of the pl_pvcam_init function in the header file to specify the correct calling convention. My psychic powers tell me that the header file doesn't specify any calling convention at all, which puts it at the mercy of the ambient calling convention for your project, which appears to be __stdcall. But the author of the header file expected __cdecl to be the default calling convention.

Put explicit calling conventions on the functions and you should be all set.


Comments (3)
  1. Keith Moore [exmsft] says:

    It should be noted (if it hasn’t been already) that link errors like this are a Very Good Thing. It would suck if this linked properly. It would really suck if the calling convention mismatch was in some rarely exercised (and therefore mostly untested) code path, leading to subtle and oh-so-fun-to-debug stack corruption problems.

  2. Keith Hill says:

    Actually you can run into these problems if you dynamically load DLLs and do GetProcAddress. The linker doesn’t catch this sort of problem, however you can compile with /GZ in your debug bits to enable stack checking OR if you want to handle the chores yourself like so:

    #define SAVE_STACK_REGISTER() __asm(mov f_startingESPValue, esp)

    #define #define CHECK_STACK_REGISTER()

    __asm(mov f_endingESPValue, esp);

    if (f_endingESPValue != f_startingESPValue)

    {

    // Alert user of calling convention mismatch – avoid using stack variables :-)

    }

    SAVE_STACK_REGISTER()

    pDllFunction();

    CHECK_STACK_REGISTER()

    Note that you can’t use /GZ with the above method.

  3. voidref says:

    ".. ambient calling convention …"

    Man, that’s just poetic!

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index