aboutsummaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorRussell King2011-09-20 23:35:15 +0100
committerRussell King2011-09-20 23:42:31 +0100
commit6760b109603c794e4bd281c0014fef069c019b6a (patch)
treef0656ff7de073301d75200264d672282e6b7f558 /arch/arm
parent4dfa33868d9f8595717047eb058322e0999691cc (diff)
ARM: fix vmlinux.lds.S discarding sections
We are seeing linker errors caused by sections being discarded, despite the linker script trying to keep them. The result is (eg): `.exit.text' referenced in section `.alt.smp.init' of drivers/built-in.o: defined in discarded section `.exit.text' of drivers/built-in.o `.exit.text' referenced in section `.alt.smp.init' of net/built-in.o: defined in discarded section `.exit.text' of net/built-in.o This is the relevent part of the linker script (reformatted to make it clearer): | SECTIONS | { | /* | * unwind exit sections must be discarded before the rest of the | * unwind sections get included. | */ | /DISCARD/ : { | *(.ARM.exidx.exit.text) | *(.ARM.extab.exit.text) | } | ... | .exit.text : { | *(.exit.text) | *(.memexit.text) | } | ... | /DISCARD/ : { | *(.exit.text) | *(.memexit.text) | *(.exit.data) | *(.memexit.data) | *(.memexit.rodata) | *(.exitcall.exit) | *(.discard) | *(.discard.*) | } | } Now, this is what the linker manual says about discarded output sections: | The special output section name `/DISCARD/' may be used to discard | input sections. Any input sections which are assigned to an output | section named `/DISCARD/' are not included in the output file. No questions, no exceptions. It doesn't say "unless they are listed before the /DISCARD/ section." Now, this is what asn-generic/vmlinux.lds.S says: | /* | * Default discarded sections. | * | * Some archs want to discard exit text/data at runtime rather than | * link time due to cross-section references such as alt instructions, | * bug table, eh_frame, etc. DISCARDS must be the last of output | * section definitions so that such archs put those in earlier section | * definitions. | */ And guess what - the list _always_ includes .exit.text etc. Now, what's actually happening is that the linker is reading the script, and it finds the first /DISCARD/ output section at the beginning of the script. It continues reading the script, and finds the 'DISCARD' macro at the end, which having been postprocessed results in another /DISCARD/ output section. As the linker already contains the earlier /DISCARD/ output section, it adds it to that existing section, so it effectively is placed at the start. This can be seen by using the -M option to ld: | Linker script and memory map | | 0xc037c080 jiffies = jiffies_64 | | /DISCARD/ | *(.ARM.exidx.exit.text) | *(.ARM.extab.exit.text) | *(.exit.text) | *(.memexit.text) | *(.exit.data) | *(.memexit.data) | *(.memexit.rodata) | *(.exitcall.exit) | *(.discard) | *(.discard.*) | | 0xc0008000 . = 0xc0008000 | | .head.text 0xc0008000 0x1d0 | 0xc0008000 _text = . | *(.head.text) | .head.text 0xc0008000 0x1d0 arch/arm/kernel/head.o | 0xc0008000 stext | | .text 0xc0008200 0x2d78d0 | 0xc0008200 _stext = . | 0xc0008200 __exception_text_start = . | *(.exception.text) | .exception.text | ... As you can see, all the discarded sections are grouped together - and as a result of it being the first output section, they all appear before any other section. The result is that not only is the unwind information discarded (as intended), but also the .exit.text, despite us wanting to have the .exit.text preserved. We can't move the unwind information elsewhere, because it'll then be included even when we do actually discard the .exit.text (and similar) sections. So, work around this by avoiding the generic DISCARDS macro, and instead conditionalize the sections to be discarded ourselves. This avoids the ambiguity in how the linker assigns input sections to output sections, making our script less dependent on undocumented linker behaviour. Reported-by: Rob Herring <robherring2@gmail.com> Tested-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/kernel/vmlinux.lds.S15
1 files changed, 12 insertions, 3 deletions
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index bf977f8514f6..4e66f62b8d41 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -23,8 +23,10 @@
#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)
#define ARM_EXIT_KEEP(x) x
+#define ARM_EXIT_DISCARD(x)
#else
#define ARM_EXIT_KEEP(x)
+#define ARM_EXIT_DISCARD(x) x
#endif
OUTPUT_ARCH(arm)
@@ -39,6 +41,11 @@ jiffies = jiffies_64 + 4;
SECTIONS
{
/*
+ * XXX: The linker does not define how output sections are
+ * assigned to input sections when there are multiple statements
+ * matching the same input section name. There is no documented
+ * order of matching.
+ *
* unwind exit sections must be discarded before the rest of the
* unwind sections get included.
*/
@@ -47,6 +54,9 @@ SECTIONS
*(.ARM.extab.exit.text)
ARM_CPU_DISCARD(*(.ARM.exidx.cpuexit.text))
ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text))
+ ARM_EXIT_DISCARD(EXIT_TEXT)
+ ARM_EXIT_DISCARD(EXIT_DATA)
+ EXIT_CALL
#ifndef CONFIG_HOTPLUG
*(.ARM.exidx.devexit.text)
*(.ARM.extab.devexit.text)
@@ -58,6 +68,8 @@ SECTIONS
#ifndef CONFIG_SMP_ON_UP
*(.alt.smp.init)
#endif
+ *(.discard)
+ *(.discard.*)
}
#ifdef CONFIG_XIP_KERNEL
@@ -279,9 +291,6 @@ SECTIONS
STABS_DEBUG
.comment 0 : { *(.comment) }
-
- /* Default discards */
- DISCARDS
}
/*