NixOS / patchelf

A small utility to modify the dynamic linker and RPATH of ELF executables
GNU General Public License v3.0
3.59k stars 487 forks source link

Should --clear-symbol-version remove versions from multiple instances? #252

Open nitz opened 3 years ago

nitz commented 3 years ago

Describe the bug

I have a shared object I'm attempting to remove the symbol version from that is linking to a newer version of libm.so than my machine has. The shared object seems to have 2 instances of the symbol, one in .dynsym the other in .symtab, but the --clear-symbol-version flag only seems to work on the first.

Steps To Reproduce

Example:

cmd@t:~/app $ readelf -a libMySharedObject.so | grep pow
000b3000  00007416 R_ARM_JUMP_SLOT   00000000   pow@GLIBC_2.29
   116: 00000000     0 FUNC    GLOBAL DEFAULT  UND pow@GLIBC_2.29 (15)
  6483: 00000000     0 FUNC    GLOBAL DEFAULT  UND pow@@GLIBC_2.29

cmd@t:~/app $ patchelf --clear-symbol-version pow libMySharedObject.so --debug
patching ELF file 'libMySharedObject.so'
clearing symbol version for pow
writing libMySharedObject.so

cmd@t:~/app $ readelf -a libMySharedObject.so | grep pow
000b3000  00007416 R_ARM_JUMP_SLOT   00000000   pow
   116: 00000000     0 FUNC    GLOBAL DEFAULT  UND pow
  6483: 00000000     0 FUNC    GLOBAL DEFAULT  UND pow@@GLIBC_2.29

cmd@t:~/app $

Expected behavior

Both symbols should have their version requirement removed, not just the first. Is it perhaps because the second symbol is in .symtab? The one that survives, pow@@GLIBC_2.29 still shows up with, and still seems to be required:

cmd@t:~/app $ ./test
./test: /lib/arm-linux-gnueabihf/libm.so.6: version `GLIBC_2.29' not found (required by ./libMySharedObject.so)

patchelf --version output

patchelf 0.12

Additional context

The binary is a cross compiled binary (host machine was x86_64, target is armv8a. I unfortunately don't have a binary I can share at this time, but may be able to do so in the future.

nitz commented 3 years ago

I had a few moments to dig into the source, and it does look like it's not checking the .symtab section. I thought to add it myself, but I only have a cursory knowledge of ELF in general, and am not sure where the .symtab section stores it's symbol versions. (I'm guessing not .gnu.version, since the size of .gnu.version seems required to match the size of .dynsym?)

Radvendii commented 3 years ago

I'm also having this problem. Did you find a solution / workaround?

nitz commented 3 years ago

I never did. I ended up just building that one particular library on a target set up like my actual target. Not really a great workaround but was enough to let me move forward.

Radvendii commented 3 years ago

Ah, bummer. I'm not sure what the use-case for --clear-symbol-version is that works, given that it's also not documented in the man page (#258). But anyways, I'm exploring other options now. This is kind of an error-prone hack anyways for what we were trying to do.

nitz commented 3 years ago

This is kind of an error-prone hack anyways for what we were trying to do.

Mayyyybe ;) I'm still convinced it probably would have worked if I knew better how to get the other symbol references out. 🤷🏻‍♀️

Radvendii commented 3 years ago

Oh it might have worked for your use-case, if you just wanted a particular binary to work on a particular computer. But it's not very robust; if there's a breaking change to the symbol's ABI, the program wouldn't know to use the right version, and would break on updated computers. That's the whole reason for symbol versioning, no?

Anyways, I managed to make an overlay that uses an older version of GLIBC, so that worked. =)

z16166 commented 1 year ago

1, ".dynsym" is for loader/linker. 2, ".symtab" is for debugger, which can be erased by "strip" command.

so patchelf can be used to deal with glibc symbol version of stripped elf files.