[v1] ld/ELF: Add --image-base command line option to the ELF linker

Message ID kn2fnBHQrpWlZFTsaDdi2GlvOFwQxrALNfyJ08bltUDNw3m7-QBvKzrhtJU1EhsZLF6W2I_jjkC1IicG-lBggPFjBDGHC-tHPe1YB-6W_lM=@protonmail.com
State New
Headers
Series [v1] ld/ELF: Add --image-base command line option to the ELF linker |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed

Commit Message

Hakan Candar Oct. 25, 2024, 1:25 a.m. UTC
  LLD has dropped the option -Ttext-segment for specifying image base
addresses, instead forcing the use of the --image-base option for both
ELF and PE targets. As it stands, GNU LD and LLVM LLD are incompatible,
having two different options for the same functionality.

This patch enables the use of --image-base on ELF targets, advancing
consistency and compatibility.

See: https://reviews.llvm.org/D70468
     https://maskray.me/blog/2020-11-15-explain-gnu-linker-options#address-related
     https://sourceware.org/bugzilla/show_bug.cgi?id=25207

Moreover, a new test has been added to ensure -z separate-code behaviour
when used with -Ttext-segment stays the same. When this combination is
used, -Ttext-segment sets the address of the first segment (R), not the
text segment (RX), and like with -z noseparate-code, no segments lesser
than the specified address are created. If this behaviour was to change,
the first (R) segment of the ELF file would begin in a lesser address
than the specified text (RX) segment, breaking traditional use of this
option for specifying image base address.

ld/
	PR 25207
	* emultempl/pe.em: Remove redeclaration of --image-base.
	* emultempl/pep.em: Ditto.
	* emultempl/beos.em: Ditto.
	* ldlex.h (enum option_values): Move OPTION_IMAGE_BASE.
	* lexsup.c (ld_options): Add --image-base.
	(parse_args): On ELF, make --image-base follow -Ttext-segment behaviour.
	* ld.texi: Document the new option and re-define -Ttext-segment
	with established behaviour.
	* testsuite/ld-elf/pr25207.d: New file.
	* testsuite/ld-elf/pr25207.s: New file.
	* NEWS: Mention the new feature.

Tested on Linux x86-64, for ELF and PE targets.

Signed-off-by: Hakan Candar <hakancandar@protonmail.com>
---
 ld/NEWS                       |  3 +++
 ld/emultempl/beos.em          |  1 -
 ld/emultempl/pe.em            |  1 -
 ld/emultempl/pep.em           |  1 -
 ld/ld.texi                    | 26 ++++++++++++++------------
 ld/ldlex.h                    |  2 +-
 ld/lexsup.c                   |  5 +++++
 ld/testsuite/ld-elf/pr25207.d | 11 +++++++++++
 ld/testsuite/ld-elf/pr25207.s |  8 ++++++++
 9 files changed, 42 insertions(+), 16 deletions(-)
 create mode 100644 ld/testsuite/ld-elf/pr25207.d
 create mode 100644 ld/testsuite/ld-elf/pr25207.s
  

Comments

Alan Modra Oct. 25, 2024, 3:37 a.m. UTC | #1
On Fri, Oct 25, 2024 at 01:25:21AM +0000, hakan wrote:
> LLD has dropped the option -Ttext-segment for specifying image base
> addresses, instead forcing the use of the --image-base option for both
> ELF and PE targets. As it stands, GNU LD and LLVM LLD are incompatible,
> having two different options for the same functionality.
> 
> This patch enables the use of --image-base on ELF targets, advancing
> consistency and compatibility.
> 
> See: https://reviews.llvm.org/D70468
>      https://maskray.me/blog/2020-11-15-explain-gnu-linker-options#address-related
>      https://sourceware.org/bugzilla/show_bug.cgi?id=25207
> 
> Moreover, a new test has been added to ensure -z separate-code behaviour
> when used with -Ttext-segment stays the same. When this combination is
> used, -Ttext-segment sets the address of the first segment (R), not the
> text segment (RX), and like with -z noseparate-code, no segments lesser
> than the specified address are created. If this behaviour was to change,
> the first (R) segment of the ELF file would begin in a lesser address
> than the specified text (RX) segment, breaking traditional use of this
> option for specifying image base address.
> 
> ld/
> 	PR 25207
> 	* emultempl/pe.em: Remove redeclaration of --image-base.
> 	* emultempl/pep.em: Ditto.
> 	* emultempl/beos.em: Ditto.
> 	* ldlex.h (enum option_values): Move OPTION_IMAGE_BASE.
> 	* lexsup.c (ld_options): Add --image-base.
> 	(parse_args): On ELF, make --image-base follow -Ttext-segment behaviour.
> 	* ld.texi: Document the new option and re-define -Ttext-segment
> 	with established behaviour.
> 	* testsuite/ld-elf/pr25207.d: New file.
> 	* testsuite/ld-elf/pr25207.s: New file.
> 	* NEWS: Mention the new feature.
> 
> Tested on Linux x86-64, for ELF and PE targets.

The test needs some tweaking.  Fix these fails then the patch is OK.

arc-linux-uclibc  +FAIL: ld-elf/pr25207
bfin-linux-uclibc  +FAIL: ld-elf/pr25207
h8300-linux-gnu  +FAIL: ld-elf/pr25207
hppa64-linux-gnu  +FAIL: ld-elf/pr25207
metag-linux-gnu  +FAIL: ld-elf/pr25207
mips64-linux-gnuabi64  +FAIL: ld-elf/pr25207
mipsel-linux-gnu  +FAIL: ld-elf/pr25207
mipsisa32el-linux-gnu  +FAIL: ld-elf/pr25207
mips-linux-gnu  +FAIL: ld-elf/pr25207
nds32le-linux-gnu  +FAIL: ld-elf/pr25207
sparc64-linux-gnu  +FAIL: ld-elf/pr25207
  
Hakan Candar Oct. 26, 2024, 12:34 a.m. UTC | #2
Dear Alan Modra,

Sorry for the second mail. I forgot to CC the mailing list.

I am in the process of writing an updated patch, I fixed tests for all
targets except nds32le-linux-gnu, arc-linux-uclibc, and
h8300-linux-gnu.

Only on targets nds32le-linux-gnu and arc-linux-uclibc, the paddr and
vaddr of the data segment is different. I suspect this might be a bug.

Readelf output:
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00120000 0x00110000 0x00094 0x00094 R   0x10000
  LOAD           0x000094 0x00120094 0x00120094 0x00002 0x00002 R E 0x10000
  LOAD           0x000098 0x00130098 0x00130098 0x00000 0x00000 RW  0x10000

Notice how the VirtAddr and PhysAddr of the first segment is different.
This behaviour is always present, regardless if -Ttext-segment was
specified or not.

I can fix the issue by changing the ldscripts of those two targets and
adding `. = ALIGN(CONSTANT (MAXPAGESIZE));` over `.init` for
SEPARATE_CODE, similar to how other targets handle this. After this
is done, these targets behave like other platforms where paddr and
vaddr is the same.

How may I continue? Should I change the test case from
"  LOAD +0x0+ 0x0*120000 0x0*120000 0x[0-9a-f]+ 0x[0-9a-f]+ R   .*"
to
"  LOAD +0x0+ 0x0*120000 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R   .*"
not accounting for the physical address, or should the test stay as is
and a new bug report be opened for this problem?

Further, the h8300-linux-gnu target did not create two different
segments (R) and (RX) when -z separate-code was specified. It acted as
-z noseparate-code. I am thinking of adding this target as xfail.

Best regards,
Hakan

On Friday, 25 October 2024 at 06:37, Alan Modra <amodra@gmail.com> wrote:

> On Fri, Oct 25, 2024 at 01:25:21AM +0000, hakan wrote:
> 
> > LLD has dropped the option -Ttext-segment for specifying image base
> > addresses, instead forcing the use of the --image-base option for both
> > ELF and PE targets. As it stands, GNU LD and LLVM LLD are incompatible,
> > having two different options for the same functionality.
> > 
> > This patch enables the use of --image-base on ELF targets, advancing
> > consistency and compatibility.
> > 
> > See: https://reviews.llvm.org/D70468
> > https://maskray.me/blog/2020-11-15-explain-gnu-linker-options#address-related
> > https://sourceware.org/bugzilla/show_bug.cgi?id=25207
> > 
> > Moreover, a new test has been added to ensure -z separate-code behaviour
> > when used with -Ttext-segment stays the same. When this combination is
> > used, -Ttext-segment sets the address of the first segment (R), not the
> > text segment (RX), and like with -z noseparate-code, no segments lesser
> > than the specified address are created. If this behaviour was to change,
> > the first (R) segment of the ELF file would begin in a lesser address
> > than the specified text (RX) segment, breaking traditional use of this
> > option for specifying image base address.
> > 
> > ld/
> > PR 25207
> > * emultempl/pe.em: Remove redeclaration of --image-base.
> > * emultempl/pep.em: Ditto.
> > * emultempl/beos.em: Ditto.
> > * ldlex.h (enum option_values): Move OPTION_IMAGE_BASE.
> > * lexsup.c (ld_options): Add --image-base.
> > (parse_args): On ELF, make --image-base follow -Ttext-segment behaviour.
> > * ld.texi: Document the new option and re-define -Ttext-segment
> > with established behaviour.
> > * testsuite/ld-elf/pr25207.d: New file.
> > * testsuite/ld-elf/pr25207.s: New file.
> > * NEWS: Mention the new feature.
> > 
> > Tested on Linux x86-64, for ELF and PE targets.
> 
> 
> The test needs some tweaking. Fix these fails then the patch is OK.
> 
> arc-linux-uclibc +FAIL: ld-elf/pr25207
> bfin-linux-uclibc +FAIL: ld-elf/pr25207
> h8300-linux-gnu +FAIL: ld-elf/pr25207
> hppa64-linux-gnu +FAIL: ld-elf/pr25207
> metag-linux-gnu +FAIL: ld-elf/pr25207
> mips64-linux-gnuabi64 +FAIL: ld-elf/pr25207
> mipsel-linux-gnu +FAIL: ld-elf/pr25207
> mipsisa32el-linux-gnu +FAIL: ld-elf/pr25207
> mips-linux-gnu +FAIL: ld-elf/pr25207
> nds32le-linux-gnu +FAIL: ld-elf/pr25207
> sparc64-linux-gnu +FAIL: ld-elf/pr25207
> 
> --
> Alan Modra
  
Alan Modra Oct. 28, 2024, 12:48 a.m. UTC | #3
On Sat, Oct 26, 2024 at 12:34:12AM +0000, Hakan Candar wrote:
> I am in the process of writing an updated patch, I fixed tests for all
> targets except nds32le-linux-gnu, arc-linux-uclibc, and
> h8300-linux-gnu.
> 
> Only on targets nds32le-linux-gnu and arc-linux-uclibc, the paddr and
> vaddr of the data segment is different. I suspect this might be a bug.
> 
> Readelf output:
> Program Headers:
>   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>   LOAD           0x000000 0x00120000 0x00110000 0x00094 0x00094 R   0x10000
>   LOAD           0x000094 0x00120094 0x00120094 0x00002 0x00002 R E 0x10000
>   LOAD           0x000098 0x00130098 0x00130098 0x00000 0x00000 RW  0x10000
> 
> Notice how the VirtAddr and PhysAddr of the first segment is different.
> This behaviour is always present, regardless if -Ttext-segment was
> specified or not.
> 
> I can fix the issue by changing the ldscripts of those two targets and
> adding `. = ALIGN(CONSTANT (MAXPAGESIZE));` over `.init` for
> SEPARATE_CODE, similar to how other targets handle this. After this
> is done, these targets behave like other platforms where paddr and
> vaddr is the same.
> 
> How may I continue? Should I change the test case from

Thanks for looking at the test results.  I just looked at one or two
FAILs and saw you had some easy fixes to make.  I'm OK with you
leaving these three target FAILs as they are, for someone to fix
later.

> "  LOAD +0x0+ 0x0*120000 0x0*120000 0x[0-9a-f]+ 0x[0-9a-f]+ R   .*"
> to
> "  LOAD +0x0+ 0x0*120000 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R   .*"
> not accounting for the physical address, or should the test stay as is
> and a new bug report be opened for this problem?
> 
> Further, the h8300-linux-gnu target did not create two different
> segments (R) and (RX) when -z separate-code was specified. It acted as
> -z noseparate-code. I am thinking of adding this target as xfail.
> 
> Best regards,
> Hakan
> 
> On Friday, 25 October 2024 at 06:37, Alan Modra <amodra@gmail.com> wrote:
> 
> > On Fri, Oct 25, 2024 at 01:25:21AM +0000, hakan wrote:
> > 
> > > LLD has dropped the option -Ttext-segment for specifying image base
> > > addresses, instead forcing the use of the --image-base option for both
> > > ELF and PE targets. As it stands, GNU LD and LLVM LLD are incompatible,
> > > having two different options for the same functionality.
> > > 
> > > This patch enables the use of --image-base on ELF targets, advancing
> > > consistency and compatibility.
> > > 
> > > See: https://reviews.llvm.org/D70468
> > > https://maskray.me/blog/2020-11-15-explain-gnu-linker-options#address-related
> > > https://sourceware.org/bugzilla/show_bug.cgi?id=25207
> > > 
> > > Moreover, a new test has been added to ensure -z separate-code behaviour
> > > when used with -Ttext-segment stays the same. When this combination is
> > > used, -Ttext-segment sets the address of the first segment (R), not the
> > > text segment (RX), and like with -z noseparate-code, no segments lesser
> > > than the specified address are created. If this behaviour was to change,
> > > the first (R) segment of the ELF file would begin in a lesser address
> > > than the specified text (RX) segment, breaking traditional use of this
> > > option for specifying image base address.
> > > 
> > > ld/
> > > PR 25207
> > > * emultempl/pe.em: Remove redeclaration of --image-base.
> > > * emultempl/pep.em: Ditto.
> > > * emultempl/beos.em: Ditto.
> > > * ldlex.h (enum option_values): Move OPTION_IMAGE_BASE.
> > > * lexsup.c (ld_options): Add --image-base.
> > > (parse_args): On ELF, make --image-base follow -Ttext-segment behaviour.
> > > * ld.texi: Document the new option and re-define -Ttext-segment
> > > with established behaviour.
> > > * testsuite/ld-elf/pr25207.d: New file.
> > > * testsuite/ld-elf/pr25207.s: New file.
> > > * NEWS: Mention the new feature.
> > > 
> > > Tested on Linux x86-64, for ELF and PE targets.
> > 
> > 
> > The test needs some tweaking. Fix these fails then the patch is OK.
> > 
> > arc-linux-uclibc +FAIL: ld-elf/pr25207
> > bfin-linux-uclibc +FAIL: ld-elf/pr25207
> > h8300-linux-gnu +FAIL: ld-elf/pr25207
> > hppa64-linux-gnu +FAIL: ld-elf/pr25207
> > metag-linux-gnu +FAIL: ld-elf/pr25207
> > mips64-linux-gnuabi64 +FAIL: ld-elf/pr25207
> > mipsel-linux-gnu +FAIL: ld-elf/pr25207
> > mipsisa32el-linux-gnu +FAIL: ld-elf/pr25207
> > mips-linux-gnu +FAIL: ld-elf/pr25207
> > nds32le-linux-gnu +FAIL: ld-elf/pr25207
> > sparc64-linux-gnu +FAIL: ld-elf/pr25207
> > 
> > --
> > Alan Modra
  

Patch

diff --git a/ld/NEWS b/ld/NEWS
index 1f14dd6bc77..f7de85bd3ce 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -2,6 +2,9 @@ 
 
 Changes in 2.44:
 
+* Add --image-base=<ADDR> option to the ELF linker to behave the same
+  as -Ttext-segment for compatibility with LLD.
+
 * Add a "--build-id=xx" option, if built with the xxhash library.  This
   produces a 128-bit hash, 2-4x faster than md5 or sha1.
 
diff --git a/ld/emultempl/beos.em b/ld/emultempl/beos.em
index 29c386c61f8..54d03537de6 100644
--- a/ld/emultempl/beos.em
+++ b/ld/emultempl/beos.em
@@ -82,7 +82,6 @@  gld${EMULATION_NAME}_add_options
     {"dll", no_argument, NULL, OPTION_DLL},
     {"file-alignment", required_argument, NULL, OPTION_FILE_ALIGNMENT},
     {"heap", required_argument, NULL, OPTION_HEAP},
-    {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
     {"major-image-version", required_argument, NULL, OPTION_MAJOR_IMAGE_VERSION},
     {"major-os-version", required_argument, NULL, OPTION_MAJOR_OS_VERSION},
     {"major-subsystem-version", required_argument, NULL, OPTION_MAJOR_SUBSYSTEM_VERSION},
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index 9ab5e6ef481..869ffd3f623 100644
--- a/ld/emultempl/pe.em
+++ b/ld/emultempl/pe.em
@@ -251,7 +251,6 @@  gld${EMULATION_NAME}_add_options
     {"dll", no_argument, NULL, OPTION_DLL},
     {"file-alignment", required_argument, NULL, OPTION_FILE_ALIGNMENT},
     {"heap", required_argument, NULL, OPTION_HEAP},
-    {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
     {"major-image-version", required_argument, NULL, OPTION_MAJOR_IMAGE_VERSION},
     {"major-os-version", required_argument, NULL, OPTION_MAJOR_OS_VERSION},
     {"major-subsystem-version", required_argument, NULL, OPTION_MAJOR_SUBSYSTEM_VERSION},
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index 00c4ea9e15a..c225d052fb8 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -261,7 +261,6 @@  gld${EMULATION_NAME}_add_options
     {"dll", no_argument, NULL, OPTION_DLL},
     {"file-alignment", required_argument, NULL, OPTION_FILE_ALIGNMENT},
     {"heap", required_argument, NULL, OPTION_HEAP},
-    {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
     {"major-image-version", required_argument, NULL, OPTION_MAJOR_IMAGE_VERSION},
     {"major-os-version", required_argument, NULL, OPTION_MAJOR_OS_VERSION},
     {"major-subsystem-version", required_argument, NULL, OPTION_MAJOR_SUBSYSTEM_VERSION},
diff --git a/ld/ld.texi b/ld/ld.texi
index 90182c436ec..17ad4048796 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -2732,6 +2732,19 @@  for compatibility with other linkers, you may omit the leading
 should be no white space between @var{sectionname}, the equals
 sign (``@key{=}''), and @var{org}.
 
+@kindex --image-base=@var{org}
+@item --image-base=@var{org}
+@cindex image base address, cmd line
+When using ELF, same as @option{-Ttext-segment}, with both options effectively
+setting the base address of the ELF executable.
+
+When using PE, use @var{value} as the base address of your program or dll.
+This is the lowest memory location that will be used when your program or
+dll is loaded.  To reduce the need to relocate and improve performance of
+your dlls, each should have a unique base address and not overlap any
+other dlls.  The default is 0x400000 for executables, and 0x10000000
+for dlls.
+
 @kindex -Tbss=@var{org}
 @kindex -Tdata=@var{org}
 @kindex -Ttext=@var{org}
@@ -2746,7 +2759,7 @@  Same as @option{--section-start}, with @code{.bss}, @code{.data} or
 @item -Ttext-segment=@var{org}
 @cindex text segment origin, cmd line
 When creating an ELF executable, it will set the address of the first
-byte of the text segment.  Note that when @option{-pie} is used with
+byte of the first segment.  Note that when @option{-pie} is used with
 @option{-Ttext-segment=@var{org}}, the output executable is marked
 ET_EXEC so that the address of the first byte of the text segment will
 be guaranteed to be @var{org} at run time.
@@ -3392,17 +3405,6 @@  to be used as heap for this program.  The default is 1MB reserved, 4K
 committed.
 [This option is specific to the i386 PE targeted port of the linker]
 
-@cindex image base
-@kindex --image-base
-@item --image-base @var{value}
-Use @var{value} as the base address of your program or dll.  This is
-the lowest memory location that will be used when your program or dll
-is loaded.  To reduce the need to relocate and improve performance of
-your dlls, each should have a unique base address and not overlap any
-other dlls.  The default is 0x400000 for executables, and 0x10000000
-for dlls.
-[This option is specific to the i386 PE targeted port of the linker]
-
 @kindex --kill-at
 @item --kill-at
 If given, the stdcall suffixes (@@@var{nn}) will be stripped from
diff --git a/ld/ldlex.h b/ld/ldlex.h
index defe3fcbbb9..bb431101fb2 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -67,6 +67,7 @@  enum option_values
   OPTION_SYMBOLIC,
   OPTION_SYMBOLIC_FUNCTIONS,
   OPTION_TASK_LINK,
+  OPTION_IMAGE_BASE,
   OPTION_TBSS,
   OPTION_TDATA,
   OPTION_TTEXT,
@@ -325,7 +326,6 @@  enum option_values
   /* Used by emultempl/pe.em, emultempl/pep.em and emultempl/beos.em.  */
   OPTION_DLL,
   OPTION_FILE_ALIGNMENT,
-  OPTION_IMAGE_BASE,
   OPTION_MAJOR_IMAGE_VERSION,
   OPTION_MAJOR_OS_VERSION,
   OPTION_MAJOR_SUBSYSTEM_VERSION,
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 92a12fe19af..bc3ee9d3691 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -510,6 +510,8 @@  static const struct ld_option ld_options[] =
   { {"section-start", required_argument, NULL, OPTION_SECTION_START},
     '\0', N_("SECTION=ADDRESS"), N_("Set address of named section"),
     TWO_DASHES },
+  { {"image-base", required_argument, NULL, OPTION_IMAGE_BASE},
+    '\0', N_("ADDRESS"), N_("Set image base address"), TWO_DASHES },
   { {"Tbss", required_argument, NULL, OPTION_TBSS},
     '\0', N_("ADDRESS"), N_("Set address of .bss section"), ONE_DASH },
   { {"Tdata", required_argument, NULL, OPTION_TDATA},
@@ -1478,6 +1480,9 @@  parse_args (unsigned argc, char **argv)
 	case OPTION_TTEXT:
 	  set_segment_start (".text", optarg);
 	  break;
+	case OPTION_IMAGE_BASE:
+	  /* Unless PE, --image-base and -Ttext-segment behavior is the same
+	     PE-specific functionality is implemented in emultempl/{pe, pep, beos}.em  */
 	case OPTION_TTEXT_SEGMENT:
 	  set_segment_start (".text-segment", optarg);
 	  break;
diff --git a/ld/testsuite/ld-elf/pr25207.d b/ld/testsuite/ld-elf/pr25207.d
new file mode 100644
index 00000000000..6b9965ab591
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr25207.d
@@ -0,0 +1,11 @@ 
+#source: pr25207.s
+#ld: -z separate-code -Ttext-segment=0x120000
+#readelf: -l --wide
+#target: *-*-linux* *-*-gnu* arm*-*-uclinuxfdpiceabi
+# changing -Ttext-segment behaviour will break --image-base (pr25207)
+# -Ttext-segment=<ADDR> should set the first segment address,
+# not necessarily the first executable segment.
+
+#...
+  LOAD +0x0+ 0x0*120000 0x0*120000 0x0*[0-9a-f][0-9a-f][0-9a-f] 0x0*[0-9a-f][0-9a-f][0-9a-f] R   .*
+#pass
diff --git a/ld/testsuite/ld-elf/pr25207.s b/ld/testsuite/ld-elf/pr25207.s
new file mode 100644
index 00000000000..ffa11bbc550
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr25207.s
@@ -0,0 +1,8 @@ 
+        .section .text, "ax"
+	.globl  _start
+_start:
+	.space 1
+
+	.section .rodata
+	.globl	foo
+foo:	.space 1