Mandalika's scratchpad [ Work blog @Oracle | Stock Market Notes | My Music Compositions ]

Old Posts: 09.04  10.04  11.04  12.04  01.05  02.05  03.05  04.05  05.05  06.05  07.05  08.05  09.05  10.05  11.05  12.05  01.06  02.06  03.06  04.06  05.06  06.06  07.06  08.06  09.06  10.06  11.06  12.06  01.07  02.07  03.07  04.07  05.07  06.07  08.07  09.07  10.07  11.07  12.07  01.08  02.08  03.08  04.08  05.08  06.08  07.08  08.08  09.08  10.08  11.08  12.08  01.09  02.09  03.09  04.09  05.09  06.09  07.09  08.09  09.09  10.09  11.09  12.09  01.10  02.10  03.10  04.10  05.10  06.10  07.10  08.10  09.10  10.10  11.10  12.10  01.11  02.11  03.11  04.11  05.11  07.11  08.11  09.11  10.11  11.11  12.11  01.12  02.12  03.12  04.12  05.12  06.12  07.12  08.12  09.12  10.12  11.12  12.12  01.13  02.13  03.13  04.13  05.13  06.13  07.13  08.13  09.13  10.13  11.13  12.13  01.14  02.14  03.14  04.14  05.14  06.14  07.14  09.14  10.14  11.14  12.14  01.15  02.15  03.15  04.15  06.15  09.15  12.15  01.16  03.16  04.16  05.16  06.16  07.16  08.16  09.16  12.16  01.17  02.17  03.17  04.17 


Wednesday, May 04, 2005
 
C/C++: global const variables, symbol collisions & symbolic scoping

(Most of the following is "generic" C/C++. Sun Studio compilers were used to compile the code and to propose a solution to symbol collision problem)

The way C++ handles global const variables is different from C.

In C++, a global const variable that is not explicitly declared extern has static linkage.

In C, global const variables will have extern linkage by default, and global variables can be declared more than once. As long as a single initialization (at most) for the same variable is used, the linker resolves all the repeated declarations into a single entity; and the the initialization takes place when the program starts up, before entry to the main function.

This can be illustrated with a simple C program, that produces different results when compiled with C and C++ compilers

% cat mylib.h
const float libraryversion = 2.2;
float getlibversion();
int checklibversion();

% cat mylib.c
#include <stdio.h>
#include "mylib.h"

float getlibversion() {
printf("\nmylib.c: libraryversion = %f", libraryversion);
return (libraryversion);
}

int checklibversion() {
float ver;
ver = getlibversion();
printf("\nmylib.c: ver = %f", ver);
if (ver < 2.0) {
return (1);
} else {
return (0);
}
}

% cat thirdpartylib.h
extern const float libraryversion = 1.5;
float getlibversion();

% cat thirdpartylib.c
#include <stdio.h>
#include "thirdpartylib.h"

float getlibversion() {
printf("\nthirdparty.c: libraryversion = %f", libraryversion);
return (libraryversion);
}

% cat versioncheck.c
#include <stdio.h>
#include "mylib.h"

int main() {
printf("\n** versioncheck.c: libraryversion = %f", libraryversion);
int retval = 0;
retval = checklibversion();
if (retval) {
printf("\n** Obsolete version being used .. Can\'t proceed further! **\n");
} else {
printf("\n** Met the library version requirement .. Good to Go! ** \n");
}
return (0);
}

Case 1:
Compile with Sun Studio C compiler:

% cc -G -o libmylib.so mylib.c
% cc -G -o libthirdparty.so thirdpartylib.c
% cc -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck

** versioncheck.c: libraryversion = 2.200000
thirdparty.c: libraryversion = 2.200000
mylib.c: ver = 2.200000
** Met the library version requirement .. Good to Go! **

From this output, it appears that it is working as expected although there is a symbol collision between libmylib and libthirdparty load modules over libraryversion symbol.

Case 2:
Compile with Sun Studio C++ compiler:

% CC -G -o libmylib.so mylib.c
% CC -G -o libthirdparty.so thirdpartylib.c
% CC -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck

** versioncheck.c: libraryversion = 2.200000
thirdparty.c: libraryversion = 1.500000
mylib.c: ver = 1.500000
** Obsolete version being used .. Can't proceed further! **

The inherent symbol collision was exposed when the code was compiled with C++ compiler.

It is a known fact that the global const variables, as libraryversion in this example are bound to cause problems.

The following is an alternative implementation of the above example, which shows consistent behavior when compiled with C and C++ compilers.

% cat mylib_public.h
float getlibversion();
int checklibversion();

% cat mylib_private.h
#include "mylib_public.h"
const float libversion = 2.2;

% cat mylib.c
#include <stdio.h>
#include "mylib_private.h"

float getlibversion() {
printf("\nmylib.c: libraryversion = %f", libraryversion);
return (libraryversion);
}

int checklibversion() {
float ver;
ver = getlibversion();
printf("\nmylib.c: ver = %f", ver);
if (ver < 2.0) {
return (1);
} else {
return (0);
}
}

% cat versioncheck.c
#include <stdio.h>
#include "mylib_public.h"

int main() {
int retval = 0;
retval = checklibversion();
if (retval) {
printf("\n** Obsolete version being used .. Can\'t proceed further! **\n");
} else {
printf("\n** Met the library version requirement .. Good to Go! ** \n");
}
return (0);
}

Since we cannot control 3rd party implementation, it was kept intact in this example.

Case 1:
Compile with Sun Studio C compiler:

% cc -G -o libmylib.so mylib.c
% cc -G -o libthirdparty.so thirdpartylib.c
% cc -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck

thirdparty.c: libraryversion = 1.500000
mylib.c: ver = 1.500000
** Obsolete version being used .. Can't proceed further! **

Case 2:
Compile with Sun Studio C++ compiler:

% CC -G -o libmylib.so mylib.c
% CC -G -o libthirdparty.so thirdpartylib.c
% CC -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck

thirdparty.c: libraryversion = 1.500000
mylib.c: ver = 1.500000
** Obsolete version being used .. Can't proceed further! **

Now with the new implementation, the behavior of the code is the same and as expected with both C and C++ compilers.

The final paragraph proposes a solution common to both C and C++, to resolve the symbol collision. With C++, symbol collisions can be minimized using namespaces.

symbolic (protected) scope
All symbols of a library get symbolic scope, when the library was built with Sun Studio's -xldscope=symbolic compiler option.

Symbolic scoping is more restrictive than global linker scoping; all references within a library that match definitions within the library will bind to those definitions. Outside of the library, the symbol appears as though it was global. That is, at first the link-editor tries to find the definition of the symbol being used in the same shared library. If found the symbol will be bound to the definition during link time; otherwise the search continues outside the library as the case with global symbols. This explanation holds good for functions, but for variables, there is an extra complication of copy relocations.

Let's see how symbolic scope works practically, by compiling the same code again with -xldscope=symbolic option.

Case 1:
Compile with Sun Studio C compiler:

% cc -G -o libmylib.so -xldscope=symbolic mylib.c
% cc -G -o libthirdparty.so thirdpartylib.c
% cc -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck

mylib.c: libraryversion = 2.200000
mylib.c: ver = 2.200000
** Met the library version requirement .. Good to Go! **

Case 2:
Compile with Sun Studio C++ compiler:

% CC -G -o libmylib.so -xldscope=symbolic mylib.c
% CC -G -o libthirdparty.so thirdpartylib.c
% CC -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck

mylib.c: libraryversion = 2.200000
mylib.c: ver = 2.200000
** Met the library version requirement .. Good to Go! **

With symbolic (protected) scoping, the reference to the symbol libraryversion was bound to its definition within the load module libmylib and the program showed the intended behavior.

However the main drawback of -xldscope=symbolic is that, it may interpose the implementation symbols of C++. These implementation interfaces often must remain global within a group of similar dynamic objects, as one interface must interpose on all the others for the correct execution of the application. Due to this, the use of -xldscope=symbolic is strongly discouraged.

Sun Studio compilers (8 or later versions) provide a declaration specifier called __symbolic and using __symbolic specifier with symbols that needs to have symbolic scope (protected symbols) is recommended.


Comments: Post a Comment

Links to this post:

Create a Link



<< Home


2004-2017 

This page is powered by Blogger. Isn't yours?