Fix ld bloat introduced between binutils-2.38 and 2.39

Message ID 20230102160857.ABA7F2042C@pchp3.se.axis.com
State Accepted
Headers
Series Fix ld bloat introduced between binutils-2.38 and 2.39 |

Checks

Context Check Description
snail/binutils-gdb-check success Github commit url

Commit Message

Hans-Peter Nilsson Jan. 2, 2023, 4:08 p.m. UTC
  (Subject is for email list use, see below for a better
commit title.)

Ok to commit?  If so, binutils-2.39 and 2.40 branches too?
If not, suggestion of other approaches, no later than
configure-time?

--- 8< ---
Subject: Let --with-elf-maxpagesize=N override target ELF_MAXPAGESIZE

Since commit 9833b7757d24, "PR28824, relro security issues",
ELF_MAXPAGESIZE matters much more, with regards to layout of
the linked file.  That commit fixed an actual bug, but also
exposes a problem for targets were that value is too high.

For example, for ARM(32, a.k.a. "Aarch32") specifically
bfd_arch_arm, it's set to 64 KiB, making all Linux(/GNU)
targets pay an extra amount of up to 60 KiB of bloat in
DSO:s and executables.  This matters when there are many
such files, and where storage is expensive.

It's *mostly* bloat when using a Linux kernel, as ARM(32) is
a good example of an target where ELF_MAXPAGESIZE is set to
an extreme value for an obscure corner-case.  The ARM
(32-bit) kernel has 4 KiB pages, has had that value forever,
and can't be configured to any other value.  The use-case is
IIUC "Aarch32" emulation on an "Aarch64" (arm64) kernel, but
not just that, but a setup where the Linux page-size is
configured to something other than the *default* 4 KiB.  Not
sure there actually any such systems in use, again with
both Aarch32 compatibility support and a non-4KiB pagesize,
with all the warnings in the kernel config and requiring the
"EXPERT" level set on.

That may sound like an argument for setting the bfd_arch_arm
ELF_MAXPAGESIZE to 4 KiB, but then the obscure corner-case
wouldn't be properly handled.  I wouldn't oppose that, but I
prefer not to regress the linker by default in my own patch.
I know about the linker option "-z max-page-size=0x1000",
but that requires finding every linker invocation or
patching gcc -and still finding all stray naked ld calls.

There was for a short while config.relro_use_commonpagesize
in the linker (commit 31b4d3a16f20) but besides the
self-explanatory ld_config_type member, IMHO it's too
obscure to re-introduce.

Instead, I suggest simply making ELF_MAXPAGESIZE generally
overridable by means of a --with option at linker
configuration time.  In the patch I make the option
ELF-specific mostly for simplicity (more object-formats
means more places to find and patch, also the original
problem is ELF-specific).

bfd:
	Let --with-elf-maxpagesize=N override target ELF_MAXPAGESIZE.
	* configure.ac: Define FORCED_ELF_MAXPAGESIZE if
	--with-elf-maxpagesize=N is passed.
	* elfxx-target.h: Let FORCED_ELF_MAXPAGESIZE] override ELF_MAXPAGESIZE.
	* configure, config.in: Regenerate.
---
 bfd/config.in      |  3 +++
 bfd/configure      | 22 ++++++++++++++++++++--
 bfd/configure.ac   | 10 ++++++++++
 bfd/elfxx-target.h |  5 +++++
 4 files changed, 38 insertions(+), 2 deletions(-)
  

Comments

Alan Modra Jan. 3, 2023, 1:35 a.m. UTC | #1
On Mon, Jan 02, 2023 at 05:08:57PM +0100, Hans-Peter Nilsson via Binutils wrote:
> That may sound like an argument for setting the bfd_arch_arm
> ELF_MAXPAGESIZE to 4 KiB, but then the obscure corner-case
> wouldn't be properly handled.

Agreed.  It's what x86 did when facing the same thing.  If anybody
cares about the obscure corner-case you identify then they can just
use -z max-page-size.  Or edit elf32-arm.c.

> Instead, I suggest simply making ELF_MAXPAGESIZE generally
> overridable by means of a --with option at linker
> configuration time.

I dislike configure time options that affect linker behaviour, but I
realise I'm flogging a dead horse since we already have a lot of them.
However, this particular option is worse than most since it affects
all ELF targets.  That can't be correct or useful with
--enable-targets=all.
  

Patch

diff --git a/bfd/configure.ac b/bfd/configure.ac
index 82a3d1f832e7..88eaa52b5a82 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -115,6 +115,16 @@  AC_ARG_WITH(mmap,
   *)    AC_MSG_ERROR(bad value ${withval} for BFD with-mmap option) ;;
 esac],[want_mmap=false])dnl
 
+ac_default_elf_maxpagesize=unset
+AC_ARG_WITH(elf_maxpagesize,
+  AS_HELP_STRING([--with-elf-maxpagesize=N],
+    [Set ELF_MAXPAGESIZE to N instead of using the target value]),
+[ac_default_elf_maxpagesize=$withval]) dnl
+if test ${ac_default_elf_maxpagesize} != unset; then
+  AC_DEFINE_UNQUOTED(FORCED_ELF_MAXPAGESIZE, ${ac_default_elf_maxpagesize},
+    [Define to a value with which to override the target ELF_MAXPAGESIZE.])
+fi
+
 AC_ARG_ENABLE(secureplt,
 [  --enable-secureplt      Default to creating read-only plt entries],
 [case "${enableval}" in
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 9bcbdfb27dd8..2a32b8a8cb0d 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -374,6 +374,11 @@ 
 #define ELF_OSABI ELFOSABI_NONE
 #endif
 
+#ifdef FORCED_ELF_MAXPAGESIZE
+#undef ELF_MAXPAGESIZE
+#define ELF_MAXPAGESIZE FORCED_ELF_MAXPAGESIZE
+#endif
+
 #ifndef ELF_MAXPAGESIZE
 # error ELF_MAXPAGESIZE is not defined
 #define ELF_MAXPAGESIZE 1