maxschlepzig
maxschlepzig

Reputation: 39195

Limiting shared library symbol visibility on Solaris

With GCC (on Linux) I can easily limit the visibility of symbols in shared libraries.

What are my options on Solaris (10)?

Do these GCC features also work with GCC on Solaris (especially with a GCC that uses the Solaris linker/assembler)?

And does the Solaris Studio C-compiler/linker provide similar attributes/pragmas for controlling the visibility of symbols (i.e. for setting the default to hidden and explicitly marking symbols as visible)?

Upvotes: 4

Views: 2048

Answers (3)

maxschlepzig
maxschlepzig

Reputation: 39195

I've tested some declaration annotation methods on a Solaris 10 machine. Surprisingly, the Solaris Studio C compiler also supports the GCC-hidden-function attribute.

A GCC configured with Solaris as/ld correctly implements the visibiltiy function attribute.

Thus, using the GCC function attribute syntax should be the most convenient/portable method because it works on Linux/GCC, Solaris/GCC and Solaris/Sol-Studio.

See the following table for an overview of the effects setting a function visibility to hidden.

Results

                                                     .dynsym|.symtab
System           Compiler     Visibility      nm     readelf           link-error
                                                     elfdump
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
Linux Fedora 17  gcc-4.7.2    not specified   T      GLOBAL DEFAULT    no
Linux Fedora 17  gcc-4.7.2    attr-hidden     t      -|LOCAL DEFAULT   yes
Solaris 10       gcc-4.8      not specified   GLOB   GLOB D            no
Solaris 10       gcc-4.8      attr-hidden     LOCL   -|LOCL H          yes
Solaris 10       cc-12.3      attr-hidden     LOCL   -|LOCL H          yes
Solaris 10       cc-12.3      __hidden        LOCL   -|LOCL H          yes

Methods

main.c:

#include <stdio.h>
#include <stdlib.h>

#include "power3.h"
#include "power2.h"

int main(int argc, char **argv)
{
  printf("Result: %d\n", power3(atoi(argv[1])));
  // should result in a link error when symbol is hidden
  printf("Result: %d\n", power2(atoi(argv[1])));

  return 0;
}

power2.h:

#ifndef POWER2_H
#define POWER2_H

#if !defined(NO_HIDE)
  #if defined(__GNUC__) || defined(FORCE_GCC)
    __attribute__((visibility("hidden")))
    #warning Using GNU-C function attribute
  #elif defined(__SUNPRO_C)
    __hidden
    #warning Using SUNPRO-C qualifier
  #endif
#endif
int
// GCC attribute also possible here
    power2(int x);
#endif

power3.h:

#ifndef POWER3_H
#define POWER3_H
int power3(int x);
#endif

power3.c

#include "power3.h"
#include "power2.h"
int power3(int x)
{
  return power2(x)*x;
}

Build commands:

cc -g   -c -o main.o main.c
cc  -g -fpic -c -o power3.po power3.c
cc  -g -fpic -c -o power2.po power2.c
cc -shared -fpic -o libpower.so power3.po power2.po
cc -L$PWD -Wl,-R$PWD

Introspection:

Under Linux:

nm libpower.so | grep power
readelf --dyn-sym libpower.so | grep power
readelf -s libpower.so | grep 'FUNC.*power'

Under Solaris:

/usr/ccs/bin/nm libpower.so | grep 'FUNC.*power'
/usr/ccs/bin/elfdump -N .dynsym libpower.so | grep 'FUNC.*power'
elfdump -N .symtab libpower.so | grep 'FUNC.*power'

System details:

The Solaris 10 system is a SPARC machine and the GCC uses as/ld from /usr/ccs/bin. The Solaris Studio version is 12.3 with patches applied (2013/02/04).

Sources

Global switches

For completeness, visibility of functions (and other symbols) can also be influenced by other means:

GCC-method                            Sol equivalent     effect
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
#pragma GCC visibility push(hidden)   -                  everything between push/pop
#pragma GCC visibility pop            -                  has default visibility hidden
#pragma GCC visibility push(default)  -                  ~ default to default-visibility
#pragma GCC visibility pop            -
-fvisibility=hidden                   -xldscope=hidden   sets default visibility of
-fvisibility=default                  -xldscope=global   a translation unit

The ELF standard also defines symbol visibilities internal and protected - which are also understood by the compilers, but which are less useful in general.

Upvotes: 4

maxschlepzig
maxschlepzig

Reputation: 39195

Another option is to use version script files. This works on Linux, Solaris/GCC and Solaris/CC.

Example

Consider a shared library where only a function power3() should be globally available. It uses power2() which is defined in another translation unit and power2() should be hidden.

Following version script specifies this:

$ cat vscript
{
  global: power3;
  local: *;
};

You can use one file for linking on Linux and Solaris - Linux/Solaris seem to understand the same syntactic constructs.

Build commands

System            Compiler   Link command
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
Linux Fedora 17   gcc-4.7.2  cc -shared -Wl,--version-script,vscript -fpic -o libpower.so ...
Solaris 10        gcc-4.8*   gcc -shared -Wl,-M,vscript -fpic -o libpower.so ...
Solaris 10        cc 12.3    cc -shared -M vscript -fpic -o libpower.so ...

Note that the GCC on Solaris is configured to use ld/as from /usr/ccs/bin.

Upvotes: 3

osgx
osgx

Reputation: 94445

Can't answer about gcc visibility on Solaris, but

In the Sun Studio there are

compiler option -xldscope, and the code attributes _global/_hidden

according to http://lists.qt.nokia.com/public/qt-interest/2010-January/017893.html

http://qt.gitorious.org/qt/qt/merge_requests/433:

SunStudio since version 8 (CC version 5.5) has had the ability to control symbol visibility in ABI via the linker option

 -xldscope=[global|symbolic|hidden] 

and via code "attributes" __global, __symbolic & __hidden.

-xldscope=global maps to GCC's -fvisibility=default 
-xldscope=symbolic maps to GCC's -fvisibility=protected 
-xldscope=hidden maps to GCC's -fvisibility=hidden

__global maps to GCC's __attribute__((visibility("default")) 
__symbolic maps to GCC's __attribute__((visibility("protected")) 
__hidden maps to GCC's __attribute__((visibility("hidden"))

And there is an overview from Sun: http://www.oracle.com/technetwork/server-storage/solaris/symbol-scope-140496.html

Reducing Symbol Scope with Sun Studio C/C++ by Giri Mandalika, May, 2005 (revised March 22, 2006)

Upvotes: 2

Related Questions