mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00:00
4f047d9ede
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>
139 lines
3.6 KiB
Awk
139 lines
3.6 KiB
Awk
# This awk script expects to get command-line files that are each
|
|
# the output of 'readelf -WSdr' on a single shared object, and named
|
|
# .../NAME.jmprel where NAME is the unadorned file name of the shared object.
|
|
# It writes "NAME: SYMBOL" for each PLT entry in NAME that refers to a
|
|
# symbol defined in the same object.
|
|
|
|
BEGIN {
|
|
result = 0;
|
|
pltrelsize = -1;
|
|
}
|
|
|
|
FILENAME != lastfile {
|
|
if (lastfile && jmprel_offset == 0 && rela_offset == 0 && rel_offset == 0 \
|
|
&& relr_offset == 0) {
|
|
print FILENAME ": *** failed to find expected output (readelf -WSdr)";
|
|
result = 2;
|
|
}
|
|
if (pltrelsz > 0 && jmprel_offset == -1) {
|
|
print FILENAME ": Could not find section for DT_JMPREL";
|
|
result = 2;
|
|
}
|
|
lastfile = FILENAME;
|
|
jmprel_offset = 0;
|
|
rela_offset = 0;
|
|
rel_offset = 0;
|
|
relr_offset = 0;
|
|
pltrelsz = -1;
|
|
delete section_offset_by_address;
|
|
}
|
|
|
|
/^Section Headers:/ { in_shdrs = 1; next }
|
|
in_shdrs && !/^ +\[/ { in_shdrs = 0 }
|
|
|
|
in_shdrs && /^ +\[/ { sub(/\[ +/, "[") }
|
|
in_shdrs {
|
|
address = strtonum("0x" $4);
|
|
offset = strtonum("0x" $5);
|
|
section_offset_by_address[address] = offset;
|
|
}
|
|
|
|
in_shdrs { next }
|
|
|
|
$1 == "Offset" && $2 == "Info" { in_relocs = 1; next }
|
|
NF == 0 { in_relocs = 0 }
|
|
|
|
in_relocs && relocs_offset == jmprel_offset && NF >= 5 {
|
|
# Relocations against GNU_IFUNC symbols are not shown as an hexadecimal
|
|
# value, but rather as the resolver symbol followed by ().
|
|
if ($4 ~ /\(\)/) {
|
|
print whatfile, gensub(/@.*/, "", "g", $5)
|
|
} else {
|
|
symval = strtonum("0x" $4);
|
|
if (symval != 0)
|
|
print whatfile, gensub(/@.*/, "", "g", $5)
|
|
}
|
|
}
|
|
|
|
in_relocs && relocs_offset == rela_offset && NF >= 5 {
|
|
# Relocations against GNU_IFUNC symbols are not shown as an hexadecimal
|
|
# value, but rather as the resolver symbol followed by ().
|
|
if ($4 ~ /\(\)/) {
|
|
print whatfile, gensub(/@.*/, "", "g", $5), "RELA", $3
|
|
} else {
|
|
symval = strtonum("0x" $4);
|
|
if (symval != 0)
|
|
print whatfile, gensub(/@.*/, "", "g", $5), "RELA", $3
|
|
}
|
|
}
|
|
|
|
in_relocs && relocs_offset == rel_offset && NF >= 5 {
|
|
# Relocations against GNU_IFUNC symbols are not shown as an hexadecimal
|
|
# value, but rather as the resolver symbol followed by ().
|
|
if ($4 ~ /\(\)/) {
|
|
print whatfile, gensub(/@.*/, "", "g", $5), "REL", $3
|
|
} else {
|
|
symval = strtonum("0x" $4);
|
|
if (symval != 0)
|
|
print whatfile, gensub(/@.*/, "", "g", $5), "REL", $3
|
|
}
|
|
}
|
|
|
|
# No need to handle DT_RELR (all packed relocations are relative).
|
|
|
|
in_relocs { next }
|
|
|
|
$1 == "Relocation" && $2 == "section" && $5 == "offset" {
|
|
relocs_offset = strtonum($6);
|
|
whatfile = gensub(/^.*\/([^/]+)\.jmprel$/, "\\1:", 1, FILENAME);
|
|
next
|
|
}
|
|
|
|
$2 == "(JMPREL)" {
|
|
jmprel_addr = strtonum($3);
|
|
if (jmprel_addr in section_offset_by_address) {
|
|
jmprel_offset = section_offset_by_address[jmprel_addr];
|
|
} else {
|
|
jmprel_offset = -1
|
|
}
|
|
next
|
|
}
|
|
|
|
$2 == "(PLTRELSZ)" {
|
|
pltrelsz = strtonum($3);
|
|
next
|
|
}
|
|
|
|
$2 == "(RELA)" {
|
|
rela_addr = strtonum($3);
|
|
if (rela_addr in section_offset_by_address) {
|
|
rela_offset = section_offset_by_address[rela_addr];
|
|
} else {
|
|
print FILENAME ": *** DT_RELA does not match any section's address";
|
|
result = 2;
|
|
}
|
|
next
|
|
}
|
|
|
|
$2 == "(REL)" {
|
|
rel_addr = strtonum($3);
|
|
if (rel_addr in section_offset_by_address) {
|
|
rel_offset = section_offset_by_address[rel_addr];
|
|
} else {
|
|
print FILENAME ": *** DT_REL does not match any section's address";
|
|
result = 2;
|
|
}
|
|
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) }
|