This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH RFC v2] Add support for non-contiguous memory regions


Hi,

This is a follow-up to
https://sourceware.org/ml/binutils/2019-11/msg00402.html

This version detects cases it isn't (yet?) able to handle and emits an
error message (and uses abort() which can probably be made more
user-friendly).

Specifically, I have:
* improved the testcase in ld-elf, hoping that it's now generic enough
(at least it passes on arm and powerpc).

* added a powerpc testcase, based on the sample provided by Simon. It
now fails with an error message when relaxation was applied.

* added several arm testcases, some of which involve farcall stubs
insertion. Something annoying with stubs handling is that I had to
modify arm-specific code to generate an error in a case where the stub
destination could not be allocated. We'd have to do this in every
target that has XXX_build_one_stub().
I now add the SEC_LINKER_CREATED flag on the stubs sections so that we
can emit a helpful error message in case the stubs do not fit in
memory.

There's a new test to check that section order does not change.

Finally, I had to change the way I remove input_section statements in
lang_size_sections_1() to correctly handle the case where we have to
remove the head of the list.

There are now 4 patches, to hopefully make review/comments easier:
* patch1: is the main (code) patch
* patch2: generic test
* patch3: arm tests
* patch4: powerpc test

Thoughts?

Thanks,

Christophe
From cc9f4001edfd4cf8fdf4b5da3425557523bc121a 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  | 35 +++++++++++++
 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 | 34 +++++++++++++
 ld/testsuite/ld-arm/non-contiguous-arm3.d  | 82 ++++++++++++++++++++++++++++++
 ld/testsuite/ld-arm/non-contiguous-arm3.ld | 34 +++++++++++++
 ld/testsuite/ld-arm/non-contiguous-arm4.d  |  4 ++
 ld/testsuite/ld-arm/non-contiguous-arm4.ld | 35 +++++++++++++
 ld/testsuite/ld-arm/non-contiguous-arm5.d  | 77 ++++++++++++++++++++++++++++
 ld/testsuite/ld-arm/non-contiguous-arm5.ld | 35 +++++++++++++
 ld/testsuite/ld-arm/non-contiguous-arm6.d  | 76 +++++++++++++++++++++++++++
 ld/testsuite/ld-arm/non-contiguous-arm6.ld | 34 +++++++++++++
 14 files changed, 569 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 b4ff044..dc1591a 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..5441764
--- /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.*No output section assigned to .code.4. 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..551eb41
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm.ld
@@ -0,0 +1,35 @@
+/*
+ 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..ef38e96
--- /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..461f119
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm2.ld
@@ -0,0 +1,34 @@
+/*
+ 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..a18d64c
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm3.ld
@@ -0,0 +1,34 @@
+/*
+ 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..8882c47
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm4.ld
@@ -0,0 +1,35 @@
+/*
+ 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..6284fda
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm5.ld
@@ -0,0 +1,35 @@
+/*
+ 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..f00cd6a
--- /dev/null
+++ b/ld/testsuite/ld-arm/non-contiguous-arm6.ld
@@ -0,0 +1,34 @@
+/*
+ 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

From b63693a5b36d1fbf8514e193d572fc64ac263f25 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 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 | 30 +++++++++++++++++++++++++
 ld/testsuite/ld-elf/non-contiguous.s  | 21 ++++++++++++++++++
 3 files changed, 92 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..665aa1e
--- /dev/null
+++ b/ld/testsuite/ld-elf/non-contiguous.ld
@@ -0,0 +1,30 @@
+MEMORY
+{
+  RAML (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010
+  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..af76cfc
--- /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 3eac50c5b3b1a13c116bb08c0747508a95f59824 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 | 18 ++++++++++++++++++
 ld/testsuite/ld-powerpc/non-contiguous-powerpc.s  |  8 ++++++++
 ld/testsuite/ld-powerpc/powerpc.exp               |  2 ++
 4 files changed, 32 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..6937d39
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/non-contiguous-powerpc.ld
@@ -0,0 +1,18 @@
+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 7634891..eeb460d 100644
--- a/ld/testsuite/ld-powerpc/powerpc.exp
+++ b/ld/testsuite/ld-powerpc/powerpc.exp
@@ -410,3 +410,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 65fb590a60aef51a7e3e9f8df2b04fb7ada942a1 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.
	* elf32-arm.c (arm_build_one_stub): Add support for
	non_contiguous_regions.
	* emultempl/armelf.em (elf32_arm_add_stub_section): Add
	SEC_LINKER_CREATED flag.

	include/
	* bfdlink.h (bfd_link_info): Add non_contiguous_regions field.

	ld/
	* ldlang.c (lang_add_section): Add support for
	non_contiguous_regions.
	(size_input_section): Likewise.
	(lang_size_sections_1): Likewise.
	* ldlex.h (option_values): Add OPTION_NON_CONTIGUOUS_REGIONS.
	* lexsup.c (ld_options): Add entry for
	--enable-non-contiguous-regions.
	(parse_args): Handle it.

Change-Id: Iac2f395b3a1fbea4b3a732ba5a9b847e10b4b2f0
---
 bfd/bfd-in2.h          |   9 +++-
 bfd/elf32-arm.c        |  11 +++++
 bfd/section.c          |   9 +++-
 include/bfdlink.h      |   3 ++
 ld/emultempl/armelf.em |   3 +-
 ld/ldlang.c            | 116 +++++++++++++++++++++++++++++++++++++++++++++++--
 ld/ldlex.h             |   1 +
 ld/lexsup.c            |   5 +++
 8 files changed, 150 insertions(+), 7 deletions(-)

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index a00dfa35..0e1126c 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1177,6 +1177,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
@@ -1358,7 +1362,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/elf32-arm.c b/bfd/elf32-arm.c
index dca208f..7b6b7a6 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 (_("No output section assigned to %pA. "
+	       "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/section.c b/bfd/section.c
index 34e08ae..b1f0b71 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -536,6 +536,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
@@ -717,7 +721,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 32d1512..e1e7c1e 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -501,6 +501,9 @@ 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;
+
   /* 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/emultempl/armelf.em b/ld/emultempl/armelf.em
index 9a1bc9a..445977b 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/ldlang.c b/ld/ldlang.c
index eedcb7f..75dc5b1 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -2550,7 +2550,14 @@ 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 affected 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
@@ -5109,11 +5116,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;
@@ -5145,6 +5168,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;
 
@@ -5152,6 +5212,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;
@@ -5436,10 +5504,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:
@@ -5864,7 +5936,7 @@ lang_size_sections_1
 		  *relax = TRUE;
 	      }
 	    dot = size_input_section (prev, output_section_statement,
-				      fill, dot);
+				      fill, &removed, dot);
 	  }
 	  break;
 
@@ -5969,7 +6041,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 32a7a64..4e7a419 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -150,6 +150,7 @@ enum option_values
   OPTION_FORCE_GROUP_ALLOCATION,
   OPTION_PRINT_MAP_DISCARDED,
   OPTION_NO_PRINT_MAP_DISCARDED,
+  OPTION_NON_CONTIGUOUS_REGIONS,
 };
 
 /* The initial parser states.  */
diff --git a/ld/lexsup.c b/ld/lexsup.c
index d7766c3..13cab6d 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -122,6 +122,8 @@ 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 },
   { {"EB", no_argument, NULL, OPTION_EB},
     '\0', NULL, N_("Link big-endian objects"), ONE_DASH },
   { {"EL", no_argument, NULL, OPTION_EL},
@@ -845,6 +847,9 @@ 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 'e':
 	  lang_add_entry (optarg, TRUE);
 	  break;
-- 
2.7.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]