Why does loading the libc shared library have 'LibraryLoader' object is not callable error?
You're confusing lower case cdll
(which is a LibraryLoader
) with upper case CDLL
, which is the constructor for shared libraries.
This code will work as expected:
libc = ctypes.CDLL("/lib/x86_64-linux-gnu/libc.so.6")
Docker Alpine executable binary not found even if in PATH
On Alpine Linux, the not found
error is a typical symptom of dynamic link failure. It is indeed a rather confusing error by musl's ldd
linker.
Most of the world Linux software is linked against glibc, the GNU libc library (libc provides the standard C library and POSIX API). Most Linux distributions are based on glibc. OTOH, Alpine Linux is based on the musl libc library, which is a minimal implementation and strictly POSIX compliant. Executables built on glibc distributions depend on /lib/x86_64-linux-gnu/libc.so.6
, for example, which is not available on Alpine (unless, they are statically linked).
Except for this dependency, it's important to note that while musl attempts to maintain glibc compatibility to some extent, it is far from being fully compatible, and complex software that's built against glibc won't work with musl-libc, so simply symlinking /lib/ld-musl-x86_64.so.1
to the glibc path isn't likely going to work.
Generally, there are several ways for running glibc binaries on Alpine:
- Install one the glibc compatibility packages, libc6-compat or gcompat:
# apk add gcompat
apk add libc6-compat
Both packages provide a light weight glibc compatibility layer which may be suitable for running simple glibc applications.libc6-compat
implements glibc compatibility APIs and provides symlinks to glibc shared libraries such as libm.so
, libpthread.so
and libcrypt.so
. The gcompat
package is based on Adelie Linux gcompat project and does the same but provides a single library libgcompat.so
. Both libraries install loader stubs. Depdending on the application, one of them may work while the other won't, so it's good to try both.
- Install proper glibc on Alpine, for providing all glibc methods and functionalities. There are glibc builds available for Alpine, which should be installed in the following procedure (example):
# Source: https://github.com/anapsix/docker-alpine-java
ENV GLIBC_REPO=https://github.com/sgerrand/alpine-pkg-glibc
ENV GLIBC_VERSION=2.30-r0
RUN set -ex && \
apk --update add libstdc++ curl ca-certificates && \
for pkg in glibc-${GLIBC_VERSION} glibc-bin-${GLIBC_VERSION}; \
do curl -sSL ${GLIBC_REPO}/releases/download/${GLIBC_VERSION}/${pkg}.apk -o /tmp/${pkg}.apk; done && \
apk add --allow-untrusted /tmp/*.apk && \
rm -v /tmp/*.apk && \
/usr/glibc-compat/sbin/ldconfig /lib /usr/glibc-compat/lib
Use statically linked executables. Static executables don't carry dynamic dependencies and could run on any Linux.
Alternatively, the software may be built from source on Alpine.
For LibreDWG, let's first verify the issue:
/usr/local/bin # ./dwg2dxf
/bin/sh: ./dwg2dxf: not found
/usr/local/bin
/usr/local/bin # ldd ./dwg2dxf
/lib64/ld-linux-x86-64.so.2 (0x7fd375538000)
libredwg.so.0 => /usr/local/lib/libredwg.so.0 (0x7fd3744db000)
libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7fd375538000)
libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7fd375538000)
Error relocating /usr/local/lib/libredwg.so.0: __strcat_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __snprintf_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __memcpy_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __stpcpy_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __strcpy_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __printf_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __fprintf_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __strncat_chk: symbol not found
Error relocating /usr/local/lib/libredwg.so.0: __sprintf_chk: symbol not found
Error relocating ./dwg2dxf: __snprintf_chk: symbol not found
Error relocating ./dwg2dxf: __printf_chk: symbol not found
Error relocating ./dwg2dxf: __fprintf_chk: symbol not found
You can see that dwg2dxf
depends on several glibc symbols.
Now, let's follow option 2 for installing glibc:
/usr/src/app # cd /usr/local/bin
/usr/local/bin # ls
dwg2SVG dwg2dxf dwgadd dwgbmp dwgfilter dwggrep dwglayers dwgread dwgrewrite dwgwrite dxf2dwg dxfwrite
/usr/local/bin # ./dwg2dxf
/bin/sh: ./dwg2dxf: not found
/usr/local/bin # export GLIBC_REPO=https://github.com/sgerrand/alpine-pkg-glibc && \
> export GLIBC_VERSION=2.30-r0 && \
> apk --update add libstdc++ curl ca-certificates && \
> for pkg in glibc-${GLIBC_VERSION} glibc-bin-${GLIBC_VERSION}; \
> do curl -sSL ${GLIBC_REPO}/releases/download/${GLIBC_VERSION}/${pkg}.apk -o /tmp/${pkg}.apk; done && \
> apk add --allow-untrusted /tmp/*.apk && \
> rm -v /tmp/*.apk && \
> /usr/glibc-compat/sbin/ldconfig /lib /usr/glibc-compat/lib
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/community/x86_64/APKINDEX.tar.gz
(1/1) Installing curl (7.74.0-r1)
Executing busybox-1.32.1-r3.trigger
OK: 629 MiB in 126 packages
(1/2) Installing glibc (2.30-r0)
(2/2) Installing glibc-bin (2.30-r0)
Executing glibc-bin-2.30-r0.trigger
/usr/glibc-compat/sbin/ldconfig: /usr/local/lib/libredwg.so.0 is not a symbolic link
/usr/glibc-compat/sbin/ldconfig: /usr/glibc-compat/lib/ld-linux-x86-64.so.2 is not a symbolic link
OK: 640 MiB in 128 packages
removed '/tmp/glibc-2.30-r0.apk'
removed '/tmp/glibc-bin-2.30-r0.apk'
/usr/glibc-compat/sbin/ldconfig: /usr/glibc-compat/lib/ld-linux-x86-64.so.2 is not a symbolic link
/usr/glibc-compat/sbin/ldconfig: /usr/local/lib/libredwg.so.0 is not a symbolic link
Voila:
/usr/local/bin # ./dwg2dxf
Usage: dwg2dxf [-v[N]] [--as rNNNN] [-m|--minimal] [-b|--binary] DWGFILES...
difference between -lgcc_s and gcc
libgcc_s.so
is a shared library, libgcc.a
is a static library. They are not equivalent; it may be necessary to link both. libgcc_s contains global variables which must not have multiple copies in a process; the code in libgcc is safe to link multiple times.
Can you compile a shared object to prefer local symbols even if it's being loaded by a program compiled with -rdynamic?
Have you tried -Bsymbolic
linker option (or -Bsymbolic-functions
)? Quoting from ld
man:
-Bsymbolic
When creating a shared library, bind references to global symbols to the definition within the shared library, if any. Normally, it is possible for a program linked against a shared library to override the definition within the shared library. This option can also be used with the --export-dynamic option, when creating a position independent executable, to bind references to global symbols to the definition within the executable. This option is only meaningful on ELF platforms which support shared libraries and position independent executables.
It seems to solve the problem:
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -shared -fPIC -o shared.so shared.c
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -o main main.c internal.c -l dl -rdynamic
$ ./main
main:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
I should only be callable from the main program
baz:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
I should only be callable from the main program
bar:
It's important that I'm callable from a program that loads shared.so as well as from other functions in shared.so
$ gcc -m64 -std=c89 -Wall -Wextra -Werror -pedantic -shared -fPIC -Wl,-Bsymbolic -o shared.so shared.c
$ ./main
main:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
I should only be callable from the main program
baz:
It's important that I am callable from both main and from any .so that we dlopen, that's why we compile with -rdynamic
bar:
It's important that I'm callable from a program that loads shared.so as well as from other functions in shared.so
bar:
It's important that I'm callable from a program that loads shared.so as well as from other functions in shared.so
Related Topics
How to Use Expect on Windows Without Installing Cygwin
How to Convert an Xml File to Nice Pandas Dataframe
Fast Punctuation Removal with Pandas
Creating a Dictionary from a CSV File
Python Subprocess/Popen with a Modified Environment
Behavior of Exec Function in Python 2 and Python 3
Is It Worth Using Python's Re.Compile
How Remove Camera Preview to Raspberry Pi
Add Custom Method to String Object
Writing a Pandas Dataframe to CSV File
Removing Elements That Have Consecutive Duplicates
Replacing Instances of a Character in a String
Python List Sort in Descending Order