Understanding the classical model for linking: You can override an LIB with another LIB, and a LIB with an OBJ, but you can’t override an OBJ

If you study the classical model for linking, you'll see that OBJ files provided directly to the linker have a special property: They are added to the module even if nobody requests a symbol from them.

OBJs bundled into a library are pulled into the module only if they are needed to resolve a needed symbol request. If nobody needs a symbol in the OBJ, then the OBJ doesn't get added to the module. On the other hand, OBJs handed directly to the linker get added to the module whether anybody wants them or not.

Last time, we learned about the along for the ride technique which lets you pull components into a module even if they were not explicitly requested by an OBJ. Today's problem is sort of the reverse of this: If you move an OBJ from the explicit OBJ list to a library, then somebody has to remember to take it for a ride.

Some time ago, Larry Osterman described how some components use sections to have one component automatically register itself with another component when the OBJ is pulled into the module. But in order for that to work, you have to make sure the OBJ gets pulled into the module in the first place. (That's what Larry's Call­Force­Load function is for: By putting it an explicit OBJ, that function forces the OBJ from the LIB to be pulled in. And then, since nobody ever calls Call­Force­Load, a later linker pass discards it as an unused function.)

Another consequence of the algorithm by which the linker pulls OBJs from libraries to form a module is that if a needed symbol can be satsified without consulting a library, then the OBJ in the library will not be used. This lets you override a symbol in a library by explicitly placing it an OBJ. You can also override a symbol in a library to putting it in another library that gets searched ahead of the one you want to override. But you can't override a symbol in an explicit OBJ, because those are part of the initial conditions.


Discuss this user's analysis of a linker issue.

I have three files:

// awesome1.cpp
int index;

// awesome2.cpp
extern int index;
void setawesomeindex(int i)
 index = i;

// main.cpp
int index = 0;
int main(int, char**)
 return index;

When I link the object files together, I get an error complaining that index is multiply defined, as expected. On the other hand, if I put awesome1.cpp and awesome2.cpp into a library, then the program links fine, but the two copies of the index variable were merged by the linker! When I set the awesome index to 3, it also changes my main program's variable index which has the same name. Why is the linker merging my variables, and how can I keep them separate?

When I share my awesome.lib with others, I don't want to have to give them a list of all my global variables and say, "Don't create a global variable with any of these names, because they will conflict with my library." (And that would also prevent me from adding any new global variables to my library.)

Exercise: Clarify the following remark by making it more precise and calling out the cases where it is false. "Multiple definitions for a symbol are allowed if they appear in LIBs."

Exercise (harder): The printf function is in a bit of a pickle regarding whether it should support the floating point formats. If it includes them unconditionally, then its use of the floating point data types causes the floating point emulation library to be linked into the module, even if the module didn't otherwise use floating point! Use what you've learned so far this week to provide one way that the printf function could determine whether it should include floating point format support based on whether the module uses floating point.

Comments (27)
  1. Bob says:


    Wouldn't there be a problem if two libraries define the same symbol, but the one later in the linking order also provides a symbol which is also needed?  In that case, the OBJs from both libraries would be pulled in and a conflict would result.

    And for printf, since printf itself is large, I think it would be desirable to pull it in only if the function is used…not generically as part of floating-point support.  Perhaps one could have two versions of printf, as you describe, in separate libraries.  The one with floating point support would provide two symbols, a standard "printf" one and a second one, the equivalent of "printf_with_FP_support".  Both would point to the same underlying code entry point.  The compiler would modify "printf" to "printf_with_FP_support" in cases where it saw the need for FP support, similar to how it added the _fltused symbol.  In this way, the linker would pull in one copy of printf only if the underlying function was used.

    [(Good point on the multiple definition issue.) The compiler cannot rewrite printf to printf_with_FP_support because the OBJ that calls printf may not use floating point explicitly. Consider this function: void log(const char *format, ...) { va_list ap; va_start(ap, format); vprintf(format, ap); va_end(ap); } This function does not use any floating point, but it might need to use the FP-enabled version of printf based on whether the rest of the program uses floating point. -Raymond]
  2. Peter says:

    "Another consequence of the algorithm by which the linker pulls OBJs from libraries to form a module is that if a needed symbol can be satsified without consulting a library, then the OBJ in the library will not be used."

    It seems like this should be tricky to pull off in practice.  If I understand correctly, when I have a library that contains a.obj, and I want to override a function Foo() in a.obj, then I must also override all other functions in a.obj that my program uses.  For instance, if I override Foo() but don't override Bar() (also defined in a.obj), then this will cause the linker to pull in the entire a.obj file and Foo() will be multiply defined.

    [Many libraries are built according to the "one function per OBJ" model. The static C runtime library, for example. -Raymond]
  3. Peter says:

    For the printf problem, could we solve it using a factory approach similar to the ATL example?  Internally, printf could refer to a table of format functions (each entry would be a format specifier and a function pointer).  The printf module would define all the entries expect for the floating point entry, which would appear in the floating point module.

    [That would work. You could special-case it further, where the only registration entry is for the floating point formats and you just hard-code the integer formats into printf. -Raymond]
  4. ZLB says:

    This is difficult.

    Will this work:

    printf provided by a lib which is made up of the following:

    1 Obj which provides printf with floating point support. Also exports a __printf_with_fp__ symbol.

    1 Obj without floating point support. Does not export symbol.

    Floating point lib imports (requires) printf_with_fp symbol so uses the floating point version.

  5. Henning Makholm says:

    @ZLB: That won't work if the linker arbitrarily decides to resolve printf ifself before it resolves printf_with_fp, or before it even gets around to adding the ordinary floating-point support module.

  6. Bob says:

    @ZLB:  Problem is that if you use FP, but not printf, you get printf in your linked module anyway.

    Best I can come up with right now is to factor out the FP support from the rest of printf.  This gives 3 OBJ, in link order…

    1)  FP support OBJ which provides "__fltused"  and "printf__fp" (FP portion of printf)

    2)  printf   OBJ   which provides "printf"   and needs "printf__fp"

    3)  dummy  OBJ which provides a version of "printf__fp" which just returns an error indicator in case someone uses %f in printf call w/o any other FP used.

    In this way, FP support only comes in if you use FP.  Also, the bulk of printf only comes in if you actually use printf.  But, if you use FP but not printf, you get a copy of "printf__fp" anyway.

  7. Joshua says:

    [The problem is to avoid using the floating point version of printf if the program does not use floating point (even though it links with the floating point library). -Raymond]

    The way I remember it being done was printf called a function called something like __ftoa, and there was an implementation of __ftoa() in the floating point library and another __ftoa() all the way on the end of the list that raised an error. The meaning of the error was "Hey, you passed %e, %f or %g to printf() but you didn't use float or double anywhere. What did you expect this to do?"

    [This requires that the FP library be linked ahead of the static CRT. This is the sort of mistake most people will never figure out. -Raymond]
  8. AC says:


    Would that really work for the "no FP" variant?

    When the linker encounters printf in the second OBJ, it needs to resolve printf__fp. But it will take it from the first OBJ, because of the link order. The first OBJ also providing the unused __fltused doesn't stop that, does it?

  9. Peter says:

    @Joshua: I don't think that would work.  As soon as printf declares that it needs __ftoa, the linker would pull in the version from the floating point .OBJ.

    But it could work if we found the pointer indirectly:

    In printf.obj, we declare a section __ftoa_sect_a with a single pointer (__dummy_ftoa), and another section __ftoa_sect_c a pointer to the error version of __ftoa you described.

    In the floating point .obj, we declare a section __ftoa_sect_b with a pointer to the real __ftoa.

    Now, printf calls __ftoa by (__dummy_ftoa + 1)( … ).  If the floating point .obj is included, this will end up calling the real __ftoa, otherwise it will call the error version.

  10. Max says:

    I just tried to compile a test program where I provided my own implementation of CreateFile ( just returns NULL ) attempting to use the "OBJ overrides the LIB" principle. Linker complains that the CreateFile symbol is already defined blablabla. Does it mean that the behavior is different when we are talking about import libraries ?


  11. Joshua says:

    [This requires that the FP library be linked ahead of the static CRT. This is the sort of mistake most people will never figure out. -Raymond]

    It was all one library. Don't ask me how the linker knew not to resolve __itoa to the floating point version if __fltused was not defined. I have no idea. Today I'd do it with a weak symbol at the front but I don't think the 1980's linker knew about weak symbols.

  12. @Joshua: Wouldn't printf need to cast the va_list argument to a float before it could call __ftoa()? Wouldn't that cause the program to bring in whatever floating-point support was needed for its platform?

  13. Nevermind, I'm forgetting that the point is to not pull in any floating-point support except when needed.

  14. Paul says:

    Does anyone know the details of library search order? In particular, how does specifying a lib on the linker input line compare to using a #pragma comment(lib,"") in a source file in the project? How about #pragma's in different source files in the project?

  15. ipoverscsi says:

    Perhaps I'm over thinking the "link the correct version of printf", but I would modify the compiler to scan the formatting string to printf and its variants (sprintf, etc.) and if the formatting string referenced floating point variables update the code to call the printf_with_float() instead of printf_no_float() using one of the techniques mentioned in this series.

    [What if the format string is generated at run time? -Raymond]
  16. Brian_EE says:


    "…but I would modify the compiler…"

    Tell me how that works to link object files in the project that were created in assembly (or any other language) and make calls to printf. Remember, the linker is language-agnostic.

  17. ipoverscsi says:


    True.  But unless you preprocess the printf format string you won't know until runtime whether an attempt will be made to format a floating point value.  If we assume that we're only doing static linking (no DLLs) then I can't think of any other way to know at link time if you need to floating point library.

  18. Anonymous123 says:

    For the printf issue – printf OBJ should not include _fltused.  Yes if the app uses %f and does not use floating point the app will crash, but any app that uses floating formats will itself include _fltused so this symbol is not needed by printf

  19. Joshua says:

    I think Anonymous123 found it. by knocking out the reference to _fltused in vfprintf's .OBJ (all other *printf call this one), the floating point library is not called in unless used elsewhere. This assumes that vfprintf's %e, %f, and %g are fully inlined. You end up with maybe .5k of unreachable garbage if not used. No special cases in the linker required.

  20. One way to resolve this is to create an (awesome) namespace.

  21. ipoverscsi says:

    [What if the format string is generated at run time? -Raymond]

    I didn't think of that one.  Hmm.  

    Well, you stumped me, Raymond.  I can't think of a way to determine which version of printf to use at link-time.  I can see how to do it at runtime with DLLs, overlays, or some other dynamic code loading, but not at link time.

    I eagerly await the answer.

  22. henke37 says:

    The easy exercise has the following issues:

    * It is not allowed to have multiple definitions for a symbol in the same library.

    * The correct rule is "If multiple libraries define the same symbol then the linker picks one of them according to the linking order.".

    The way to avoid the namespace collision is to use a namespace. Not all languages support namespaces. Not all languages call them namespaces, the term "package" is common. Some languages define the term "namespace" as something else.

    The hard exercise is rather easy. Code two versions of printf, one with floating point support and one without it. Stick the floating point version in the floating point emulation library. Then just ensure that the floating point emulation library is linked in before the library with the non floating point version of printf would be.

    [The problem is to avoid using the floating point version of printf if the program does not use floating point (even though it links with the floating point library). -Raymond]
  23. Silly says:

    [This requires that the FP library be linked ahead of the static CRT. This is the sort of mistake most people will never figure out.]

    Surely not in ye olde classical linker days? But from what I recall, the math libary usually went at the end of the library arg list since it had no dependencies, which is sort of the opposite of this FP library idea.

    Wasn't the DOS era floating point emulation stuff either done via an explicit linker option (offloading the choice to the developer), or by the user choosing to run an enumation tsr or having an emu387.exe to be loaded by runtime if needed (maybe triggered by a hardware fault)? I think developers would have cracked the s*ts back in the day if they had to endure a lookup + indirect function call to handle every %f printf argument encounter.

    Delay load functionality could also be an option if a time machine is allowed.

  24. DS says:

    I think I'd go with Peter's approach, as corrected by Raymond (entry point pointing to dummy function and corrected by FP library's init code to point to FP argument handler). Anonymous123's approach would require coding a special case into the compiler (remember, when float or double is used, as it must be to implement %f, the compiler always generates _fltused) or coding %f etc. support in assembler (well, maybe that's what CRT does, but I actually tend to doubt it).

  25. Matt says:


    /// printf.c provides "printf, dummy_printf_do_f_impl, printf_do_f_fp"


    void dummy_printf_do_f_impl()


     printf("Uh oh – you used %%f but didn't use the float keyword anywhere!!"); abort();

     // alternatively, you could dynamically load the floating point library here, for example to handle the case where the main program's "printf" has been passed a float from a plugin.


    extern FARPROC printf_do_f_fp = &dummy_printf_do_f_impl;

    … printf(…)


     case "f": printf_do_f_fp();



    /// flt.lib provides __fltused, requires _printf_fp_impl


    int __fltused;

    void* force_load_printf_fp = &actual_printf_do_f_impl;


    /// printf_fp.c in printf_fp.lib (provides _printf_fp_impl)


    printf_do_f.c requires __fltused

    FARPROC printf_do_f = NULL;

    void actual_printf_do_f_impl()


     printf("Here's your float: ", …etc…);



    class InitMagicNumber




       printf_do_f = &actual_printf_do_f_impl;




    // Now follow through the compilation of main.c (main() { printf("This should return an error: %f"); }

    main.c requires printf, provided by printf.lib. printf.lib doesn't require any printf_fp stuff, so that's not loaded. Now when printf is called, it does normal printf behaviour until it hits %f, when it then calls printf_do_f_fp, which is a symbol in printf.lib defined to point to dummy_printf_do_f_impl, which triggers an error.

    // Now follow through the compilation of main_fp.c (main() { printf("This should work: %f", 0.0f); }

    main_fp.c uses floating point, so automatically requires __fltinit. It calls printf, so we load printf.lib. printf.lib doesn't use printf_fp, so that doesn't automatically trigger a load there, but we're now left with one unresolved symbol: __fltinit. __fltinit is defined in flt.lib, which requires the symbol _printf_fp_impl, defined in printf_fp.lib. This requires the printf_do_f_fp symbol which resolves to the definition in printf.lib. printf_fp.lib also has a "magic" variable and the linker will add its constructor to the list of CRT initialization functions.

    Now when main_fp.c runs, the CRT will call all of the constructors in turn, including the InitMagicNumber magic class, which sets printf_do_f (from printf.lib) to point to actual_printf_do_f_impl. The CRT eventually calls main who calls printf, who eventually calls the deref of printf_do_f_fp, which now takes it to actual_printf_do_f_impl.

    Result: printf floating point code is only brought along for the ride if you actually use floating point (or are dumb enough to include an extern int __fltused) somewhere in your code. Otherwise, a dummy implementation of printf will handle the case where %f is used on a non-floating-point program, which can either load the expensive fp library, or can explode, or can return "0.0" or whatever.

  26. Marcel says:

    Well, in the case of my microcontroller compiler (avrgcc) there is no magic going on, you have to tell the linker explicitly which version you want. The default version doesn't include floating point. If I really want that, I have to include the "printf_flt" library. There's even a third, minimalistic version that supports even less options than the standard one, called printf_min.

  27. Neil says:

    Sorry if I've misremembered this.

    In printf.c, declare extern (*printf__fp)();

    In fltused.c, define printf__fp.

    Then when printf wants to print a floating-point number it just invokes printf__fp and you crash if you didn't trigger the include of the floating-point library.

    Better still would be a weak symbol if that's supported.

Comments are closed.

Skip to main content