This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH RFC v3] Add support for non-contiguous memory regions
- From: Christophe Lyon <christophe dot lyon at linaro dot org>
- To: binutils <binutils at sourceware dot org>
- Date: Mon, 3 Feb 2020 11:08:37 +0100
- Subject: [PATCH RFC v3] Add support for non-contiguous memory regions
Hi,
This is a follow-up to
https://sourceware.org/ml/binutils/2019-11/msg00402.html
and
https://sourceware.org/ml/binutils/2020-01/msg00064.html
The changes between v2 and v3:
* added some doc/NEWS
* fixed bugs detected when running the testsuite with the option
activated by default. In particular, I've noticed and documented the
incompatibility with INSERT (or rather, it's likely to cause problems,
but depends on the actual linker scripts contents), because my new
option breaks the assumption of the parsing & processing order assumed
by INSERT.
* added new option --enable-non-contiguous-regions-warnings which
activates some warnings to help understand why the behaviour changes
in some cases
We'd still have to do modify target that has XXX_build_one_stub(), in
a way similar to what I did in elf32-arm.c.
What is the recommended way of early-exiting the linker when a problem
is detected? I'm using abort(), but that's not very nice and implies
that there's a bug in the linker code. I'm more willing to report
unsupported cases in a friendly way.
There are 4 patches, to hopefully make review/comments easier; I can
squash them at commit time if this is preferable.
* patch1: is the main (code) patch
* patch2: generic test
* patch3: arm tests
* patch4: powerpc test
Thoughts?
Thanks,
Christophe
From 01087e85dc598ce34db800f217ac206bc2d8075e Mon Sep 17 00:00:00 2001
From: Christophe Lyon <christophe.lyon@linaro.org>
Date: Mon, 25 Nov 2019 08:55:37 +0000
Subject: [PATCH 1/4] Add support for non-contiguous memory regions
2020-01-06 Christophe Lyon <christophe.lyon@linaro.org>
bfd/
* bfd-in2.h: Regenerate.
* section.c (asection): Add already_assigned field.
(BFD_FAKE_SECTION): Add default initializer for it.
* ecoff.c (bfd_debug_section): Initialize already_assigned field.
* elf32-arm.c (arm_build_one_stub): Add support for
non_contiguous_regions.
* elflink.c (elf_link_input_bfd): Likewise.
* emultempl/armelf.em (elf32_arm_add_stub_section): Add
SEC_LINKER_CREATED flag.
include/
* bfdlink.h (bfd_link_info): Add non_contiguous_regions and
non_contiguous_regions_warnings fields.
ld/
* ldlang.c (lang_add_section): Add support for
non_contiguous_regions.
(size_input_section): Likewise.
(lang_size_sections_1): Likewise.
(process_insert_statements): Likewise.
* ldlex.h (option_values): Add OPTION_NON_CONTIGUOUS_REGIONS and
OPTION_NON_CONTIGUOUS_REGIONS_WARNINGS.
* lexsup.c (ld_options): Add entries for
--enable-non-contiguous-regions and
--enable-non-contiguous-regions-warnings.
(parse_args): Handle it.
* (NEWS): Add --enable-non-contiguous-regions and
--enable-non-contiguous-regions-warnings.
* ld.texi: Add --enable-non-contiguous-regions and
--enable-non-contiguous-regions-warnings documentation.
Change-Id: Iac2f395b3a1fbea4b3a732ba5a9b847e10b4b2f0
---
bfd/bfd-in2.h | 9 ++-
bfd/ecoff.c | 6 +-
bfd/elf32-arm.c | 11 ++++
bfd/elflink.c | 12 ++++
bfd/section.c | 9 ++-
include/bfdlink.h | 8 +++
ld/NEWS | 3 +
ld/emultempl/armelf.em | 3 +-
ld/ld.texi | 42 ++++++++++++++
ld/ldlang.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++--
ld/ldlex.h | 2 +
ld/lexsup.c | 10 ++++
12 files changed, 252 insertions(+), 9 deletions(-)
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 09a5a39..35d1abb 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1190,6 +1190,10 @@ typedef struct bfd_section
struct bfd_link_order *link_order;
struct bfd_section *s;
} map_head, map_tail;
+ /* Points to the output section this section is already assigned to, if any.
+ This is used when support for non-contiguous memory regions is enabled. */
+ struct bfd_section *already_assigned;
+
} asection;
/* Relax table contains information about instructions which can
@@ -1371,7 +1375,10 @@ discarded_section (const asection *sec)
(struct bfd_symbol *) SYM, &SEC.symbol, \
\
/* map_head, map_tail */ \
- { NULL }, { NULL } \
+ { NULL }, { NULL }, \
+ \
+ /* already_assigned */ \
+ NULL \
}
/* We use a macro to initialize the static asymbol structures because
diff --git a/bfd/ecoff.c b/bfd/ecoff.c
index 050fd7b..58620e5 100644
--- a/bfd/ecoff.c
+++ b/bfd/ecoff.c
@@ -78,8 +78,10 @@ static asection bfd_debug_section =
NULL,
/* symbol_ptr_ptr, */
NULL,
- /* map_head, map_tail */
- { NULL }, { NULL }
+ /* map_head, map_tail, */
+ { NULL }, { NULL },
+ /* already_assigned */
+ NULL,
};
/* Create an ECOFF object. */
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index faf8376..a32d5d2 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -5085,6 +5085,17 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
stub_bfd = stub_sec->owner;
+ /* Fail if the target section could not be assigned to an output
+ section. The user should fix his linker script. */
+ if (stub_entry->target_section->output_section == NULL
+ && info->non_contiguous_regions)
+ {
+ _bfd_error_handler (_("Could not assign %pA to an output section. "
+ "Retry without --enable-non-contiguous-regions.\n"),
+ stub_entry->target_section);
+ abort();
+ }
+
/* This is the address of the stub destination. */
sym_value = (stub_entry->target_value
+ stub_entry->target_section->output_offset
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 5217528..deef7f5 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -10569,6 +10569,18 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
discarding, we don't need to keep it. */
if (isym->st_shndx != SHN_UNDEF
&& isym->st_shndx < SHN_LORESERVE
+ && isec->output_section == NULL
+ && flinfo->info->non_contiguous_regions
+ && flinfo->info->non_contiguous_regions_warnings)
+ {
+ _bfd_error_handler (_("warning: --enable-non-contiguous-regions "
+ "discards section `%s' from '%s'\n"),
+ isec->name, isec->owner->filename);
+ continue;
+ }
+
+ if (isym->st_shndx != SHN_UNDEF
+ && isym->st_shndx < SHN_LORESERVE
&& bfd_section_removed_from_list (output_bfd,
isec->output_section))
continue;
diff --git a/bfd/section.c b/bfd/section.c
index 0c15a0d..c1a1a4b 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -549,6 +549,10 @@ CODE_FRAGMENT
. struct bfd_link_order *link_order;
. struct bfd_section *s;
. } map_head, map_tail;
+. {* Points to the output section this section is already assigned to, if any.
+. This is used when support for non-contiguous memory regions is enabled. *}
+. struct bfd_section *already_assigned;
+.
.} asection;
.
.{* Relax table contains information about instructions which can
@@ -730,7 +734,10 @@ CODE_FRAGMENT
. (struct bfd_symbol *) SYM, &SEC.symbol, \
. \
. {* map_head, map_tail *} \
-. { NULL }, { NULL } \
+. { NULL }, { NULL }, \
+. \
+. {* already_assigned *} \
+. NULL \
. }
.
.{* We use a macro to initialize the static asymbol structures because
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 8d85530..529ea6e 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -501,6 +501,14 @@ struct bfd_link_info
/* TRUE if "-Map map" is passed to linker. */
unsigned int has_map_file : 1;
+ /* TRUE if "--enable-non-contiguous-regions" is passed to the
+ linker. */
+ unsigned int non_contiguous_regions : 1;
+
+ /* TRUE if "--enable-non-contiguous-regions-warnings" is passed to
+ the linker. */
+ unsigned int non_contiguous_regions_warnings : 1;
+
/* Char that may appear as the first char of a symbol, but should be
skipped (like symbol_leading_char) when looking up symbols in
wrap_hash. Used by PowerPC Linux for 'dot' symbols. */
diff --git a/ld/NEWS b/ld/NEWS
index f659ccf..2611a3e 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
-*- text -*-
+* Add command-line options --enable-non-contiguous-regions and
+ --enable-non-contiguous-regions-warnings.
+
Changes in 2.34:
* cr16c support removed.
diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
index efdcf5a..fb5bbf8 100644
--- a/ld/emultempl/armelf.em
+++ b/ld/emultempl/armelf.em
@@ -227,7 +227,8 @@ elf32_arm_add_stub_section (const char * stub_sec_name,
struct hook_stub_info info;
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
- | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
+ | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP
+ | SEC_LINKER_CREATED);
stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
stub_sec_name, flags);
if (stub_sec == NULL)
diff --git a/ld/ld.texi b/ld/ld.texi
index 9bb3d55..07933b2 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -459,6 +459,48 @@ will contain a colon separated list of audit interfaces to use. This
option is only meaningful on ELF platforms supporting the rtld-audit interface.
The -P option is provided for Solaris compatibility.
+@kindex --enable-non-contiguous-regions
+@item --enable-non-contiguous-regions
+This option avoids generating an error if an input section does not
+fit a matching output section. The linker tries to allocate the input
+section to subseque nt matching output sections, and generates an
+error only if no output section is large enough. This is useful when
+several non-contiguous memory regions are available and the input
+section does not require a particular one. The order in which input
+sections are evaluated does not change, for instance:
+
+@smallexample
+ MEMORY @{
+ MEM1 (rwx) : ORIGIN : 0x1000, LENGTH = 0x14
+ MEM2 (rwx) : ORIGIN : 0x1000, LENGTH = 0x40
+ MEM3 (rwx) : ORIGIN : 0x2000, LENGTH = 0x40
+ @}
+ SECTIONS @{
+ mem1 : @{ *(.data.*); @} > MEM1
+ mem2 : @{ *(.data.*); @} > MEM2
+ mem3 : @{ *(.data.*); @} > MEM2
+ @}
+
+ with input sections:
+ .data.1: size 8
+ .data.2: size 0x10
+ .data.3: size 4
+
+ results in .data.1 affected to mem1, and .data.2 and .data.3
+ affected to mem2, even though .data.3 would fit in mem3.
+@end smallexample
+
+This option is incompatible with INSERT statements because it changes
+the way input sections are mapped to output sections.
+
+@kindex --enable-non-contiguous-regions-warnings
+@item --enable-non-contiguous-regions-warnings
+This option enables warnings when
+@code{--enable-non-contiguous-regions} allows possibly unexpected
+matches in sections mapping, potentially leading to silently
+discarding a section instead of failing because it does not fit any
+output region.
+
@cindex entry point, from command line
@kindex -e @var{entry}
@kindex --entry=@var{entry}
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 91c160b..d34919e 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -2537,6 +2537,11 @@ lang_add_section (lang_statement_list_type *ptr,
/* This prevents future calls from assigning this section. */
section->output_section = bfd_abs_section_ptr;
}
+ else if (link_info.non_contiguous_regions_warnings)
+ einfo (_("%P:%pS: warning: --enable-non-contiguous-regions makes "
+ "section `%pA' from '%pB' match /DISCARD/ clause.\n"),
+ NULL, section, section->owner);
+
return;
}
@@ -2550,7 +2555,33 @@ lang_add_section (lang_statement_list_type *ptr,
}
if (section->output_section != NULL)
- return;
+ {
+ if (!link_info.non_contiguous_regions)
+ return;
+
+ /* SECTION has already been handled in a special way
+ (eg. LINK_ONCE): skip it. */
+ if (bfd_is_abs_section (section->output_section))
+ return;
+
+ /* Already assigned to the same output section, do not process
+ it again, to avoid creating loops between duplicate sections
+ later. */
+ if (section->output_section == output->bfd_section)
+ return;
+
+ if (link_info.non_contiguous_regions_warnings && output->bfd_section)
+ einfo (_("%P:%pS: warning: --enable-non-contiguous-regions may "
+ "change behaviour for section `%pA' from '%pB' (assigned to "
+ "%pA, but additional match: %pA)\n"),
+ NULL, section, section->owner, section->output_section,
+ output->bfd_section);
+
+ /* SECTION has already been assigned to an output section, but
+ the user allows it to be mapped to another one in case it
+ overflows. We'll later update the actual output section in
+ size_input_section as appropriate. */
+ }
/* We don't copy the SEC_NEVER_LOAD flag from an input section
to an output section, because we want to be able to include a
@@ -4194,6 +4225,12 @@ process_insert_statements (lang_statement_union_type **start)
lang_statement_union_type **ptr;
lang_statement_union_type *first;
+ if (link_info.non_contiguous_regions)
+ {
+ einfo (_("warning: INSERT statement in linker script is "
+ "incompatible with --enable-non-contiguous-regions.\n"));
+ }
+
where = lang_output_section_find (i->where);
if (where != NULL && i->is_before)
{
@@ -5116,11 +5153,27 @@ size_input_section
(lang_statement_union_type **this_ptr,
lang_output_section_statement_type *output_section_statement,
fill_type *fill,
+ bfd_boolean *removed,
bfd_vma dot)
{
lang_input_section_type *is = &((*this_ptr)->input_section);
asection *i = is->section;
asection *o = output_section_statement->bfd_section;
+ *removed = 0;
+
+ if (link_info.non_contiguous_regions)
+ {
+ /* If the input section I has already been successfully assigned
+ to an output section other than O, don't bother with it and
+ let the caller remove it from the list. Keep processing in
+ case we have already handled O, because the repeated passes
+ have reinitialized its size. */
+ if (i->already_assigned && i->already_assigned != o)
+ {
+ *removed = 1;
+ return dot;
+ }
+ }
if (i->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
i->output_offset = i->vma - o->vma;
@@ -5152,6 +5205,43 @@ size_input_section
dot += alignment_needed;
}
+ if (link_info.non_contiguous_regions)
+ {
+ /* If I would overflow O, let the caller remove I from the
+ list. */
+ if (output_section_statement->region)
+ {
+ bfd_vma end = output_section_statement->region->origin
+ + output_section_statement->region->length;
+
+ if (dot + TO_ADDR (i->size) > end)
+ {
+ if (i->flags & SEC_LINKER_CREATED)
+ {
+ einfo (_("Output section %s not large enough for the "
+ "linker-created stubs section %s.\n"),
+ i->output_section->name, i->name);
+ abort();
+ }
+
+ if (i->rawsize && i->rawsize != i->size)
+ {
+ einfo (_("Relaxation not supported with "
+ "--enable-non-contiguous-regions (section %s "
+ "would overflow %s after it changed size).\n"),
+ i->name, i->output_section->name);
+ abort();
+ }
+
+ *removed = 1;
+ dot = end;
+ ASSERT (i->already_assigned == NULL);
+ i->output_section = NULL;
+ return dot;
+ }
+ }
+ }
+
/* Remember where in the output section this input section goes. */
i->output_offset = dot - o->vma;
@@ -5159,6 +5249,14 @@ size_input_section
dot += TO_ADDR (i->size);
if (!(o->flags & SEC_FIXED_SIZE))
o->size = TO_SIZE (dot - o->vma);
+
+ if (link_info.non_contiguous_regions)
+ {
+ /* Record that I was successfully assigned to O, and update
+ its actual output section too. */
+ i->already_assigned = o;
+ i->output_section = o;
+ }
}
return dot;
@@ -5445,10 +5543,14 @@ lang_size_sections_1
bfd_boolean check_regions)
{
lang_statement_union_type *s;
+ lang_statement_union_type *prev_s = NULL;
+ bfd_boolean removed_prev_s = FALSE;
/* Size up the sections from their constituent parts. */
- for (s = *prev; s != NULL; s = s->header.next)
+ for (s = *prev; s != NULL; prev_s = s, s = s->header.next)
{
+ bfd_boolean removed=FALSE;
+
switch (s->header.type)
{
case lang_output_section_statement_enum:
@@ -5874,7 +5976,7 @@ lang_size_sections_1
*relax = TRUE;
}
dot = size_input_section (prev, output_section_statement,
- fill, dot);
+ fill, &removed, dot);
}
break;
@@ -5979,7 +6081,43 @@ lang_size_sections_1
FAIL ();
break;
}
- prev = &s->header.next;
+
+ /* If an input section doesn't fit in the current output
+ section, remove it from the list. Handle the case where we
+ have to remove an input_section statement here: there is a
+ special case to remove the first element of the list. */
+ if (link_info.non_contiguous_regions && removed)
+ {
+ /* If we removed the first element during the previous
+ iteration, override the loop assignment of prev_s. */
+ if (removed_prev_s)
+ prev_s = NULL;
+
+ if (prev_s)
+ {
+ /* If there was a real previous input section, just skip
+ the current one. */
+ prev_s->header.next=s->header.next;
+ s = prev_s;
+ removed_prev_s = FALSE;
+ }
+ else
+ {
+ /* Remove the first input section of the list. */
+ *prev = s->header.next;
+ removed_prev_s = TRUE;
+ }
+
+ /* Move to next element, unless we removed the head of the
+ list. */
+ if (!removed_prev_s)
+ prev = &s->header.next;
+ }
+ else
+ {
+ prev = &s->header.next;
+ removed_prev_s = FALSE;
+ }
}
return dot;
}
diff --git a/ld/ldlex.h b/ld/ldlex.h
index 5287f19..22b928d 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -150,6 +150,8 @@ enum option_values
OPTION_FORCE_GROUP_ALLOCATION,
OPTION_PRINT_MAP_DISCARDED,
OPTION_NO_PRINT_MAP_DISCARDED,
+ OPTION_NON_CONTIGUOUS_REGIONS,
+ OPTION_NON_CONTIGUOUS_REGIONS_WARNINGS,
};
/* The initial parser states. */
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 3d15cc4..2597e2d 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -122,6 +122,10 @@ static const struct ld_option ld_options[] =
'E', NULL, N_("Export all dynamic symbols"), TWO_DASHES },
{ {"no-export-dynamic", no_argument, NULL, OPTION_NO_EXPORT_DYNAMIC},
'\0', NULL, N_("Undo the effect of --export-dynamic"), TWO_DASHES },
+ { {"enable-non-contiguous-regions", no_argument, NULL, OPTION_NON_CONTIGUOUS_REGIONS},
+ '\0', NULL, N_("Enable support of non-contiguous memory regions"), TWO_DASHES },
+ { {"enable-non-contiguous-regions-warnings", no_argument, NULL, OPTION_NON_CONTIGUOUS_REGIONS_WARNINGS},
+ '\0', NULL, N_("Enable warnings when --enable-non-contiguous-regions may cause unexpected behaviour"), TWO_DASHES },
{ {"EB", no_argument, NULL, OPTION_EB},
'\0', NULL, N_("Link big-endian objects"), ONE_DASH },
{ {"EL", no_argument, NULL, OPTION_EL},
@@ -845,6 +849,12 @@ parse_args (unsigned argc, char **argv)
case OPTION_NO_EXPORT_DYNAMIC:
link_info.export_dynamic = FALSE;
break;
+ case OPTION_NON_CONTIGUOUS_REGIONS:
+ link_info.non_contiguous_regions = TRUE;
+ break;
+ case OPTION_NON_CONTIGUOUS_REGIONS_WARNINGS:
+ link_info.non_contiguous_regions_warnings = TRUE;
+ break;
case 'e':
lang_add_entry (optarg, TRUE);
break;
--
2.7.4
From 7298bda0d21c96f5db7fb62f623f8795718dd10d Mon Sep 17 00:00:00 2001
From: Christophe Lyon <christophe.lyon@linaro.org>
Date: Mon, 25 Nov 2019 08:56:22 +0000
Subject: [PATCH 2/4] Add generic test for non-contiguous memory regions
2020-01-06 Christophe Lyon <christophe.lyon@linaro.org>
ld/
* testsuite/ld-elf/non-contiguous.d: New.
* testsuite/ld-elf/non-contiguous.ld: New.
* testsuite/ld-elf/non-contiguous.s: New.
Change-Id: Ia81d08450956f0fee7eff365ab23060f4882703b
---
ld/testsuite/ld-elf/non-contiguous.d | 41 +++++++++++++++++++++++++++++++++++
ld/testsuite/ld-elf/non-contiguous.ld | 34 +++++++++++++++++++++++++++++
ld/testsuite/ld-elf/non-contiguous.s | 21 ++++++++++++++++++
3 files changed, 96 insertions(+)
create mode 100644 ld/testsuite/ld-elf/non-contiguous.d
create mode 100644 ld/testsuite/ld-elf/non-contiguous.ld
create mode 100644 ld/testsuite/ld-elf/non-contiguous.s
diff --git a/ld/testsuite/ld-elf/non-contiguous.d b/ld/testsuite/ld-elf/non-contiguous.d
new file mode 100644
index 0000000..7a11443
--- /dev/null
+++ b/ld/testsuite/ld-elf/non-contiguous.d
@@ -0,0 +1,41 @@
+#name: non-contiguous
+#source: non-contiguous.s
+#as: -mlittle-endian
+#ld: --enable-non-contiguous-regions -T non-contiguous.ld -EL
+#objdump: -rdtsh
+#xfail: [is_generic]
+
+.*: file format .*
+
+Sections:
+Idx Name Size VMA LMA File off Algn
+ 0 \.raml 0000000c 1fff0000 1fff0000 00010000 2\*\*0
+ CONTENTS, ALLOC, LOAD, DATA
+ 1 \.ramu 00000014 20000000 1fff000c 00020000 2\*\*0
+ CONTENTS, ALLOC, LOAD, DATA
+ 2 \.ramz 0000003c 20040000 20000014 00030000 2\*\*0
+ CONTENTS, ALLOC, LOAD, DATA
+SYMBOL TABLE:
+1fff0000 l d .raml 00000000 .raml
+20000000 l d .ramu 00000000 .ramu
+20040000 l d .ramz 00000000 .ramz
+00000000 l df \*ABS\* 00000000 .*/non-contiguous.o
+00000002 l \*ABS\* 00000000 ALIGN
+1fff000c g .raml 00000000 _raml_end
+2004003c g .ramz 00000000 _ramz_end
+20000000 g .ramu 00000000 _rmau_start
+1fff0000 g .raml 00000000 _rmal_start
+20000014 g .ramu 00000000 _ramu_end
+20040000 g .ramz 00000000 _rmaz_start
+
+
+Contents of section .raml:
+ 1fff0000 01000000 02000000 03000000 ............
+Contents of section .ramu:
+ 20000000 04000000 05000000 06000000 07000000 ................
+ 20000010 08000000 ....
+Contents of section .ramz:
+ 20040000 09090909 09090909 09090909 09090909 ................
+ 20040010 09090909 09090909 09090909 09090909 ................
+ 20040020 09090909 09090909 09090909 09090909 ................
+ 20040030 09090909 09090909 09090909 ............
diff --git a/ld/testsuite/ld-elf/non-contiguous.ld b/ld/testsuite/ld-elf/non-contiguous.ld
new file mode 100644
index 0000000..50c98b4
--- /dev/null
+++ b/ld/testsuite/ld-elf/non-contiguous.ld
@@ -0,0 +1,34 @@
+/*
+ section .data.1 fits in .raml
+ sections .data.2 .data.3 fit in .ramu
+ section .data.4 fits in .ramz
+*/
+MEMORY
+{
+ RAML (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 0x00014
+ RAMU (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040
+ RAMZ (rwx) : ORIGIN = 0x20040000, LENGTH = 0x00040
+}
+
+SECTIONS
+{
+ /DISCARD/ : { *(.ARM.attributes) }
+ .raml : AT ( ADDR (.text) + SIZEOF (.text) )
+ { _rmal_start = . ;
+ *(.boot) ;
+ *(.data) *(.data.*) ;
+ _raml_end = . ;
+ } > RAML
+
+ .ramu : AT ( ADDR (.raml) + SIZEOF (.raml) )
+ { _rmau_start = . ;
+ *(.data) *(.data.*) ;
+ _ramu_end = . ;
+ } > RAMU
+
+ .ramz : AT ( ADDR (.ramu) + SIZEOF (.ramu) )
+ { _rmaz_start = . ;
+ *(.data) *(.data.*) ;
+ _ramz_end = . ;
+ } > RAMZ
+}
diff --git a/ld/testsuite/ld-elf/non-contiguous.s b/ld/testsuite/ld-elf/non-contiguous.s
new file mode 100644
index 0000000..8e2d581
--- /dev/null
+++ b/ld/testsuite/ld-elf/non-contiguous.s
@@ -0,0 +1,21 @@
+ .section .data.1
+ # Fit in RAML
+ .4byte 1
+ .4byte 2
+ .4byte 3
+
+ .section .data.2
+ # Fit in RAMU
+ .4byte 4
+ .4byte 5
+ .4byte 6
+
+ .section .data.3
+ # Fit in RAMU
+ .4byte 7
+ .4byte 8
+
+ .section .data.4
+ # Fit in RAMZ
+ .fill 0x3c, 1, 9
+
--
2.7.4
From d29c3b8ded98f629044fa85e94b0862c47df308b Mon Sep 17 00:00:00 2001
From: Christophe Lyon <christophe.lyon@linaro.org>
Date: Mon, 6 Jan 2020 14:58:43 +0000
Subject: [PATCH 4/4] Add powerpc test for non-contiguous memory regions
2020-01-06 Christophe Lyon <christophe.lyon@linaro.org>
ld/
* testsuite/ld-powerpc/powerpc.exp: Run new test.
* testsuite/ld-powerpc/non-contiguous-powerpc.d: New.
* testsuite/ld-powerpc/non-contiguous-powerpc.ld: New.
* testsuite/ld-powerpc/non-contiguous-powerpc.sd: New.
Change-Id: Iad0b160ad1b382a158dc06fa4e4656eb06691a8a
---
ld/testsuite/ld-powerpc/non-contiguous-powerpc.d | 4 ++++
ld/testsuite/ld-powerpc/non-contiguous-powerpc.ld | 22 ++++++++++++++++++++++
ld/testsuite/ld-powerpc/non-contiguous-powerpc.s | 8 ++++++++
ld/testsuite/ld-powerpc/powerpc.exp | 2 ++
4 files changed, 36 insertions(+)
create mode 100644 ld/testsuite/ld-powerpc/non-contiguous-powerpc.d
create mode 100644 ld/testsuite/ld-powerpc/non-contiguous-powerpc.ld
create mode 100644 ld/testsuite/ld-powerpc/non-contiguous-powerpc.s
diff --git a/ld/testsuite/ld-powerpc/non-contiguous-powerpc.d b/ld/testsuite/ld-powerpc/non-contiguous-powerpc.d
new file mode 100644
index 0000000..2dd7d21
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/non-contiguous-powerpc.d
@@ -0,0 +1,4 @@
+#name: non-contiguous-powerpc
+#source: non-contiguous-powerpc.s
+#ld: --enable-non-contiguous-regions -T non-contiguous-powerpc.ld
+#error: \ARelaxation not supported with --enable-non-contiguous-regions.*
\ No newline at end of file
diff --git a/ld/testsuite/ld-powerpc/non-contiguous-powerpc.ld b/ld/testsuite/ld-powerpc/non-contiguous-powerpc.ld
new file mode 100644
index 0000000..744d246
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/non-contiguous-powerpc.ld
@@ -0,0 +1,22 @@
+/* Distance between 'one' and 'two' means that relaxation implies that
+ .text.one's size increases. Even though the result would fit in
+ 'oneandhalf', this is not supported by
+ --enable-non-contiguous-regions. */
+
+MEMORY {
+ one (RXAI) : ORIGIN = 0x00000000, LENGTH = 0x00000010
+ oneandhalf (RXAI) : ORIGIN = 0x00001000, LENGTH = 0x00001010
+ two (RXAI) : ORIGIN = 0x20000000, LENGTH = 0x10000000
+}
+
+SECTIONS {
+ one : {
+ *(.text.one)
+ } > one
+ oneandhalf : {
+ *(.text.one)
+ } > oneandhalf
+ two : {
+ *(.text.two)
+ } > two
+}
diff --git a/ld/testsuite/ld-powerpc/non-contiguous-powerpc.s b/ld/testsuite/ld-powerpc/non-contiguous-powerpc.s
new file mode 100644
index 0000000..e02b322
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/non-contiguous-powerpc.s
@@ -0,0 +1,8 @@
+ .machine "ppc"
+
+ .section .text.one
+ b 2f
+
+ .section .text.two
+2:
+ nop
diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp
index 94b2fac..796635f 100644
--- a/ld/testsuite/ld-powerpc/powerpc.exp
+++ b/ld/testsuite/ld-powerpc/powerpc.exp
@@ -443,3 +443,5 @@ run_dump_test "vle-multiseg-6"
run_dump_test "ppc476-shared"
run_dump_test "ppc476-shared2"
+
+run_dump_test "non-contiguous-powerpc"
--
2.7.4
From ad381e5cb59f17da928af23d420ce33d466348f1 Mon Sep 17 00:00:00 2001
From: Christophe Lyon <christophe.lyon@linaro.org>
Date: Mon, 6 Jan 2020 14:58:24 +0000
Subject: [PATCH 3/4] Add arm tests for non-contiguous memory regions
2020-01-06 Christophe Lyon <christophe.lyon@linaro.org>
ld/
* testsuite/ld-arm/arm-elf.exp: Run the new tests.
* testsuite/ld-arm/arm-elf/non-contiguous-arm.s: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm.d: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm.ld: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm2.d: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm3.ld: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm3.d: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm3.ld: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm4.d: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm4.ld: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm5.d: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm5.ld: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm6.d: New.
* testsuite/ld-arm/arm-elf/non-contiguous-arm6.ld: New.
Change-Id: Ib9e82b1eedd84aee936e01f9aeee7fdd4aa331bb
---
ld/testsuite/ld-arm/arm-elf.exp | 7 +++
ld/testsuite/ld-arm/non-contiguous-arm.d | 4 ++
ld/testsuite/ld-arm/non-contiguous-arm.ld | 34 +++++++++++++
ld/testsuite/ld-arm/non-contiguous-arm.s | 35 +++++++++++++
ld/testsuite/ld-arm/non-contiguous-arm2.d | 77 ++++++++++++++++++++++++++++
ld/testsuite/ld-arm/non-contiguous-arm2.ld | 33 ++++++++++++
ld/testsuite/ld-arm/non-contiguous-arm3.d | 82 ++++++++++++++++++++++++++++++
ld/testsuite/ld-arm/non-contiguous-arm3.ld | 33 ++++++++++++
ld/testsuite/ld-arm/non-contiguous-arm4.d | 4 ++
ld/testsuite/ld-arm/non-contiguous-arm4.ld | 34 +++++++++++++
ld/testsuite/ld-arm/non-contiguous-arm5.d | 77 ++++++++++++++++++++++++++++
ld/testsuite/ld-arm/non-contiguous-arm5.ld | 34 +++++++++++++
ld/testsuite/ld-arm/non-contiguous-arm6.d | 76 +++++++++++++++++++++++++++
ld/testsuite/ld-arm/non-contiguous-arm6.ld | 33 ++++++++++++
14 files changed, 563 insertions(+)
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm.d
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm.ld
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm.s
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm2.d
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm2.ld
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm3.d
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm3.ld
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm4.d
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm4.ld
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm5.d
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm5.ld
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm6.d
create mode 100644 ld/testsuite/ld-arm/non-contiguous-arm6.ld
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 44e599f..18177d1 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -1261,3 +1261,10 @@ set arm_unwind_tests {
"unwind-mix"}
}
run_ld_link_tests $arm_unwind_tests
+
+run_dump_test "non-contiguous-arm"
+run_dump_test "non-contiguous-arm2"
+run_dump_test "non-contiguous-arm3"
+run_dump_test "non-contiguous-arm4"
+run_dump_test "non-contiguous-arm5"
+run_dump_test "non-contiguous-arm6"
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm.d b/ld/testsuite/ld-arm/non-contiguous-arm.d
new file mode 100644
index 0000000..c62a453
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm.d
@@ -0,0 +1,4 @@
+#name: non-contiguous-arm
+#source: non-contiguous-arm.s
+#ld: --enable-non-contiguous-regions -T non-contiguous-arm.ld
+# error: \A.*Could not assign .code.4 to an output section. Retry without --enable-non-contiguous-regions.*\Z
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm.ld b/ld/testsuite/ld-arm/non-contiguous-arm.ld
new file mode 100644
index 0000000..a50621b
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm.ld
@@ -0,0 +1,34 @@
+/*
+ sections .code.1 and .code.2 fit in .raml
+ section .code.3 fits in .ramu
+ section .code.4 too large to fit
+ expect an error about .code.4
+*/
+MEMORY
+{
+ RAML (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 0x0001c
+ RAMU (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040
+ RAMZ (rwx) : ORIGIN = 0x20040000, LENGTH = 0x00040
+}
+
+SECTIONS
+{
+ .raml :
+ { _raml_start = . ;
+ *(.boot) ;
+ *(.code) *(.code.*) ;
+ _raml_end = . ;
+ } > RAML
+
+ .ramu : AT ( ADDR (.raml) + SIZEOF (.raml) )
+ { _ramu_start = . ;
+ *(.code) *(.code.*) ;
+ _ramu_end = . ;
+ } > RAMU
+
+ .ramz : AT ( ADDR (.ramu) + SIZEOF (.ramu) )
+ { _ramz_start = . ;
+ *(.code) *(.code.*) ;
+ _ramz_end = . ;
+ } > RAMZ
+}
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm.s b/ld/testsuite/ld-arm/non-contiguous-arm.s
new file mode 100644
index 0000000..cdc8b00
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm.s
@@ -0,0 +1,35 @@
+ .syntax unified
+ .section .code.1, "ax", %progbits
+ .arm
+ # Fit in RAML
+ .global code1
+ .type code1, %function
+code1:
+ nop
+ nop
+ bl code2
+
+ .section .code.2, "ax", %progbits
+ # Fit in RAML
+ .global code2
+ .type code2, %function
+code2:
+ nop
+ nop
+ bl code3
+
+ .section .code.3, "ax", %progbits
+ # Fit in RAMU
+ .global code3
+ .type code3, %function
+code3:
+ nop
+ bl code4
+
+ .section .code.4, "ax", %progbits
+ # Fit in RAMZ
+ .global code4
+ .type code4, %function
+code4:
+$a:
+ .fill 20, 4, 0xe1a00000
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm2.d b/ld/testsuite/ld-arm/non-contiguous-arm2.d
new file mode 100644
index 0000000..ed2ba69
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm2.d
@@ -0,0 +1,77 @@
+#name: non-contiguous-arm2
+#source: non-contiguous-arm.s
+#ld: --enable-non-contiguous-regions -T non-contiguous-arm2.ld
+#objdump: -rdth
+#xfail: [is_generic]
+
+.*: file format elf32-(little|big)arm
+
+Sections:
+Idx Name Size VMA LMA File off Algn
+ 0 \.raml 00000018 1fff0000 1fff0000 00010000 2\*\*2
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 1 \.ramu 00000008 20000000 1fff0018 00020000 2\*\*2
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 2 \.ramz 00000050 20040000 20000008 00030000 2\*\*2
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 3 .ARM.attributes 00000012 00000000 00000000 00030050 2\*\*0
+ CONTENTS, READONLY
+SYMBOL TABLE:
+1fff0000 l d .raml 00000000 .raml
+20000000 l d .ramu 00000000 .ramu
+20040000 l d .ramz 00000000 .ramz
+00000000 l d .ARM.attributes 00000000 .ARM.attributes
+00000000 l df \*ABS\* 00000000 .*/non-contiguous-arm.o
+1fff0018 g .raml 00000000 _raml_end
+20000000 g .ramu 00000000 _ramu_start
+1fff000c g F .raml 00000000 code2
+20040000 g .ramz 00000000 _ramz_start
+1fff0000 g .raml 00000000 _raml_start
+20000000 g F .ramu 00000000 code3
+1fff0000 g F .raml 00000000 code1
+20040050 g .ramz 00000000 _ramz_end
+20040000 g F .ramz 00000000 code4
+20000008 g .ramu 00000000 _ramu_end
+
+
+Disassembly of section .raml:
+
+1fff0000 \<code1\>:
+1fff0000: e1a00000 nop ; \(mov r0, r0\)
+1fff0004: e1a00000 nop ; \(mov r0, r0\)
+1fff0008: ebffffff bl 1fff000c \<code2\>
+
+1fff000c \<code2\>:
+1fff000c: e1a00000 nop ; \(mov r0, r0\)
+1fff0010: e1a00000 nop ; \(mov r0, r0\)
+1fff0014: eb003ff9 bl 20000000 \<code3\>
+
+Disassembly of section .ramu:
+
+20000000 \<code3\>:
+20000000: e1a00000 nop ; \(mov r0, r0\)
+20000004: eb00fffd bl 20040000 \<code4\>
+
+Disassembly of section .ramz:
+
+20040000 \<code4\>:
+20040000: e1a00000 .word 0xe1a00000
+20040004: e1a00000 .word 0xe1a00000
+20040008: e1a00000 .word 0xe1a00000
+2004000c: e1a00000 .word 0xe1a00000
+20040010: e1a00000 .word 0xe1a00000
+20040014: e1a00000 .word 0xe1a00000
+20040018: e1a00000 .word 0xe1a00000
+2004001c: e1a00000 .word 0xe1a00000
+20040020: e1a00000 .word 0xe1a00000
+20040024: e1a00000 .word 0xe1a00000
+20040028: e1a00000 .word 0xe1a00000
+2004002c: e1a00000 .word 0xe1a00000
+20040030: e1a00000 .word 0xe1a00000
+20040034: e1a00000 .word 0xe1a00000
+20040038: e1a00000 .word 0xe1a00000
+2004003c: e1a00000 .word 0xe1a00000
+20040040: e1a00000 .word 0xe1a00000
+20040044: e1a00000 .word 0xe1a00000
+20040048: e1a00000 .word 0xe1a00000
+2004004c: e1a00000 .word 0xe1a00000
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm2.ld b/ld/testsuite/ld-arm/non-contiguous-arm2.ld
new file mode 100644
index 0000000..f13567e
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm2.ld
@@ -0,0 +1,33 @@
+/*
+ sections .code.1 and .code.2 fit in .raml
+ section .code.3 fits in .ramu and does not need a farcall stub to jump to code4
+ section .code.4 fits in .ramz
+*/
+MEMORY
+{
+ RAML (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 0x0001c
+ RAMU (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008
+ RAMZ (rwx) : ORIGIN = 0x20040000, LENGTH = 0x00400
+}
+
+SECTIONS
+{
+ .raml :
+ { _raml_start = . ;
+ *(.boot) ;
+ *(.code) *(.code.*) ;
+ _raml_end = . ;
+ } > RAML
+
+ .ramu : AT ( ADDR (.raml) + SIZEOF (.raml) )
+ { _ramu_start = . ;
+ *(.code) *(.code.*) ;
+ _ramu_end = . ;
+ } > RAMU
+
+ .ramz : AT ( ADDR (.ramu) + SIZEOF (.ramu) )
+ { _ramz_start = . ;
+ *(.code) *(.code.*) ;
+ _ramz_end = . ;
+ } > RAMZ
+}
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm3.d b/ld/testsuite/ld-arm/non-contiguous-arm3.d
new file mode 100644
index 0000000..f8bbf98
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm3.d
@@ -0,0 +1,82 @@
+#name: non-contiguous-arm3
+#source: non-contiguous-arm.s
+#ld: --enable-non-contiguous-regions -T non-contiguous-arm3.ld
+#objdump: -rdth
+#xfail: [is_generic]
+
+.*: file format elf32-(little|big)arm
+
+Sections:
+Idx Name Size VMA LMA File off Algn
+ 0 \.raml 00000018 1fff0000 1fff0000 00010000 2\*\*2
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 1 \.ramu 00000010 20000000 1fff0018 00020000 2\*\*3
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 2 \.ramz 00000050 30040000 20000010 00030000 2\*\*2
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 3 .ARM.attributes 00000012 00000000 00000000 00030050 2\*\*0
+ CONTENTS, READONLY
+SYMBOL TABLE:
+1fff0000 l d .raml 00000000 .raml
+20000000 l d .ramu 00000000 .ramu
+30040000 l d .ramz 00000000 .ramz
+00000000 l d .ARM.attributes 00000000 .ARM.attributes
+00000000 l df \*ABS\* 00000000 .*/non-contiguous-arm.o
+20000008 l F .ramu 00000008 __code4_veneer
+1fff0018 g .raml 00000000 _raml_end
+20000000 g .ramu 00000000 _ramu_start
+1fff000c g F .raml 00000000 code2
+30040000 g .ramz 00000000 _ramz_start
+1fff0000 g .raml 00000000 _raml_start
+20000000 g F .ramu 00000000 code3
+1fff0000 g F .raml 00000000 code1
+30040050 g .ramz 00000000 _ramz_end
+30040000 g F .ramz 00000000 code4
+20000010 g .ramu 00000000 _ramu_end
+
+
+Disassembly of section .raml:
+
+1fff0000 \<code1\>:
+1fff0000: e1a00000 nop ; \(mov r0, r0\)
+1fff0004: e1a00000 nop ; \(mov r0, r0\)
+1fff0008: ebffffff bl 1fff000c \<code2\>
+
+1fff000c \<code2\>:
+1fff000c: e1a00000 nop ; \(mov r0, r0\)
+1fff0010: e1a00000 nop ; \(mov r0, r0\)
+1fff0014: eb003ff9 bl 20000000 \<code3\>
+
+Disassembly of section .ramu:
+
+20000000 \<code3\>:
+20000000: e1a00000 nop ; \(mov r0, r0\)
+20000004: ebffffff bl 20000008 \<__code4_veneer\>
+
+20000008 \<__code4_veneer\>:
+20000008: e51ff004 ldr pc, \[pc, #-4\] ; 2000000c \<__code4_veneer\+0x4\>
+2000000c: 30040000 .word 0x30040000
+
+Disassembly of section .ramz:
+
+30040000 \<code4\>:
+30040000: e1a00000 .word 0xe1a00000
+30040004: e1a00000 .word 0xe1a00000
+30040008: e1a00000 .word 0xe1a00000
+3004000c: e1a00000 .word 0xe1a00000
+30040010: e1a00000 .word 0xe1a00000
+30040014: e1a00000 .word 0xe1a00000
+30040018: e1a00000 .word 0xe1a00000
+3004001c: e1a00000 .word 0xe1a00000
+30040020: e1a00000 .word 0xe1a00000
+30040024: e1a00000 .word 0xe1a00000
+30040028: e1a00000 .word 0xe1a00000
+3004002c: e1a00000 .word 0xe1a00000
+30040030: e1a00000 .word 0xe1a00000
+30040034: e1a00000 .word 0xe1a00000
+30040038: e1a00000 .word 0xe1a00000
+3004003c: e1a00000 .word 0xe1a00000
+30040040: e1a00000 .word 0xe1a00000
+30040044: e1a00000 .word 0xe1a00000
+30040048: e1a00000 .word 0xe1a00000
+3004004c: e1a00000 .word 0xe1a00000
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm3.ld b/ld/testsuite/ld-arm/non-contiguous-arm3.ld
new file mode 100644
index 0000000..81bb695
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm3.ld
@@ -0,0 +1,33 @@
+/*
+ sections .code.1 and .code.2 fit in .raml
+ section .code.3 fits in .ramu even with a farcall stub to jump to code4
+ section .code.4 fits in .ramz
+*/
+MEMORY
+{
+ RAML (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 0x0001c
+ RAMU (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00010
+ RAMZ (rwx) : ORIGIN = 0x30040000, LENGTH = 0x00400
+}
+
+SECTIONS
+{
+ .raml :
+ { _raml_start = . ;
+ *(.boot) ;
+ *(.code) *(.code.*) ;
+ _raml_end = . ;
+ } > RAML
+
+ .ramu : AT ( ADDR (.raml) + SIZEOF (.raml) )
+ { _ramu_start = . ;
+ *(.code) *(.code.*) ;
+ _ramu_end = . ;
+ } > RAMU
+
+ .ramz : AT ( ADDR (.ramu) + SIZEOF (.ramu) )
+ { _ramz_start = . ;
+ *(.code) *(.code.*) ;
+ _ramz_end = . ;
+ } > RAMZ
+}
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm4.d b/ld/testsuite/ld-arm/non-contiguous-arm4.d
new file mode 100644
index 0000000..6b99544
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm4.d
@@ -0,0 +1,4 @@
+#name: non-contiguous-arm4
+#source: non-contiguous-arm.s
+#ld: --enable-non-contiguous-regions -T non-contiguous-arm4.ld
+# error: \AOutput section .ramu not large enough for the linker-created stubs section .code.3.__stub.*\Z
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm4.ld b/ld/testsuite/ld-arm/non-contiguous-arm4.ld
new file mode 100644
index 0000000..1e0c376
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm4.ld
@@ -0,0 +1,34 @@
+/*
+ sections .code.1 and .code.2 fit in .raml
+ section .code.3 fits in .ramu but not its farcall stub to jump to code4
+ section .code.4 fits in .ramz
+ expect an error about .code.3
+*/
+MEMORY
+{
+ RAML (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 0x0001c
+ RAMU (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008
+ RAMZ (rwx) : ORIGIN = 0x30040000, LENGTH = 0x00400
+}
+
+SECTIONS
+{
+ .raml :
+ { _raml_start = . ;
+ *(.boot) ;
+ *(.code) *(.code.*) ;
+ _raml_end = . ;
+ } > RAML
+
+ .ramu : AT ( ADDR (.raml) + SIZEOF (.raml) )
+ { _ramu_start = . ;
+ *(.code) *(.code.*) ;
+ _ramu_end = . ;
+ } > RAMU
+
+ .ramz : AT ( ADDR (.ramu) + SIZEOF (.ramu) )
+ { _ramz_start = . ;
+ *(.code) *(.code.*) ;
+ _ramz_end = . ;
+ } > RAMZ
+}
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm5.d b/ld/testsuite/ld-arm/non-contiguous-arm5.d
new file mode 100644
index 0000000..30f6118
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm5.d
@@ -0,0 +1,77 @@
+#name: non-contiguous-arm5
+#source: non-contiguous-arm.s
+#ld: --enable-non-contiguous-regions -T non-contiguous-arm5.ld
+#objdump: -rdth
+#xfail: [is_generic]
+
+.*: file format elf32-(little|big)arm
+
+Sections:
+Idx Name Size VMA LMA File off Algn
+ 0 \.raml 0000000c 1fff0000 1fff0000 00010000 2\*\*2
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 1 \.ramu 00000014 20000000 1fff000c 00020000 2\*\*2
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 2 \.ramz 00000050 20040000 20000014 00030000 2\*\*2
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 3 .ARM.attributes 00000012 00000000 00000000 00030050 2\*\*0
+ CONTENTS, READONLY
+SYMBOL TABLE:
+1fff0000 l d .raml 00000000 .raml
+20000000 l d .ramu 00000000 .ramu
+20040000 l d .ramz 00000000 .ramz
+00000000 l d .ARM.attributes 00000000 .ARM.attributes
+00000000 l df \*ABS\* 00000000 .*/non-contiguous-arm.o
+1fff000c g .raml 00000000 _raml_end
+20000000 g .ramu 00000000 _ramu_start
+20000000 g F .ramu 00000000 code2
+20040000 g .ramz 00000000 _ramz_start
+1fff0000 g .raml 00000000 _raml_start
+2000000c g F .ramu 00000000 code3
+1fff0000 g F .raml 00000000 code1
+20040050 g .ramz 00000000 _ramz_end
+20040000 g F .ramz 00000000 code4
+20000014 g .ramu 00000000 _ramu_end
+
+
+Disassembly of section .raml:
+
+1fff0000 \<code1\>:
+1fff0000: e1a00000 nop ; \(mov r0, r0\)
+1fff0004: e1a00000 nop ; \(mov r0, r0\)
+1fff0008: eb003ffc bl 20000000 \<code2\>
+
+Disassembly of section .ramu:
+
+20000000 \<code2\>:
+20000000: e1a00000 nop ; \(mov r0, r0\)
+20000004: e1a00000 nop ; \(mov r0, r0\)
+20000008: ebffffff bl 2000000c \<code3\>
+
+2000000c \<code3\>:
+2000000c: e1a00000 nop ; \(mov r0, r0\)
+20000010: eb00fffa bl 20040000 \<code4\>
+
+Disassembly of section .ramz:
+
+20040000 \<code4\>:
+20040000: e1a00000 .word 0xe1a00000
+20040004: e1a00000 .word 0xe1a00000
+20040008: e1a00000 .word 0xe1a00000
+2004000c: e1a00000 .word 0xe1a00000
+20040010: e1a00000 .word 0xe1a00000
+20040014: e1a00000 .word 0xe1a00000
+20040018: e1a00000 .word 0xe1a00000
+2004001c: e1a00000 .word 0xe1a00000
+20040020: e1a00000 .word 0xe1a00000
+20040024: e1a00000 .word 0xe1a00000
+20040028: e1a00000 .word 0xe1a00000
+2004002c: e1a00000 .word 0xe1a00000
+20040030: e1a00000 .word 0xe1a00000
+20040034: e1a00000 .word 0xe1a00000
+20040038: e1a00000 .word 0xe1a00000
+2004003c: e1a00000 .word 0xe1a00000
+20040040: e1a00000 .word 0xe1a00000
+20040044: e1a00000 .word 0xe1a00000
+20040048: e1a00000 .word 0xe1a00000
+2004004c: e1a00000 .word 0xe1a00000
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm5.ld b/ld/testsuite/ld-arm/non-contiguous-arm5.ld
new file mode 100644
index 0000000..99c0234
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm5.ld
@@ -0,0 +1,34 @@
+/*
+ section .code.1 fits in .raml
+ section .code.2 does not fit in .raml and goes to .ramu
+ section .code.3 would fit in .raml, but goes to .ramu: Check that .code.2 and .code.3 are not swapped
+ section .code.4 fits in .ramz
+*/
+MEMORY
+{
+ RAML (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 0x00014
+ RAMU (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020
+ RAMZ (rwx) : ORIGIN = 0x20040000, LENGTH = 0x00400
+}
+
+SECTIONS
+{
+ .raml :
+ { _raml_start = . ;
+ *(.boot) ;
+ *(.code) *(.code.*) ;
+ _raml_end = . ;
+ } > RAML
+
+ .ramu : AT ( ADDR (.raml) + SIZEOF (.raml) )
+ { _ramu_start = . ;
+ *(.code) *(.code.*) ;
+ _ramu_end = . ;
+ } > RAMU
+
+ .ramz : AT ( ADDR (.ramu) + SIZEOF (.ramu) )
+ { _ramz_start = . ;
+ *(.code) *(.code.*) ;
+ _ramz_end = . ;
+ } > RAMZ
+}
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm6.d b/ld/testsuite/ld-arm/non-contiguous-arm6.d
new file mode 100644
index 0000000..5c1c938
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm6.d
@@ -0,0 +1,76 @@
+#name: non-contiguous-arm6
+#source: non-contiguous-arm.s
+#ld: --enable-non-contiguous-regions -T non-contiguous-arm6.ld
+#objdump: -rdth
+#xfail: [is_generic]
+
+.*: file format elf32-(little|big)arm
+
+Sections:
+Idx Name Size VMA LMA File off Algn
+ 0 \.raml 00000028 1fff0000 1fff0000 00010000 2\*\*3
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 1 \.ramz 00000050 40040000 30000000 00020000 2\*\*2
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 2 .ARM.attributes 00000012 00000000 00000000 00020050 2\*\*0
+ CONTENTS, READONLY
+SYMBOL TABLE:
+1fff0000 l d .raml 00000000 .raml
+40040000 l d .ramz 00000000 .ramz
+00000000 l d .ARM.attributes 00000000 .ARM.attributes
+00000000 l df \*ABS\* 00000000 .*/non-contiguous-arm.o
+1fff0020 l F .raml 00000008 __code4_veneer
+1fff0028 g .raml 00000000 _raml_end
+30000000 g .raml 00000000 _ramu_start
+1fff000c g F .raml 00000000 code2
+40040000 g .ramz 00000000 _ramz_start
+1fff0000 g .raml 00000000 _raml_start
+1fff0018 g F .raml 00000000 code3
+1fff0000 g F .raml 00000000 code1
+40040050 g .ramz 00000000 _ramz_end
+40040000 g F .ramz 00000000 code4
+30000000 g .raml 00000000 _ramu_end
+
+Disassembly of section .raml:
+
+1fff0000 \<code1\>:
+1fff0000: e1a00000 nop ; \(mov r0, r0\)
+1fff0004: e1a00000 nop ; \(mov r0, r0\)
+1fff0008: ebffffff bl 1fff000c \<code2\>
+
+1fff000c \<code2\>:
+1fff000c: e1a00000 nop ; \(mov r0, r0\)
+1fff0010: e1a00000 nop ; \(mov r0, r0\)
+1fff0014: ebffffff bl 1fff0018 \<code3\>
+
+1fff0018 \<code3\>:
+1fff0018: e1a00000 nop ; \(mov r0, r0\)
+1fff001c: ebffffff bl 1fff0020 \<__code4_veneer\>
+
+1fff0020 \<__code4_veneer\>:
+1fff0020: e51ff004 ldr pc, \[pc, #-4\] ; 1fff0024 \<__code4_veneer\+0x4\>
+1fff0024: 40040000 .word 0x40040000
+
+Disassembly of section .ramz:
+
+40040000 \<code4\>:
+40040000: e1a00000 .word 0xe1a00000
+40040004: e1a00000 .word 0xe1a00000
+40040008: e1a00000 .word 0xe1a00000
+4004000c: e1a00000 .word 0xe1a00000
+40040010: e1a00000 .word 0xe1a00000
+40040014: e1a00000 .word 0xe1a00000
+40040018: e1a00000 .word 0xe1a00000
+4004001c: e1a00000 .word 0xe1a00000
+40040020: e1a00000 .word 0xe1a00000
+40040024: e1a00000 .word 0xe1a00000
+40040028: e1a00000 .word 0xe1a00000
+4004002c: e1a00000 .word 0xe1a00000
+40040030: e1a00000 .word 0xe1a00000
+40040034: e1a00000 .word 0xe1a00000
+40040038: e1a00000 .word 0xe1a00000
+4004003c: e1a00000 .word 0xe1a00000
+40040040: e1a00000 .word 0xe1a00000
+40040044: e1a00000 .word 0xe1a00000
+40040048: e1a00000 .word 0xe1a00000
+4004004c: e1a00000 .word 0xe1a00000
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm6.ld b/ld/testsuite/ld-arm/non-contiguous-arm6.ld
new file mode 100644
index 0000000..6d6d6fe
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm6.ld
@@ -0,0 +1,33 @@
+/*
+ sections .code.1, .code.2 and .code.3 (+ farcall stub) fit in .raml
+ section .code.4 fits in .ramz
+ nothing fits in .ramu
+*/
+MEMORY
+{
+ RAML (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 0x00030
+ RAMU (rwx) : ORIGIN = 0x30000000, LENGTH = 0x00010
+ RAMZ (rwx) : ORIGIN = 0x40040000, LENGTH = 0x00400
+}
+
+SECTIONS
+{
+ .raml :
+ { _raml_start = . ;
+ *(.boot) ;
+ *(.code) *(.code.*) ;
+ _raml_end = . ;
+ } > RAML
+
+ .ramu : AT ( ADDR (.raml) + SIZEOF (.raml) )
+ { _ramu_start = . ;
+ *(.code) *(.code.*) ;
+ _ramu_end = . ;
+ } > RAMU
+
+ .ramz : AT ( ADDR (.ramu) + SIZEOF (.ramu) )
+ { _ramz_start = . ;
+ *(.code) *(.code.*) ;
+ _ramz_end = . ;
+ } > RAMZ
+}
--
2.7.4