This can happen especially if .gnu.version_r stores the strings in .dynstr, so
replacing the library names would add them twice to the same section. Keep a map
of what was already added and where, and simply reuse the old entries if they
are needed again.
When it happens that the .gnu.version_r stores the strings in .dynstr it can
come to corruption of the library names written into DT_NEEDED:
-the library names in DT_NEEDED are replaced, new entries are written to the end
of .dynstr
-the version library names are replaced, and written to the end of the string
section.
If the section for the version strings is also ".dynstr", the previous
modifications were _not_ taken into account and things were written from the old
end of .dynstr again. The order in which these strings were written is not the
same as the previous replacement, so things would end up with the same size, but
different offsets. The .gnu.version_r table is correct, the file contents are
fine, but the offsets in the DT_NEEDED entries are wrong. Since they are printed
as 0-terminated strings the first one replaced will always be shown correct,
which also is the case if the argument is only used once as the string is
replaced with itself afterwards.
A PT_PHDR corruption was previously reported and fixed in [1]: the issue was
that the VirtAddr field of the PT_PHDR program header would get overwritten
with the file offset of the program header table rather than the virtual
address. A testcase for this was also added in [2]. However, the tescase is not
included in the Makefile.am regression testsuite and also tries to run a x86_64
prebuilt binary unconditionally, which would not work on other architectures.
To fix this, create a standalone testcase for the PT_PHDR VirtAddr field
corruption and include it in Makefile.am. In order to reproduce [1], a binary
with the following characteristics is needed:
- the ELF file type must be ET_DYN
- the ELF file must contain a PT_PHDR program header
- the file offset and the VirtAddr field of the PT_PHDR program header must be
different
[1] https://github.com/NixOS/patchelf/pull/243
[2] 8f94e116f3
Signed-off-by: Ovidiu Panait <ovpanait@gmail.com>
Currently, "make check" fails on Ubuntu 20.04 because the STRIP variable is not
set in the resulting tests/Makefile:
"""
git clone https://github.com/NixOS/patchelf.git
./bootstrap.sh
./configure
make VERBOSE=1 check
...
gcc -fPIC -shared -o libbig-dynstr.so big-dynstr.c
only-keep-debug libbig-dynstr.so -o libbig-dynstr.debug
/bin/bash: only-keep-debug: command not found
make[2]: [Makefile:1526: libbig-dynstr.debug] Error 127 (ignored)
...
FAIL: no-dynamic-section.sh
===========================
patchelf: getting info about 'libbig-dynstr.debug': No such file or directory
FAIL no-dynamic-section.sh (exit status: 1)
"""
strip is used by the regression testsuite, so add a check for it configure.ac.
Signed-off-by: Ovidiu Panait <ovpanait@gmail.com>
The use of self-pointers into a vector<> meant that the vector could not
be relocated, which meant that any growth in the file had to fit within the
inital reservation.
Now, instead of a pointer to a header and a pointer to the contents, those
values are computed dynamically from the underlying vector().