diff mbox series

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

Message ID 20240716105753.524866-1-adhemerval.zanella@linaro.org
State Accepted
Commit 4f047d9edecb1a9b796a9a904dcd42bd3cc3d3b6
Headers show
Series [v2] elf: Fix localplt.awk for DT_RELR-enabled builds (BZ 31978) | expand

Commit Message

Adhemerval Zanella Netto July 16, 2024, 10:57 a.m. UTC
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.
---
 scripts/localplt.awk | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

Comments

Adhemerval Zanella Netto July 18, 2024, 12:17 p.m. UTC | #1
Ping, I think we should fix it for 2.40.

On 16/07/24 07:57, Adhemerval Zanella wrote:
> 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.
> ---
>  scripts/localplt.awk | 16 +++++++++++++++-
>  1 file changed, 15 insertions(+), 1 deletion(-)
> 
> diff --git a/scripts/localplt.awk b/scripts/localplt.awk
> index fe79ca01ab..621ae7d8e8 100644
> --- a/scripts/localplt.awk
> +++ b/scripts/localplt.awk
> @@ -10,7 +10,8 @@ BEGIN {
>  }
>  
>  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)";
>      result = 2;
>    }
> @@ -22,6 +23,7 @@ FILENAME != lastfile {
>    jmprel_offset = 0;
>    rela_offset = 0;
>    rel_offset = 0;
> +  relr_offset = 0;
>    pltrelsz = -1;
>    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 }
>  
>  $1 == "Relocation" && $2 == "section" && $5 == "offset" {
> @@ -121,4 +125,14 @@ $2 == "(REL)" {
>    }
>    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) }
Andreas K. Huettel July 18, 2024, 12:24 p.m. UTC | #2
Yes, OK with someone's R-B

Am Donnerstag, 18. Juli 2024, 14:17:11 CEST schrieb Adhemerval Zanella Netto:
> Ping, I think we should fix it for 2.40.
> 
> On 16/07/24 07:57, Adhemerval Zanella wrote:
> > 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.
> > ---
> >  scripts/localplt.awk | 16 +++++++++++++++-
> >  1 file changed, 15 insertions(+), 1 deletion(-)
> > 
> > diff --git a/scripts/localplt.awk b/scripts/localplt.awk
> > index fe79ca01ab..621ae7d8e8 100644
> > --- a/scripts/localplt.awk
> > +++ b/scripts/localplt.awk
> > @@ -10,7 +10,8 @@ BEGIN {
> >  }
> >  
> >  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)";
> >      result = 2;
> >    }
> > @@ -22,6 +23,7 @@ FILENAME != lastfile {
> >    jmprel_offset = 0;
> >    rela_offset = 0;
> >    rel_offset = 0;
> > +  relr_offset = 0;
> >    pltrelsz = -1;
> >    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 }
> >  
> >  $1 == "Relocation" && $2 == "section" && $5 == "offset" {
> > @@ -121,4 +125,14 @@ $2 == "(REL)" {
> >    }
> >    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) }
>
Carlos O'Donell July 19, 2024, 8:35 p.m. UTC | #3
On 7/16/24 6:57 AM, Adhemerval Zanella wrote:
> 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.

Agreed, as is the case in ppc64le today.

> 
> 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.

LGTM. Nice to add full DT_RELR support for this.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> ---
>  scripts/localplt.awk | 16 +++++++++++++++-
>  1 file changed, 15 insertions(+), 1 deletion(-)
> 
> diff --git a/scripts/localplt.awk b/scripts/localplt.awk
> index fe79ca01ab..621ae7d8e8 100644
> --- a/scripts/localplt.awk
> +++ b/scripts/localplt.awk
> @@ -10,7 +10,8 @@ BEGIN {
>  }
>  
>  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) {

OK. All of the *_offset variable must be zero to trigger the failure, which
would mean we didn't find any of them. Any one of them being non-zero is good
enough.

>      print FILENAME ": *** failed to find expected output (readelf -WSdr)";
>      result = 2;
>    }
> @@ -22,6 +23,7 @@ FILENAME != lastfile {
>    jmprel_offset = 0;
>    rela_offset = 0;
>    rel_offset = 0;
> +  relr_offset = 0;

OK. Set relr_offset to zero.

>    pltrelsz = -1;
>    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).


OK.

> +
>  in_relocs { next }
>  
>  $1 == "Relocation" && $2 == "section" && $5 == "offset" {
> @@ -121,4 +125,14 @@ $2 == "(REL)" {
>    }
>    next
>  }
> +
> +$2 == "(RELR)" {

OK. Matches binutils/readelf.c "RELR" output for DT_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;
> +  }

OK.

> +}
>  END { exit(result) }
Andreas K. Huettel July 19, 2024, 9:04 p.m. UTC | #4
Am Freitag, 19. Juli 2024, 22:35:41 MESZ schrieb Carlos O'Donell:
> On 7/16/24 6:57 AM, Adhemerval Zanella wrote:
> > 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.
> 
> Agreed, as is the case in ppc64le today.
> 
> > 
> > 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.
> 
> LGTM. Nice to add full DT_RELR support for this.
> 
> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
> 

And pushed.
diff mbox series

Patch

diff --git a/scripts/localplt.awk b/scripts/localplt.awk
index fe79ca01ab..621ae7d8e8 100644
--- a/scripts/localplt.awk
+++ b/scripts/localplt.awk
@@ -10,7 +10,8 @@  BEGIN {
 }
 
 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)";
     result = 2;
   }
@@ -22,6 +23,7 @@  FILENAME != lastfile {
   jmprel_offset = 0;
   rela_offset = 0;
   rel_offset = 0;
+  relr_offset = 0;
   pltrelsz = -1;
   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 }
 
 $1 == "Relocation" && $2 == "section" && $5 == "offset" {
@@ -121,4 +125,14 @@  $2 == "(REL)" {
   }
   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) }