elf: Fix localplt.awk for DT_RELR-enabled builds (BZ 31978)

For each input readelf output, localplt.awk parses each 'Relocation
section' entry, checks its offset against the dynamic section entry, and
saves each DT_JMPREL, DT_RELA, and DT_REL offset value it finds. After
all lines are read, the script checks if any segment offset differed
from 0, meaning at least one 'Relocation section' was matched.

However, if the shared object was built with RELR support and the static
linker could place all the relocation on DT_RELR, there would be no
DT_JMPREL, DT_RELA, and DT_REL entries; only a DT_RELR.

For the current three ABIs that support (aarch64, x86, and powerpc64),
the powerpc64 ld.so shows the behavior above. Both x86_64 and aarch64
show extra relocations on '.rela.dyn', which makes the script check to
succeed.

This patch fixes by handling DT_RELR, where the offset is checked
against the dynamic section entries and if the shared object contains an
entry it means that there are no extra PLT entries (since all
relocations are relative).

It fixes the elf/check-localplt failure on powerpc.

Checked with a build/check for aarch64-linux-gnu, x86_64-linux-gnu,
i686-linux-gnu, arm-linux-gnueabihf, s390x-linux-gnu, powerpc-linux-gnu,
powerpc64-linux-gnu, and powerpc64le-linux-gnu.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
Adhemerval Zanella 2024-07-16 07:57:45 -03:00 committed by Andreas K. Hüttel
parent 6b7e2e1d61
commit 4f047d9ede
No known key found for this signature in database
GPG Key ID: DC2B16215ED5412A

View File

@ -10,7 +10,8 @@ BEGIN {
} }
FILENAME != lastfile { FILENAME != lastfile {
if (lastfile && jmprel_offset == 0 && rela_offset == 0 && rel_offset == 0) { if (lastfile && jmprel_offset == 0 && rela_offset == 0 && rel_offset == 0 \
&& relr_offset == 0) {
print FILENAME ": *** failed to find expected output (readelf -WSdr)"; print FILENAME ": *** failed to find expected output (readelf -WSdr)";
result = 2; result = 2;
} }
@ -22,6 +23,7 @@ FILENAME != lastfile {
jmprel_offset = 0; jmprel_offset = 0;
rela_offset = 0; rela_offset = 0;
rel_offset = 0; rel_offset = 0;
relr_offset = 0;
pltrelsz = -1; pltrelsz = -1;
delete section_offset_by_address; delete section_offset_by_address;
} }
@ -77,6 +79,8 @@ in_relocs && relocs_offset == rel_offset && NF >= 5 {
} }
} }
# No need to handle DT_RELR (all packed relocations are relative).
in_relocs { next } in_relocs { next }
$1 == "Relocation" && $2 == "section" && $5 == "offset" { $1 == "Relocation" && $2 == "section" && $5 == "offset" {
@ -121,4 +125,14 @@ $2 == "(REL)" {
} }
next next
} }
$2 == "(RELR)" {
relr_addr = strtonum($3);
if (relr_addr in section_offset_by_address) {
relr_offset = section_offset_by_address[relr_addr];
} else {
print FILENAME ": *** DT_RELR does not match any section's address";
result = 2;
}
}
END { exit(result) } END { exit(result) }