Followed Readme, binary still contains GLIBC_2.33 funcs
Just messing around with trying to learn how to compile compatible binaries. I'm working with socat for now:
$ unzip socat-master.zip
$ cd socat-master
$ ./configure
$ make
$ objdump -T socat | grep GLIBC_ | grep 2\.33
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) lstat64
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) stat64
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) lstat
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) stat
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) mknod
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) fstat64
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) fstat
And if I take the binary from my 22.04 system to an other 18.04 I get the error:
/tmp/socat: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by /tmp/socat)
So I build with the provided header:
$ make clean
$ cp ../glibc_version_header-master/version_headers/x64/force_link_glibc_2.19.h .
$ export CFLAGS="-include force_link_glibc_2.19.h -static-libgcc"
$ ./configure
$ make
...
gcc -include force_link_glibc_2.19.h -static-libgcc -D_GNU_SOURCE -Wall -Wno-parentheses -DHAVE_CONFIG_H -I. -I. -c -o xio-udp.o xio-udp.c
gcc -include force_link_glibc_2.19.h -static-libgcc -D_GNU_SOURCE -Wall -Wno-parentheses -DHAVE_CONFIG_H -I. -I. -c -o xio-progcall.o xio-progcall.c
gcc -include force_link_glibc_2.19.h -static-libgcc -D_GNU_SOURCE -Wall -Wno-parentheses -DHAVE_CONFIG_H -I. -I. -c -o xio-exec.o xio-exec.c
gcc -include force_link_glibc_2.19.h -static-libgcc -D_GNU_SOURCE -Wall -Wno-parentheses -DHAVE_CONFIG_H -I. -I. -c -o xio-system.o xio-system.c
...
But my produced binary still has 2.33 symbols in it:
$ objdump -T socat | grep GLIBC_ | grep 2\.33
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) lstat64
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) stat64
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) lstat
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) stat
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) mknod
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) fstat64
0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.33) fstat
What am I doing wrong?
Until glibc 2.32, stat64 etc. were redirected to __xstat64 etc. by inline functions or macros; glibc 2.33 changed them to true functions. As a result, code compiled against glibc 2.32 or older will get the old __xstat64 etc. implementation that is still present, whereas code compiled against glibc 2.33 will get the new stat64 etc. implementation.
Maybe a workaround might be:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <fcntl.h>
#define REDIRECT(RET, NAME, T2) \
RET \
NAME (const char *path, T2 A2) \
{ \
RET (*_NAME) (const char *path, T2 A2); \
RET result; \
_NAME = (RET (*)(const char *path, T2 A2)) dlsym (RTLD_NEXT, #NAME); \
result = _NAME (path, A2); \
return result; \
}
REDIRECT(int, stat, struct stat *)
REDIRECT(int, stat64, struct stat64 *)
REDIRECT(int, lstat, struct stat *)
REDIRECT(int, lstat64, struct stat64 *)
REDIRECT(int, fstat, struct stat *)
REDIRECT(int, fstat64, struct stat64 *)
Hmm I see what you are saying. Sounds like an older glibc on my host might fix it, I'll have to spin up a VM to try that. I tried adding the workaround to the force_link_glibc_2.19.h
Then I reconfigured with ./configure and attempted to make
First there are a ton of errors about redefining _GNU_SOURCE
<command-line>: note: this is the location of the previous definition
gcc -include force_link_glibc_2.19.h -static-libgcc -D_GNU_SOURCE -Wall -Wno-parentheses -DHAVE_CONFIG_H -I. -I. -c -o xio-readline.o xio-readline.c
In file included from <command-line>:
./force_link_glibc_2.19.h:3729: warning: "_GNU_SOURCE" redefined
3729 | #define _GNU_SOURCE
But its just a warning, so I pressed on. Unfortunately the workaround doesn't quite work:
...
gcc -include force_link_glibc_2.19.h -static-libgcc -D_GNU_SOURCE -Wall -Wno-parentheses -DHAVE_CONFIG_H -I. -o socat socat.o libxio.a -lrt -lutil
/usr/bin/ld: libxio.a(xioinitialize.o): in function `stat':
xioinitialize.c:(.text+0x0): multiple definition of `stat'; socat.o:socat.c:(.text+0x0): first defined here
/usr/bin/ld: libxio.a(xioinitialize.o): in function `stat64':
xioinitialize.c:(.text+0x4a): multiple definition of `stat64'; socat.o:socat.c:(.text+0x4a): first defined here
/usr/bin/ld: libxio.a(xioinitialize.o): in function `lstat':
xioinitialize.c:(.text+0x94): multiple definition of `lstat'; socat.o:socat.c:(.text+0x94): first defined here
/usr/bin/ld: libxio.a(xioinitialize.o): in function `lstat64':
xioinitialize.c:(.text+0xde): multiple definition of `lstat64'; socat.o:socat.c:(.text+0xde): first defined here
/usr/bin/ld: libxio.a(xioinitialize.o): in function `fstat':
xioinitialize.c:(.text+0x128): multiple definition of `fstat'; socat.o:socat.c:(.text+0x128): first defined here
/usr/bin/ld: libxio.a(xioinitialize.o): in function `fstat64':
xioinitialize.c:(.text+0x172): multiple definition of `fstat64'; socat.o:socat.c:(.text+0x172): first defined here
... repeat for all the .c files that use these functions ...
collect2: error: ld returned 1 exit status
make: *** [Makefile:115: socat] Error 1
I tried adding the workaround to the force_link_glibc_2.19.h
You have to embed the snippet into your own source code - somewhere at the very beginning. I tried it and it seemed to work. However I am not using it because with glibc_2.34 and newer the approach in general does not work anymore because of the new __libc_start_main symbol.
I would say don't waste your time trying to get it working with glibc_2.33 ;)
Any update on this? This looked among the most promising approaches.
I was having problem with stat() not being found in the older glibc. It seems that stat() was implemented as a C preprocessor macro, redirecting to __xlstat(), which is present in the older glibc. I'll keep trying to find a way around this issue.
Update: I gave up and am now setting up compilation in a Docker container based on ubuntu:18.04, to get an old glibc. I'm using llvm with clang-17 to get a modern compiler. The LLVM compiler suite is godsent here, thanks to their ubuntu:18.04 apt repository for the latest clang version.
I managed to redirect the *stat functions (this example is only for stat() and fstat()):
__asm__(".symver __fxstat, __fxstat@GLIBC_2.0");
__asm__(".symver __xstat, __xstat@GLIBC_2.0");
struct stat;
extern int __xstat(int, const char *, struct stat *);
static inline int stat(const char *path, struct stat *statbuf)
{ return __xstat(3, path, statbuf); }
extern int __fxstat(int, int, struct stat *);
static inline int fstat(int fd, struct stat *statbuf)
{ return __fxstat(3, fd, statbuf); }
But I'm indeed stuck on redirecting the __libc_start_main symbol to its older version. I could link in my own startfile, but I'd really rather not do that.
I wish you could influence .symver logic from the linker script.
Actually, figured out that part as well. This is now a program using stat(), compiled on a glibc 2.39 system, referencing only symbols in GLIBC_2.0:
// Needs to be included in every file that uses stat()
// May also be defined only once, but in such a case "static inline" must be removed
__asm__(".symver __xstat, __xstat@GLIBC_2.0");
struct stat;
extern int __xstat(int, const char *, struct stat *);
static inline int stat(const char *path, struct stat *statbuf)
{ return __xstat(3, path, statbuf); }
// Must be defined once in the entire program
__asm__(".symver old__libc_start_main, __libc_start_main@GLIBC_2.0");
__asm__(".symver new__libc_start_main, __libc_start_main@@_NEW");
__asm__(".global new__libc_start_main");
__asm__("new__libc_start_main: jmp old__libc_start_main@PLT");
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
struct stat buf;
stat(argv[0], &buf);
printf("%lu\n", buf.st_ino);
}
Compile with: gcc -m32 -Os -U_FORTIFY_SOURCE -no-pie -o test test.c
$ objdump -x test | grep GLIBC
0x0d696910 0x00 03 GLIBC_2.0
00000000 F *UND* 00000000 printf@GLIBC_2.0
00000000 F *UND* 00000000 __xstat@GLIBC_2.0
00000000 F *UND* 00000000 __libc_start_main@GLIBC_2.0
I've successfully implemented this in a (simple, dependency-free) program: https://github.com/mid-kid/metroskrew/commit/e382cae3c78e8c492cdfd0b967203e7be0e5ed3e