Solved

Expecting linker duplicate symbol error, but not getting it!

Posted on 2014-04-10
9
702 Views
Last Modified: 2014-04-18
Ah hello.

I am looking in more depth at Linux programming, right now static libraries.  I have the following code:
/* 
Library.h
*/
#ifndef LIBRARY_H
#define	LIBRARY_H

#ifdef	__cplusplus
extern "C" {
#endif

    int GetMagicNumber();


#ifdef	__cplusplus
}
#endif

#endif	/* LIBRARY_H */


/* 
Library.c
*/
int GetMagicNumber()
{
	 return 42;
}

/* 
Library 2.c
*/
int GetMagicNumber()
{
	 return 42 * 2;
}

/* 
Main.c
*/
#include <stdio.h>
#include <stdlib.h>
#include "../StaticLibrary/Library.h"


int main(int argc, char** argv) {

    printf("%d\n", GetMagicNumber());
    return (EXIT_SUCCESS);
}

int GetMagicNumber()
{
	 return 7;
}

Open in new window


Now, first of all I wouldn't have expected the static library to build as it has two different implementations of GetMagicNumber().  Secondly, I thought main.c would complain since it effectively has three versions of GetMagicNumber() to chose from!

The program runs and outputs 7.

I am building this with Netbeans on Windows 7 using a remote Linux host.  The build output is as follows:

"/usr/bin/gmake" -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
gmake[1]: Entering directory `/home/wad/Code/NetBeansProjects/CApp'
cd ../StaticLibrary && /usr/bin/gmake  -f Makefile CONF=Debug
gmake[2]: Entering directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
"/usr/bin/gmake" -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
gmake[3]: Entering directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
"/usr/bin/gmake"  -f nbproject/Makefile-Debug.mk dist/Debug/GNU-Linux-x86/libstaticlibrary.a
gmake[4]: Entering directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
mkdir -p build/Debug/GNU-Linux-x86
rm -f "build/Debug/GNU-Linux-x86/Library.o.d"
gcc    -c -g -MMD -MP -MF "build/Debug/GNU-Linux-x86/Library.o.d" -o build/Debug/GNU-Linux-x86/Library.o Library.c
mkdir -p build/Debug/GNU-Linux-x86
rm -f "build/Debug/GNU-Linux-x86/Library2.o.d"
gcc    -c -g -MMD -MP -MF "build/Debug/GNU-Linux-x86/Library2.o.d" -o build/Debug/GNU-Linux-x86/Library2.o Library2.c
mkdir -p dist/Debug/GNU-Linux-x86
rm -f dist/Debug/GNU-Linux-x86/libstaticlibrary.a
ar -rv dist/Debug/GNU-Linux-x86/libstaticlibrary.a build/Debug/GNU-Linux-x86/Library.o build/Debug/GNU-Linux-x86/Library2.o 
ar: creating dist/Debug/GNU-Linux-x86/libstaticlibrary.a
a - build/Debug/GNU-Linux-x86/Library.o
a - build/Debug/GNU-Linux-x86/Library2.o
ranlib dist/Debug/GNU-Linux-x86/libstaticlibrary.a
gmake[4]: Leaving directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
gmake[3]: Leaving directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
gmake[2]: Leaving directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
"/usr/bin/gmake"  -f nbproject/Makefile-Debug.mk dist/Debug/GNU-Linux-x86/capp
gmake[2]: Entering directory `/home/wad/Code/NetBeansProjects/CApp'
mkdir -p build/Debug/GNU-Linux-x86
rm -f "build/Debug/GNU-Linux-x86/main.o.d"
gcc    -c -g -MMD -MP -MF "build/Debug/GNU-Linux-x86/main.o.d" -o build/Debug/GNU-Linux-x86/main.o main.c
mkdir -p dist/Debug/GNU-Linux-x86
gcc     -o dist/Debug/GNU-Linux-x86/capp build/Debug/GNU-Linux-x86/main.o ../StaticLibrary/dist/Debug/GNU-Linux-x86/libstaticlibrary.a
gmake[2]: Leaving directory `/home/wad/Code/NetBeansProjects/CApp'
gmake[1]: Leaving directory `/home/wad/Code/NetBeansProjects/CApp'

Open in new window



I am sure I am doing something silly, or have misunderstood something, but I cannot see it.  Can you?

TIA
0
Comment
Question by:mrwad99
9 Comments
 
LVL 86

Assisted Solution

by:jkr
jkr earned 83 total points
ID: 39992696
I am not surprised that the program itself builds without errors, since the presence of 'GetMagicNumber()' in it's source code eliminates the need to look for it in the static lib. The 'local' implementation will be chosen.

As for the lib, what symbols are listed when you do a 'nm libstaticlibrary.a'?
0
 
LVL 8

Expert Comment

by:Subrat (C++ windows/Linux)
ID: 39993282
Including JKR's comment...

If you will remove the implementation of int GetMagicNumber() from main.cpp, then you will see the actual magic:)
0
 
LVL 19

Author Comment

by:mrwad99
ID: 39994444
Right, OK.

nm gives me

Library.o:
0000000000000000 T GetMagicNumber

Library2.o:
0000000000000000 T GetMagicNumber

Open in new window


...which looks odd; how can we have two identical functions?

Secondly, are you saying there is logic that a linker will not look in the additional dependencies if it finds a definition locally?  I've never heard of that...where it is documented?

TIA
0
 
LVL 32

Assisted Solution

by:phoffric
phoffric earned 167 total points
ID: 39994485
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 19

Author Comment

by:mrwad99
ID: 39994850
Thanks phoffric, that's helpful.  So how come I can still build the library with duplicate symbols though?
0
 
LVL 32

Expert Comment

by:phoffric
ID: 39994882
My post dealt with linking, not with libraries. You put into the library whatever modules you choose. As C libraries, it is not a good idea to have duplicate symbols. I am guessing that when you link with your library, that the first symbol it finds matching an undefined reference will be selected and the other one ignored.

This is a serious issue with C that has been improved upon greatly with C++. Once I had to go into one of two different 3rd party binary libraries and edit duplicate symbols to make them unique. They chose a function name that was so simplistic that it is hardly surprising that another 3rd party matched. Then, in the application, I had to change one of the names to the edited name to be able get correct functionality. For example, in my case, the program originally built fine, but when trying to access a graphics engine, it hit a database instead and, not surprisingly, crashed.
0
 
LVL 19

Author Comment

by:mrwad99
ID: 39996481
OK, so fundamentally speaking, it is wrong for a static library to have duplicate symbols it, from the library's point of view?  I mean, what we are seeing here is obviously undesirable, but since a static library is just a collection of object files, thinking about it, I don't see any reason why we can't have identical symbols.  It seems to fit with what we are seeing here.

Thoughts?
0
 
LVL 32

Accepted Solution

by:
phoffric earned 167 total points
ID: 39997988
It is a bad idea for a static library to have .o files in it that result in duplicate symbols.

It is a bad idea for two different static libraries to have .o files in them that result in duplicate symbols in the different libraries; but because libraries are often 3rd party, you may have to deal with this unfortunate situation by using a binary editor to modify one of the symbols (at least that worked for me 20 years ago).

If you are creating a 3rd party library, then prefix every symbol with some unique symbol to lower the chances of name collisions.

When the linker encounters a static library, it searches it for undefined references. When it finds a .o file in the library that has the undefined reference, then it loads the entire .o file. If that newly loaded .o file has other symbols that collide with already existing defined symbols, then you will get a linker duplicate error message. Thus, the order in which you specify your .o files and library archive files may or may not result in duplicate symbol message. You are lucky if you get this duplicate symbol error message as it points out that you have duplicate symbols. If you do not get the error message, then the program that you built may be unwittingly containing the undesired symbol and the program may behave not in the desired manner.

Perhaps now, you can appreciate better the value of C++ namespaces that not only help organize your project, but also helps avoid name collisions. Using nested namespaces even further reduces the name collision chance against 3rd party C++ libraries.
0
 
LVL 19

Author Closing Comment

by:mrwad99
ID: 40008760
Thanks all :)
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now