Solaris ABI Tools

Appcert FAQ

Table of Contents
General Questions
  1. Appcert is a Perl script; which version of Perl does it work with? How can I get a copy of Perl?
  2. When trying to install appcert I get errors "Invalid character (0x0)", "tar: directory checksum error", etc. What is happening?
  3. What OS releases does appcert support? Are there any plans to support SunOS 4.x (Solaris 1)?
  4. What languages does appcert support?
  5. What programming interfaces are covered by appcert?
  6. How long will it take to check my application?
  7. Can I use appcert to examine just a .so file?
  8. How do I get started analyzing the output of appcert?
  9. Appcert claims my application calls private interfaces such as _mutex_unlock() and _dgettext(). My source code contains no references to these symbols, or anything even vaguely related to them. Is appcert confused?
  10. Why can't I statically link with archives like libc.a and libsocket.a? After all, Sun provides many of them to me in /usr/lib.
  11. Why does appcert complain about applications which statically link only libc, libnsl, libsocket, etc, but not ones which statically link some other libraries like libXm?
  12. Appcert complains that I'm using __rpc_createerr(), but it isn't in my code and I'm not statically linking any libraries. What is going on?
  13. Appcert reports a number of unbound symbols in one of my application's shared objects, but they are symbols in Solaris libraries that the shared object calls. Why doesn't appcert recognize them?
  14. Appcert claims that a documented public interface is private. Isn't this a bug?
  15. What does it mean when appcert complains about an application because it couldn't find a library?
  16. When I run appcert on the dynamic libraries in /usr/lib I get results that don't make sense. Why?
  17. Why can't I use symbols like "_select", the way I can use "_read"?
  18. Why can't I use getdomainname in libnsl? What should I use instead?
  19. What's so bad about using sys_errlist and sys_nerr?
  20. Can appcert tell me if my application will run on Solaris version "N"?
  21. What can appcert tell me about backwards compatibility? For example, if I build my application on Solaris 8, will it run on 7, 2.6, etc?
  22. I have an application which is OK on Solaris Sparc 2.6. Do I have to run appcert on the software on Solaris 8 and 9 as well?
  23. I have an application which is OK on Solaris Sparc 7, and have ported the software to Solaris X86. Do I need a separate run of appcert for this?
  24. What's an ABI (vs. an API)?
  25. So how do I find out which interfaces are public? Conversely, which ones should I stay away from?
  26. What is the difference between the "unbundled" and "bundled" versions of appcert?
  27. Is there any effort being done for I18N/L10N (Internationalization/ Localization) for appcert?
  28. Our product is running on a number of other platforms (IBM, HP, and others). Is there a possibility to use appcert for these platforms as well?
 
 

General Questions


Q:
Appcert is a Perl script; which version of Perl does it work with? How can I get a copy of Perl?
A:
The appcert script works with either version 4 or 5 of Perl. Perl 5 is included in Solaris 8. Binaries for previous release of Solaris can be found at www.sunfreeware.com. You can also download the source for Perl, and the pre-compiled binaries for some platforms, from any site in the Comprehensive Perl Archive Network (CPAN). See The Perl Institute (www.perl.org) or the Perl Language Home Page (www.perl.com).

Back to Top


Q:
When trying to install appcert I get errors "Invalid character (0x0)", "tar: directory checksum error", etc. What is happening?
A:
Most likely this indicates a failed or partial download of the installation script (e.g. "appcert_install.sparc.sh"). The 2nd line of that file should contain checksum information that will allow you to perform a sum(1) checksum of the whole installation script. If the checksums do not match you will need to try downloading the file again. If the installation script checksum matches correctly, another possibility is that you do not have enough disk space in /tmp or in the destination directory to install the tool.

Back to Top


Q:
What OS releases does appcert support? Are there any plans to support SunOS 4.x (Solaris 1)?
A:
Appcert can examine applications written for Solaris 2.3 to Solaris 9 and beyond. There are no plans to support SunOS 4.x or releases of Solaris prior to 2.3.

Back to Top


Q:
What languages does appcert support?
A:
As long as the resulting binary objects constituting the application rely on dynamic linking (i.e., access Solaris services via dynamic bindings to C-language interfaces in Solaris shared libraries), it doesn't matter what source code they were derived from -- appcert will work on them. Binaries produced from FORTRAN, Mainsail and other languages have already been checked.Appcert doesn't work on Java programs, because they rely on a different runtime interface -- the Java virtual machine (this might be called the Java ABI). For Java applications please refer to http://developer.java.sun.com/ for information on developing stable applications. Appcert currently does not check usage of symbols in the C++ runtime interfaces (libC.so.3 or libC.so.5) because there is no defined C++ ABI to be part of the current Solaris system ABI definition. We expect such a C++ ABI to be defined eventually and will then include it in the Solaris ABI.Finally, appcert also doesn't check interpreted code such as shell scripts, Perl scripts, or Tcl scripts.

Back to Top


Q:
What programming interfaces are covered by appcert?
A:
The components currently covered are: all of the C programming interfaces included (bundled) in the Solaris product. That is, all of the interfaces in the base system and networking areas (/usr/man/man{2,3}), OpenWindows (/usr/openwin/man), and CDE (Motif) (/usr/dt/man).

Back to Top


Q:
How long will it take to check my application?
A:
Appcert takes about 1-10 seconds to examine each binary object in an application. Very large application binaries will take longer, as will work done over NFS or on slower processors. See the "-1" option for a faster mode of checking.

Back to Top


Q:
Can I use appcert to examine just a .so file?
A:
Yes, but make sure that the library's dependencies are recorded in the shared object (by using the compiler's "-l" "-R" and "-z defs" options. Also, in Solaris 2.6 and earlier, the compiler will not record a dependency on libc unless "-lc" is explicitly used on the command line.

Back to Top


Q:
How do I get started analyzing the output of appcert?
A:
Here is a three-step to procedure to follow: Step 1. See if appcert was able to check all of your binaries completely. If not, determine if incomplete checking was due to an inherent limitation in appcert (e.g., appcert can't check calls to the C++ library libC), or to the runtime environment (e.g., LD_LIBRARY_PATH) not being properly set up. If necessary, rerun appcert.Step 2. Check for unbound symbols in shared object binaries. These may be due to your application's using dlopen() to access the shared object; appcert has difficulty resolving the symbol bindings in that case (see the appcert man page for more information).Step 3. Check for private symbol usage. If appcert reports that your application uses a private symbol, but you can't find any occurrence of it in your source code, then the reference is probably coming from a statically linked library; these cases can be ignored (though you should use dynamically linked libraries whenever possible). If you are actually using a private interface in a library, check the documentation to find the appropriate public interface to use instead.

Back to Top


Q:
Appcert claims my application calls private interfaces such as _mutex_unlock() and _dgettext(). My source code contains no references to these symbols, or anything even vaguely related to them. Is appcert confused?
A:
This is a problem with statically linking libraries into applications: the archives linked in may themselves make calls to private symbols in Solaris shared objects. Because the archive is statically linked in, to appcert it appears your application is making these private calls itself (which, in a sense, it is).For historical reasons, releases prior to Solaris 7 provided only static archives for the libraries in /usr/ccs/lib (e.g., libcurses.a, libtermcap.a, libgen.a, and libmalloc.a). Unfortunately a small number of calls to private symbols occur in these static archives: for example, _mutex_unlock() is called from libmalloc.a and _dgettext() is called from libcurses.a. If your build environment includes linking command-line flags such as "-lmalloc" or "-lcurses", then there is a good chance you will statically link in the archives along with the private symbol calls--even if you have not explicitly used the "-Bstatic" option (this is because the linker will use an archive version of the library if it cannot find a shared version of it).Some build environments (e.g., imake) will automatically add linking flags like "-lmalloc". Developers may not always want this, preferring instead the malloc() family of functions in libc.so.1 to the ones in /usr/ccs/lib/libmalloc.a.To increase binary stability, we encourage developers to move away from linking Solaris static archives when building their applications; as of Solaris 7, shared object versions of the static archives in /usr/ccs/lib are now available. We understand this may be difficult because it requires you to provide two sets of binaries: one for Solaris 2.6 and earlier and a second for Solaris 7 and later. If you are porting some or all of your product to 64 bits, that may be a good time to remove all of the Solaris static archive linking in your application.To be on the safe side, appcert will flag as errors private symbol calls resulting from static linking.Here is a table created by correlating the private symbols in libc.so.1 (found via pvs(1)) with the UNDEF symbols (found via elfdump(1)) in the Solaris archive libraries:
    Solaris library archive:         private symbol in libc.so the archive calls:
    /usr/ccs/lib/libcurses.a:             _dgettext
    /usr/ccs/lib/libcurses.a:             _doscan
    /usr/ccs/lib/libgen.a:                _thr_getspecific
    /usr/ccs/lib/libgen.a:                _thr_keycreate
    /usr/ccs/lib/libgen.a:                _thr_setspecific
    /usr/ccs/lib/libgen.a:                _thr_main
    /usr/ccs/lib/libgen.a:                _mutex_unlock
    /usr/ccs/lib/libmalloc.a:             _mutex_unlock
    /usr/ccs/lib/libtermcap.a:            _dgettext
    /usr/ccs/lib/libtermcap.a:            _doscan
    /usr/ccs/lib/libtermlib.a:            _dgettext
    /usr/ccs/lib/libtermlib.a:            _doscan
    /usr/openwin/lib/libxview.a:          _doscan
    /usr/lib/libbsm.a:                    _mutex_unlock
    /usr/lib/libcrypt.a:                  _mutex_unlock
    /usr/lib/libcrypt.a:                  _thr_getspecific
    /usr/lib/libcrypt.a:                  _thr_keycreate
    /usr/lib/libcrypt.a:                  _thr_setspecific
    /usr/lib/libelf.a:                    _dgettext
    /usr/lib/libelf.a:                    __threaded
    /usr/lib/libmapmalloc.a:              _mutex_unlock
    /usr/ucblib/libcurses.a:              gtty
    /usr/ucblib/libcurses.a:              stty
    /usr/ucblib/libcurses.a:              _doscan
    /usr/ucblib/libucb.a:                 _getsp
    /usr/ucblib/libucb.a:                 __getcontext
    /usr/ucblib/libucb.a:                 _cerror
    /usr/ucblib/libucb.a:                 _memcmp
    /usr/ucblib/libucb.a:                 _memmove
    /usr/ucblib/libucb.a:                 _memset
    /usr/ucblib/libucb.a:                 _psignal
    /usr/ucblib/libucb.a:                 _smbuf
    /usr/ucblib/libucb.a:                 _setbufend
    /usr/ucblib/libucb.a:                 _siguhandler
    /usr/ucblib/libucb.a:                 __sigaction
    /usr/ucblib/libucb.a:                 _findiop
    /usr/ucblib/libucb.a:                 _doprnt
    /usr/ucblib/libucb.a:                 _realbufend
    /usr/ucblib/libucb.a:                 _bufsync
    /usr/ucblib/libucb.a:                 _findbuf
    /usr/ucblib/libucb.a:                 _xflsbuf
    /usr/ucblib/libucb.a:                 _ecvt
    /usr/ucblib/libucb.a:                 _fcvt
  
One can use this table to try to find any false positives of this sort that appcert warns about. Find the occurrences of the private symbol in the right hand column, then if you know the application statically links any of the corresponding archives in the left hand column that is most likely the reason for the appcert warning.

Back to Top


Q:
Why can't I statically link with archives like libc.a and libsocket.a? After all, Sun provides many of them to me in /usr/lib.
A:
Sun provides the archives because in some circumstances static linking cannot be avoided, for example if security is an issue or if one is constructing a boot-time or other administrative tool that has to run when dynamic linking is not operational. In general, it is an unsafe practice because the older code you statically link into your application may have private interfaces that do not cooperate properly with newer Solaris system components. From the intro(4) manpage:For many shared objects, an archive library is provided for backward compatibility. Use of these libraries may restrict an applications ability to migrate between different Solaris releases. As dynamic linking is the preferred compilation method on Solaris, the use of these libraries is discouraged.As a specific example of this sort of binary breakage, one can create a small TCP/IP client program that calls socket(3N) and connect(3N) to connect to a network service. When you build that program on Solaris 2.5 and statically link libsocket.a, the program will run fine on Solaris 2.5 and 2.5.1. However, if you take that binary to Solaris 2.6 or later and attempt to run it, the socket(3N) call will fail with an error. This is because in release 2.6 Solaris moved from STREAMS-based sockets to in-kernel sockets. Older network applications *dynamically* linked with libsocket.so.1 continue to run properly on 2.6 and above; it is only the ones statically linked with libsocket.a that have problems.

Back to Top


Q:
Why does appcert complain about applications which statically link only libc, libnsl, libsocket, etc, but not ones which statically link some other libraries like libXm?
A:
Generally speaking, statically linking libraries is a bad idea, and is discouraged as a default practice in developing with Solaris. Statically linking libc, libnsl, or libsocket is a very bad idea, and is a major source of the stability problems we see with applications, hence appcert looks specifically for static linking of those libraries. In the future, appcert may check for others as well.

Back to Top


Q:
Appcert complains that I'm using __rpc_createerr(), but it isn't in my code and I'm not statically linking any libraries. What is going on?
A:
Note, however, under certain build conditions the header file /usr/include/rpc/clnt.h will replace rpc_createerr by a macro that expands to involve __rpc_createerr(). This occurs when _REENTRANT is defined, and makes your application depend directly on the private symbol __rpc_createerr.If your application was compiled in this environment it causes static analysis tools like appcert to give a "false positive" (there is not much a binary analysis tool can easily do to see that the source code did not directly reference the private symbol). If your source code does not directly reference __rpc_createerr() you should be OK.

Back to Top


Q:
Appcert reports a number of unbound symbols in one of my application's shared objects, but they are symbols in Solaris libraries that the shared object calls. Why doesn't appcert recognize them?
A:
This situation arises when the shared object does not record its dependencies and is dlopen'ed by the application rather than linked. Since the shared object is never linked, and appcert uses the linker to resolve symbols, appcert cannot figure out what is going on unless the shared object records its dependencies. Since the default compiler behavior is to NOT record dependencies in shared objects, this situation frequently happens with dlopen'ed shared objects. To avoid this problem, make sure that when a shared object is built, its dependencies on Solaris libraries are explicitly recorded by using the the "-l" and "-R" compiler options, and force symbol resolution at compile time with the "-z defs" options. See the man pages for cc and ld.

Back to Top


Q:
Appcert claims that a documented public interface is private. Isn't this a bug?
A:
Sometimes. Examples are "mkstemp" in libc, and "gethostname" in libnsl, which were misclassified in those libraries' definitions prior to Solaris 7. Remember, however, that by "public" appcert means "stable"; there are a number of experimental or evolving interfaces that are available for use, but which are unsuitable for building applications that are intended to be binary compatible with future releases of Solaris. Appcert classifies such interfaces as "private" so that you will know about their potential instability.

Back to Top


Q:
What does it mean when appcert complains about an application because it couldn't find a library?
A:
Appcert looks in the list of directories specified by the current LD_LIBRARY_PATH (and finally in /usr/lib) for libraries containing the symbols used by an application. If a non-Solaris library is used by the application, but is not on LD_LIBRARY_PATH, then appcert cannot find those symbols unless the "-R" option was used at build time to specify where the libraries were located. The presence of unbound symbols and/or failure to find a library will cause appcert to fail an application.

Back to Top


Q:
When I run appcert on the dynamic libraries in /usr/lib I get results that don't make sense. Why?
A:
Appcert is a tool for testing YOUR application's dependencies on the Solaris system libraries (i.e the shared objects in /usr/lib, /usr/dt/lib, /usr/openwin/lib, ...). It examines your application to see what interfaces it depends on in the Solaris system libraries, and then checks to see that only stable, public interfaces are used. If you run appcert on the very shared libraries that it checks against, the outcome may be unpredictable. Please note that since the Solaris system libraries are a bundled product, it is all right for one of the those libraries to call private symbols in another because Sun makes sure the bundled shared objects cooperate correctly.

Back to Top


Q:
Why can't I use symbols like "_select", the way I can use "_read"?
A:
The "strong" symbols (e.g. _socket) associated with "weak" symbols (e.g. socket) are reserved as private (their behavior could change in the future). Your application should only directly reference the weak symbol (usually the strong symbols begin with "_"). Note that the weak symbol is typically an alias for the strong symbol, not a wrapper, so there is no performance penalty in using it.Unless your application is trying to do something very special (e.g. intercepting system library calls from code that is not under your control) use the corresponding public symbols.Note: under certain build environments it may happen that the strong/private symbol dependency gets recorded into your binary instead of the weak/public one, even though the source code doesn't appear to reference the private symbol. Nevertheless, steps should be taken to trace down why this is occurring and fix the dependency.

Back to Top


Q:
Why can't I use getdomainname in libnsl? What should I use instead?
A:
In Solaris, libnsl's getdomainname() is a private interface, unlike in some other UNIX implementations. In some cases there is an ambiguity about DNS domain vs. NIS domain.A replacement for getdomainname() depends on what it is being used for. In the case of DNS, the traditional way of doing this is to call res_init(3N) and look in a deprecated data structure. This is not supported. To obtain the NIS domain the documented way is to use "sysinfo(SI_SRPC_DOMAIN)".

Back to Top


Q:
What's so bad about using sys_errlist and sys_nerr?
A:
Briefly, there are two reasons:
  1. As new errors and error messages are added to Solaris, eventually the sys_errlist array will grow, and references to it in old binaries may result in fatal errors.
  2. The two interfaces are not present in 64-bit Solaris, so no 64-bit application can be built using them. Use strerror(3C) instead.

Back to Top


Q:
Can appcert tell me if my application will run on Solaris version "N"?
A:
Not directly. Appcert will only tell you if your application is at risk of not running because it uses unstable library interfaces. If those interfaces have not changed (yet) in Solaris "N", then your application may still run without failure. Conversely, since appcert only checks library interfaces, it cannot warn about other unstable practices such as relying on private non-library interfaces in Solaris (for example, the format of various files in /etc). In those cases, appcert may not find any binary stability problems, yet your application may not run on Solaris "N".

Back to Top


Q:
What can appcert tell me about backwards compatibility? For example, if I build my application on Solaris 8, will it run on 7, 2.6, etc?
A:
You can test your Solaris 8 application on a Solaris 8 machine against an earlier model such as Solaris 7 or 2.6. See the "-c" option.

Back to Top


Q:
I have an application which is OK on Solaris Sparc 2.6. Do I have to run appcert on the software on Solaris 8 and 9 as well?
A:
You do not need to run appcert, but, depending on the risks involved, to ensure that your application has no unstable behavioral or environmental dependencies (which appcert does not check for: e.g. an application that opens a private system file or parses human-readable output from a command), one should do some testing of the application on later releases as well.

Back to Top


Q:
I have an application which is OK on Solaris Sparc 7, and have ported the software to Solaris X86. Do I need a separate run of appcert for this?
A:
Yes, those X86 binaries need to be separately exercised on their platforms and run through appcert. Note that in this case, appcert must be run again - because you are checking a different binary object (an x86 binary rather than a SPARC one). Since there are some minor differences between the Solaris SPARC and x86 ABI's with regard to some of the compiler-emitted intrinsics for low-level use of the processor's instruction set, there is a slim possibility that an x86 binary compiled from the same source code as a SPARC binary could have had unstable binary interfaces in the emitted x86 code.

Back to Top


Q:
What's an ABI (vs. an API)?
A:
The API is the source level interface which is used when source code is compiled to produce a binary object. The ABI is the resulting set of binary level interfaces that the compiled application relies on at runtime. We're concerned with the ABI since we want a given binary object already out in the field to continue to run on subsequent OS releases.

Back to Top


Q:
So how do I find out which interfaces are public? Conversely, which ones should I stay away from?
A:
The public programming interface to Solaris at the source level (the Solaris API) is represented by what's in the Solaris man pages (most notably sections 2 and 3 of /usr/man, /usr/openwin/man, /usr/dt/man, and so on for unbundled products). If you compile a program which uses only these interfaces it is virtually certain that you'll have a Solaris ABI-conforming binary object. See also the library specific man pages in section 4 to find lists of public symbols (Solaris 2.6 and above).Do not assume, however, that any interface you find in a Solaris header file is public (i.e. part of the API). Some interfaces present in Solaris header files are private, and are there only because the Solaris system implementation is built using these same header files.

So:

* Write code using only the Solaris API (those source-level interfaces specified in the man pages for the OS release you are targeting) and then

* Run appcert to verify that your resulting binary depends only on public binary interfaces (the Solaris ABI).

Back to Top


Q:
What is the difference between the "unbundled" and "bundled" versions of appcert?
A:
Starting with Solaris 8 (4/01) a version of appcert was bundled with Solaris in the developer cluster. It is based on the unbundled tool that has been available at http://www.sun.com/software/solaris/programs/abi/appcert.html The primary differences between the two tools is that the bundled one is specific to the Solaris release it is shipped with (i.e. it does not carry along with it model file definitions for all previous versions of Solaris). It also does not contain tutorial information such as html output, etc.Model files for Solaris 9 have been included in the unbundled appcert version 2.4. (Please note that these model files are not required to test for stability: if an application uses only public interfaces on a release, it will be stable on all later Solaris releases).

Back to Top


Q:
Is there any effort being done for I18N/L10N (Internationalization/ Localization) for appcert?
A:
The unbundled tool (see the previous question) is not internationalized, but the bundled appcert (Solaris 8 4/01) is.

Back to Top


Q:
Our product is running on a number of other platforms (IBM, HP, and others). Is there a possibility to use appcert for these platforms as well?
A:
Appcert is specific to the Solaris ABI. It requires definitions specific to each platform and we have not seen similar definitions other vendors. We have made a simplified port of appcert to Linux-based systems (particularly straight forward due to the similarities between the Solaris and GLIBC dynamic linkers. This opensource tool is called abicheck and is located at http://abicheck.sourceforge.net/

Back to Top