Mandalika's scratchpad [ Work blog @Oracle | 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  06.17  07.17  08.17  09.17  10.17  12.17  01.18  02.18  03.18  04.18  05.18  06.18  07.18  08.18  09.18  11.18  12.18  01.19  02.19  05.19  06.19  08.19  10.19  11.19  05.20  10.20  11.20  12.20  09.21  11.21  12.22 


Monday, September 20, 2004
 
Solaris/S1S9: Scope of Symbols IV - hidden scope

[Updated: 04/07/2006] Much accurate information is available in a better format at:
Reducing Symbol Scope with Sun Studio C/C++
__________________

The answer is to hide all the symbols within the module and export only those that are needed to external modules (objects). It can be achieved with the "hidden" value to -xldscope flag ie., -xldscope=hidden

An exert is from S1S9 documentation regarding hidden scope:
The symbol has hidden linker scoping. Hidden linker scoping is more restrictive than symbolic and global linker scoping. All references within a dynamic module bind to a definition within that module. The symbol will not be visible outside of the module
Time to check that with an example. Let's compile libhidden library with -xldscope=hidden
bpte4500s001:/sunbuild1/giri/testcases/symbol-hiding/%CC -xldscope=hidden -c hidden.c
bpte4500s001:/sunbuild1/giri/testcases/symbol-hiding/%CC -G -xldscope=hidden -o libhidden.so hidden.o

bpte4500s001:/sunbuild1/giri/testcases/symbol-hiding/%elfdump -s -C libhidden.so

Symbol Table: .dynsym
index value size type bind oth ver shndx name
[0] 0x00000000 0x00000000 NOTY LOCL D 0 UNDEF
[1] 0x000006c8 0x00000000 SECT LOCL D 0 .rodata
[2] 0x000107a8 0x00000000 SECT LOCL D 0 .data
[3] 0x000107ac 0x00000000 OBJT GLOB D 0 .data _edata
[4] 0x00000000 0x00000000 OBJT GLOB D 0 ABS _PROCEDURE_LINKAGE_TABLE_
[5] 0x00000000 0x00000000 NOTY WEAK D 0 UNDEF void __Cimpl::cplus_init()
[6] 0x000006d2 0x00000000 OBJT GLOB D 0 .rodata _etext
[7] 0x000106d4 0x00000000 OBJT GLOB D 0 .dynamic _DYNAMIC
[8] 0x00000000 0x00000000 NOTY WEAK D 0 UNDEF void __Cimpl::cplus_fini()
[9] 0x00000000 0x00000000 NOTY WEAK D 0 UNDEF _ex_register
[10] 0x00000634 0x00000090 FUNC GLOB D 0 .fini _fini
[11] 0x00000538 0x000000fc FUNC GLOB D 0 .init _init
[12] 0x00000000 0x00000000 NOTY WEAK D 0 UNDEF _ex_deregister
[13] 0x00000000 0x00000000 NOTY WEAK D 0 UNDEF void __Crun::do_exit_code_in_range(void*,void*)
[14] 0x000107ac 0x00000000 OBJT GLOB D 0 .bss _end
[15] 0x00000000 0x00000000 NOTY WEAK D 0 UNDEF _get_exit_frame_monitor
[16] 0x00000000 0x00000000 NOTY WEAK D 0 UNDEF atexit

Symbol Table: .symtab
index value size type bind oth ver shndx name
[25] 0x000107a8 0x00000004 OBJT LOCL H 0 .data age
[26] 0x000004d0 0x00000020 FUNC LOCL H 0 .text char firstchar(char*)
[27] 0x00000490 0x0000002c FUNC LOCL H 0 .text char*lastname(char*)
[28] 0x00000500 0x00000038 FUNC LOCL H 0 .text int agefunc()
[30] 0x00000450 0x0000002c FUNC LOCL H 0 .text int addtentomyage(int)

Dynamic symbol table has no entries for the interfaces of the module libhidden.so; this is because all the symbols were marked as local (LOCL, ie., local to module) and hidden (H, ie., not visible outside the module) - it can be seen from the static symbol table (.symtab)

Now if we compile & link our driver program with libhidden.so, it should fail as it can't access the symbols from the module libhidden.so

bpte4500s001:/sunbuild1/giri/testcases/symbol-hiding/% CC -o driver -lgeneric -lhidden driver.c
Undefined first referenced
symbol in file
int agefunc() driver.o
char firstchar(char*) driver.o
char*lastname(char*) driver.o
ld: fatal: Symbol referencing errors. No output written to driver

Great! Works as expected

Now let's see how to export the symbols that are necessary to compile & run the driver program. How do we know what all symbols we need to export (or make visible to external modules) to make the driver program work?

Simple; we just need to carefully look at the error message that was thrown by link-editor (ld) while linking driver's object file with libhidden.so to create the "driver" executable

The error says:
Undefined first referenced
symbol in file
int agefunc() driver.o
char firstchar(char*) driver.o
char*lastname(char*) driver.o
ld: fatal: Symbol referencing errors. No output written to driver

i.e., ld is not able to access agefunc(), firstchar(), lastname() interfaces from libhidden.so. Let's export those symbols.

__declspec(dllexport) specifier can be used to mark the symbol to be ready for exported. Similarly __declspec(dllimport) specifier can be used to ask the compiler driver to import that particular symbol and make it available. Compiler driver (CC) checks the symbol table for the symbol and if it finds the symbol as an interpreter (P) symbol, it just makes it available to the caller

Modified hidden.h with __declspec specifiers
-------------------------------------------------------------------
bpte4500s001:/sunbuild1/giri/testcases/symbol-hiding/%cat hidden.h
#ifdef S1S9_EXPORT
__declspec(dllexport) char *lastname(char *);
__declspec(dllexport) int agefunc();
__declspec(dllexport) char firstchar(char *);
__declspec(dllexport) int addtentomyage(int);
#else
__declspec(dllimport) char *lastname(char *);
__declspec(dllimport) int agefunc();
__declspec(dllimport) char firstchar(char *);
__declspec(dllimport) int addtentomyage(int);
#endif

bpte4500s001:/sunbuild1/giri/testcases/symbol-hiding/%CC -xldscope=hidden -c hidden.c
bpte4500s001:/sunbuild1/giri/testcases/symbol-hiding/%CC -G -xldscope=hidden -DS1S9_EXPORT -o libhidden.so hidden.o
bpte4500s001:/sunbuild1/giri/testcases/symbol-hiding/% elfdump -s -C libhidden.so
Symbol Table: .dynsym
index value size type bind oth ver shndx name
[9] 0x000005d0 0x00000020 FUNC GLOB D 0 .text char firstchar(char*)
[16] 0x00000590 0x0000002c FUNC GLOB D 0 .text char*lastname(char*)
[17] 0x00000550 0x0000002c FUNC GLOB D 0 .text int addtentomyage(int)
[19] 0x00000600 0x00000038 FUNC GLOB D 0 .text int agefunc()

Symbol Table: .symtab
index value size type bind oth ver shndx name
[25] 0x000108a8 0x00000004 OBJT LOCL H 0 .data age

Observe that because of the __declspec specifiers and preprocessor symbol S1S9_EXPORT, all the interfaces were marked as GLOB & D (global & defined); but still the data variable "age" is hidden as it was not exported (we didn't export it as driver program is not accessing the variable "age" directly)

Finally run the driver program

bpte4500s001:/sunbuild1/giri/testcases/symbol-hiding/%CC -o driver -lhidden driver.c
bpte4500s001:/sunbuild1/giri/testcases/symbol-hiding/%./driver
lname = mandalika
age = 35
first char = c
It just works!! Kudos to Sun ONE Studio compiler team for introducing this new feature (actually this feature was partially supported in S1S8). With this functionality the developers can export only the symbols that are needed by external modules and keep the rest in local module; hence the application performs better during run-time with less number of i-cache misses


Comments: Post a Comment



<< Home


2004-2019 

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