Discussion:
Compile-time alternative to LD_PRELOAD
(too old to reply)
Frederick Gotham
2021-07-19 12:46:03 UTC
Permalink
I have a special audio driver that needs additional clean-up when the ALSA (Advanced Linux Sound Architecture) function, 'snd_pcm_close', is called.

This additional clean-up can't take place inside the C code for the audio driver, and so it must happen inside the ALSA library 'libasound.so' whenever a process calls 'snd_pcm_close'. To make things a little more complicated, 'libasound.so' is a pre-compiled binary for which I don't have the source code (a 3rd party has already made alterations to 'alsa-lib' and they won't give me the source code).

I could create a small shared library file with just one function 'snd_pcm_close', and then when I start any program that uses ALSA, I can use LD_PRELOAD as follows:

LD_PRELOAD=my_small_library.so some_program_that_uses_sound

This would be fine if I only had one or two programs that use sound, and if this rarely changed.

I'm looking for a solution though that will work with *any* program that links with 'libasound.so'. So here's what I did:

Step 1) Rename the original library
mv libasound.so libAsound.so
Step 2) Change the 'soname' inside the original library
sed -i 's/libasound.so/libAsound.so/g' libAsound.so
Step 3) Write my own small library containing one function 'snd_pcm_close'
(see the source code for this library at the end of this post)
Step 4) Build my own small library to link with the original renamed library:
gcc -o libasound.so.2.0.0 my_small_library.c -ldl -L./ -l:libAsound.so.2.0.0 -Wl,-soname,libasound.so.2

So then when any process (for example 'baresip') links with 'libasound.so', here's what will happen:

a) baresip links with our small library libasound.so
b) libasound.so links with the original library named libAsound.so
c) So now both shared libraries, libasound.so and libAsound.so, have been loaded into the address space of baresip
d) Since libasound.so was loaded before libAsound.so, the function 'snd_pcm_open' is taken from my small library
e) All other functions such as 'snd_pcm_open' and 'snd_pcm_writei' are of course missing from our small library, but the Linux operating system automatically finds these functions in any other library that's linked in, and hence finds them in libAsound.so

I have tested this out and it works. What surprises me though is that I can't find a similar implementation to this on the internet -- I mean surely somebody has done this before? If anyone can suggest a better way of doing this, I'm all ears.

Source code for my small shared library:

#include <dlfcn.h> /* dlopen, dlsym, dlclose */

static void Patch_Code(void); /* Defined lower down in this file */

int snd_pcm_close(void *arg)
{
int retval = -1; /* ALSA manual says "Zero on success, or a negative value on error" */

void *const dlhandle = dlopen("libAsound.so", RTLD_NOW|RTLD_LOCAL); /* Load original lib */

if ( dlhandle )
{
int (*const snd_pcm_close_PROPER)(void*) = dlsym(dlhandle, "snd_pcm_close");

if ( snd_pcm_close_PROPER ) retval = snd_pcm_close_PROPER(arg); /* Call original func */

dlclose(dlhandle);
}

Patch_Code(); /* <--------------- Our patch is invoked here */

return retval;
}

static void Patch_Code(void)
{
/* We put our patch in here */
}
Nicolas George
2021-07-19 15:04:36 UTC
Permalink
Frederick Gotham , dans le message
Post by Frederick Gotham
(a 3rd party has already made alterations to 'alsa-lib' and they won't
give me the source code).
libasound is LGPL: if they distribute a binary without the source code, they
are infringing. You can threaten them.
Lew Pitcher
2021-07-19 15:10:12 UTC
Permalink
Post by Frederick Gotham
I have a special audio driver that needs additional clean-up when the ALSA
(Advanced Linux Sound Architecture) function, 'snd_pcm_close', is called.
This additional clean-up can't take place inside the C code for the audio
driver, and so it must happen inside the ALSA library 'libasound.so' whenever
a process calls 'snd_pcm_close'. To make things a little more complicated,
'libasound.so' is a pre-compiled binary for which I don't have the source
code (a 3rd party has already made alterations to 'alsa-lib' and they won't
give me the source code).
I could create a small shared library file with just one function
'snd_pcm_close', and then when I start any program that uses ALSA, I can use
LD_PRELOAD=my_small_library.so some_program_that_uses_sound
This would be fine if I only had one or two programs that use sound, and if
this rarely changed.
I'm looking for a solution though that will work with *any* program that
[snip]

ISTM that you have overlooked the advantages of LD_PRELOAD and minimized
the disadvantages of your proposed solution.

For your solution to work, you need to rename the original libasound library.
Each time your distribution or software supplier updates libasound, you have
to remember to preserve your stand-in libasound.so and rename the distributor
supplied libasound.so to the name you chose to work with. This seems dangerous
to me, as it presumes that you will remember to do this each time you update
the official libasound.so.

OTOH, /proper/ use of LD_PRELOAD would permit you to install a library that
will intercept and interceed in any snd_pcm_close() calls from running
processes, without requiring manual intervention with each libasound module
refresh.

The key would be to add the path to your intercept library into the
/etc/ld.so.preload file (see ld.so(8) for details) to ensure that all processes
have your intercept library loaded ahead of, and instead of, the libasound library.

Alternatively, you /could/ alter the various login-related scripts to set the
LD_PRELOAD environment variable appropriately, but this seems chancier, in that
you need to change /all/ the login environment setup scripts, both commandline and
GUI.
--
Lew Pitcher
"In Skills, We Trust"
Loading...