[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Adding SONAME to a shared object in KLEE



[ longish mail, bear with me ]

Greetings, Marko,


On Thu, Feb 18, 2016 at 10:43:27AM -0700, Marko Dimjašević wrote:
# Please CC me in replies as I'm not on d-devel

Hi all,

I would need help with fixing a SONAME issue with my ITP package. It's a
tool for development, which systematically explores as many as possible
execution paths in a given program, potentially triggering crashes
unknown before.

[...]


The issue is reported by Lintian:

E: klee: sharedobject-in-library-directory-missing-soname
usr/lib/libkleeRuntest.so
N:
N:    A shared object was identified in a library directory (a directory
in
N:    the standard linker path) which doesn't have a SONAME. This is
usually
N:    an error.
N:
N:    SONAMEs are set with something like gcc -Wl,-soname,libfoo.so.0,
where 0
N:    is the major version of the library. If your package uses libtool,
then
N:    libtool invoked with the right options should be doing this.
N:
N:    To view the SONAME of a shared library, run readelf -d on the
shared
N:    library and look for the tag of type SONAME.
N:
N:    Severity: important, Certainty: possible
N:
N:    Check: shared-libs, Type: binary, udeb
N:


The packaged tool doesn't use Libtool. I understand what the error
message is saying, but even with the help I got on d-mentors I wasn't
able to resolve the issue.

Therefore, I'd appreciate if someone could take a look and help with
resolving it.

I packaged a library (libwildmagic) that involved re-writing partially
the makefile shipped by upstream. In the process I tried to explain
what involves packaging a UNIX/LINUX-based shared object file to the
upstream developer who was only knowledgeable of Windows-based
development. I put that text that I modified to suit your case below.

~~~~~ soname stuff explained ~~~~~

Shared libraries are one of the most interesting/complex fields in
GNU/Linux systems. I'll try to be clear. However, if you want a
document that is pretty neat, then head for this page:

http://www.dwheeler.com/program-library/Program-Library-HOWTO/

by David Wheeler, who is a respected hacker.

But, I'm willing to recap some things here, akin to an "exec summary":

Shared libraries in GNU/Linux are versioned, contrary to what used to
be with Windows-based dlls.

We work on a library that is named kleeRuntest and the file on disk is
thus libkleeRuntest.

SONAME
======

The library file proper should store a specific bit of information
that is called a SONAME (shared object name). That SONAME should be in
the form lib<name>.so.<major-version-number>. In our example, that would be
libkleeRuntest.so.1 (as suggested by then file klee_1.1.0-1.dsc).

REAL-NAME
=========

Note however, that the SONAME is not the "real name" of the library,
that is, the name of the actual file containing the binary code
offered by the library. The real name of the library typically is the
soname *plus* a minor version number, that is actually called the
release number. That REAL-NAME is the name that should be used when
actually *creating* the library file upon building it (which is not
the case presently with your build setup, see below).

Thus, the REAL-NAME would be lib<name>.so.<major-version-number>.<minor-version.number>

libkleeRuntest.so.1.1 (again, klee_1.1.0-1.dsc).

OK, with that out of the way, let's go on with use/dev operations involving
the library:

LINKER-NAME
===========

When building a software that makes use of a library, the linker
should be told the library name to use. That library name should be in
the form of the SONAME *without the version number*. That is, the
linker should only know the name of the library to use for the
linkage.

For your library, that would be:

libkleeRuntest.so

But, then, how to tell from the LINKER-NAME, which actual file should
be used, as we've seen above that the actual file is named with the
REAL-NAME? Well, the bridge between LINKER-NAME and REAL-NAME is a
simple symbolic link.

For your lib, the real binary library file what we should ship is:
/usr/lib/libkleeRuntest.so.1.1


Then, the packager is reponsible for creating the LINKER-NAME symbolic
link:

/usr/lib/libkleeRuntest.so ---> /usr/lib/libkleeRuntest.so.1.1

so that, when the linkder searches for /usr/lib/libkleeRuntest it ends
up actually using /usr/lib/libkleeRuntest.so.1.1.

The linker name is a development/build-time name. This is not the name
that is actually used when dynamically linking the library upon
execution of the program code.

The dynamic loading process needs yet another name, that would be the
SONAME. But, as above, the SONAME is *not* the name of the library as
we ship it, so again we should provide a symbolic link:

/usr/lib/libkleeRuntest.so.1 ---> /usr/lib/libkleeRuntest.so.1.1

The SONAME is the name that the dynamic loader gets from the program
that is being executed and that requires to load library stuff. For
example, my massXpert program has these library NEEDS:

objdump -x /usr/bin/massxpert | grep NEEDED
   NEEDED               libQtSvg.so.4
   NEEDED               libQtGui.so.4
   NEEDED               libQtXml.so.4
   NEEDED               libQtCore.so.4
   NEEDED               libstdc++.so.6
   NEEDED               libm.so.6
   NEEDED               libgcc_s.so.1
   NEEDED               libc.so.6

Now, as you can see, the listed names are all SONAMES :
lib<name>.so.<version>.

For example, if I now want to see the files relating to libQtCore.so.4:

ls /usr/lib/x86_64-linux-gnu/libQtCore.so* -l
      18 Jan 12 05:15 /usr/lib/x86_64-linux-gnu/libQtCore.so -> libQtCore.so.4.8.6
      18 Jan 12 05:15 /usr/lib/x86_64-linux-gnu/libQtCore.so.4 -> libQtCore.so.4.8.6
      18 Jan 12 05:15 /usr/lib/x86_64-linux-gnu/libQtCore.so.4.8 -> libQtCore.so.4.8.6
3033168 Jan 12 05:17 /usr/lib/x86_64-linux-gnu/libQtCore.so.4.8.6

You can see that the real library name is indeed libQtCore.so.4.8.6,
of size 3033168, and the other ones are only symbolic links.


OK, NOW THAT WE HAVE THESE FUNDAMENTALS HOW WOULD WE BE DOING WITH
libkleeRuntest library ?

The real name
=============


Generate the library right from the build with the proper name:

libkleeRuntest.so.1.1

How would we do that ? We need to tell the linker how to create the
library file:

compilation flags to build your libkleeRuntest shared object lib:

-shared -fPIC -Wl,-soname,libkleeRuntest.so.1.1 -o libkleeRuntest.so.1.1

These flags need to go in the makefile that drives the build of the library.

This will build the properly-named lib file: libkleeRuntest.so.1.1.

You can check that by running this command:

readelf -d libkleeRuntest.so.1.1

will output something like:
Dynamic section at offset 0xb8c0 contains 26 entries:
   Tag        Type                         Name/Value
  0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
  0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
  0x000000000000000e (SONAME)             Library soname: [libkleeRuntest.so.1]
  0x000000000000000c (INIT)               0x4e68
  0x000000000000000d (FINI)               0x965c

As you can see, the SONAME is correctly mentioned now.

This is all we need to make real-world UNIX-based libs.

Now, we still need the symbolic links, and this is your debian
packager duty. How is this implemented in Debian and Debian-based
systems ?

When packaging libraries, we always start from a source package that
somehow only ships the original source tarball plus methods to build
the binary packages.

A random user will only want binary packages because she would not
even know what to do with a source package.

The software will be shipped as source in the debian source package
named libkleeruntest.

This source package will contain an attached archive file containing a
debian/ directory plus all of its contents.

In the debian/* files, we document how to process the source package
to actually build binary packages.

For each source package that contains a library (or set of libraries,
as is your case) we need to produce two different binary packages:

libkleeruntest1, which is the binary package that a user will have to
install if she ever needs to install a package that makes use of that
library. This package only contains the REAL-NAME file and the
SONAME-to-REAL-NAME symbolic link.

libkleeruntest-dev, which is the binary package that ships all the
files needed for the use of the library from a development
perspective. That is the package where the /usr/include/*.h[pp] files
are shipped. We also ship the second LINKER-NAME-to-REAL-NAME symbolic
link. In most cases, the -dev package is not versioned: it is
typically the last version of the library which in turn depends on the
other binary package of the same version, that of course ships the
real library file.

Hope this helps.

I tried to ./configure  the package, but I am missing a library on
this system and I cannot install it. If you cannot succeed with the
explanations above, send the makefile's (there are some, I saw) and
I'll try to see if I can help.

Ciao
Filippo

--
Filippo Rusconi, PhD - public crypto key 7694CF42@ pgp.mit.edu

Attachment: pgpeDLDoWTZ5C.pgp
Description: PGP signature


Reply to: