Improve vmlinux.lds.h support for arch specific linker scripts
authorSam Ravnborg <sam@ravnborg.org>
Sun, 7 Jun 2009 18:46:37 +0000 (20:46 +0200)
committerSam Ravnborg <sam@ravnborg.org>
Tue, 9 Jun 2009 21:02:22 +0000 (23:02 +0200)
To support alingment of the individual architecture specific linker scripts
provide a set of general definitions in vmlinux.lds.h

With these definitions applied the diverse linekr scripts can be reduced
in line count and their readability are improved - IMO.

A sample linker script is included to give the preferred
order of the sections for the architectures that do not
have any special requirments.

These definitions are also a first step towards eventual
support for -ffunction-sections.
The definitions makes it much easier to do a global
renaming of section names - but the main purpose is
to clean up the linker scripts.

Tim Aboot has provided a lot of inputs to improve
the definitions - all faults are mine.

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Cc: Tim Abbott <tabbott@mit.edu>
include/asm-generic/vmlinux.lds.h

index 3edb11499743b5ca67cf2e8f8cd05790fb180d4d..fba42236e9428207a10c5c06a977da4180dbd781 100644 (file)
@@ -1,4 +1,58 @@
-#include <linux/section-names.h>
+/*
+ * Helper macros to support writing architecture specific
+ * linker scripts.
+ *
+ * A minimal linker scripts has following content:
+ * [This is a sample, architectures may have special requiriements]
+ *
+ * OUTPUT_FORMAT(...)
+ * OUTPUT_ARCH(...)
+ * ENTRY(...)
+ * SECTIONS
+ * {
+ *     . = START;
+ *     __init_begin = .;
+ *     HEAD_SECTION
+ *     INIT_TEXT_SECTION(PAGE_SIZE)
+ *     INIT_DATA_SECTION(...)
+ *     PERCPU(PAGE_SIZE)
+ *     __init_end = .;
+ *
+ *     _stext = .;
+ *     TEXT_SECTION = 0
+ *     _etext = .;
+ *
+ *      _sdata = .;
+ *     RO_DATA_SECTION(PAGE_SIZE)
+ *     RW_DATA_SECTION(...)
+ *     _edata = .;
+ *
+ *     EXCEPTION_TABLE(...)
+ *     NOTES
+ *
+ *     __bss_start = .;
+ *     BSS_SECTION(0, 0)
+ *     __bss_stop = .;
+ *     _end = .;
+ *
+ *     /DISCARD/ : {
+ *             EXIT_TEXT
+ *             EXIT_DATA
+ *             *(.exitcall.exit)
+ *     }
+ *     STABS_DEBUG
+ *     DWARF_DEBUG
+ * }
+ *
+ * [__init_begin, __init_end] is the init section that may be freed after init
+ * [_stext, _etext] is the text section
+ * [_sdata, _edata] is the data section
+ *
+ * Some of the included output section have their own set of constants.
+ * Examples are: [__initramfs_start, __initramfs_end] for initramfs and
+ *               [__nosave_begin, __nosave_end] for the nosave data
+ */
+ #include <linux/section-names.h>
 
 #ifndef LOAD_OFFSET
 #define LOAD_OFFSET 0
        FTRACE_EVENTS()                                                 \
        TRACE_SYSCALLS()
 
-#define RO_DATA(align)                                                 \
+/*
+ * Data section helpers
+ */
+#define NOSAVE_DATA                                                    \
+       . = ALIGN(PAGE_SIZE);                                           \
+       VMLINUX_SYMBOL(__nosave_begin) = .;                             \
+       *(.data.nosave)                                                 \
+       . = ALIGN(PAGE_SIZE);                                           \
+       VMLINUX_SYMBOL(__nosave_end) = .;
+
+#define PAGE_ALIGNED_DATA(page_align)                                  \
+       . = ALIGN(page_align);                                          \
+       *(.data.page_aligned)
+
+#define READ_MOSTLY_DATA(align)                                                \
+       . = ALIGN(align);                                               \
+       *(.data.read_mostly)
+
+#define CACHELINE_ALIGNED_DATA(align)                                  \
+       . = ALIGN(align);                                               \
+       *(.data.cacheline_aligned)
+
+#define INIT_TASK(align)                                               \
+       . = ALIGN(align);                                               \
+       *(.data.init_task)
+
+/*
+ * Read only Data
+ */
+#define RO_DATA_SECTION(align)                                         \
        . = ALIGN((align));                                             \
        .rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {           \
                VMLINUX_SYMBOL(__start_rodata) = .;                     \
        }                                                               \
        . = ALIGN((align));
 
-/* RODATA provided for backward compatibility.
+/* RODATA & RO_DATA provided for backward compatibility.
  * All archs are supposed to use RO_DATA() */
-#define RODATA RO_DATA(4096)
+#define RODATA          RO_DATA_SECTION(4096)
+#define RO_DATA(align)  RO_DATA_SECTION(align)
 
 #define SECURITY_INIT                                                  \
        .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \
 /* Section used for early init (in .S files) */
 #define HEAD_TEXT  *(HEAD_TEXT_SECTION)
 
+#define HEAD_SECTION                                                   \
+       .head.text : AT(ADDR(.head.text) - LOAD_OFFSET) {               \
+               HEAD_TEXT                                               \
+       }
+
+/*
+ * Exception table
+ */
+#define EXCEPTION_TABLE(align)                                         \
+       . = ALIGN(align);                                               \
+       __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {               \
+               VMLINUX_SYMBOL(__start___ex_table) = .;                 \
+               *(__ex_table)                                           \
+               VMLINUX_SYMBOL(__stop___ex_table) = .;                  \
+       }
+
+/*
+ * Init task
+ */
+#define INIT_TASK_DATA(align)                                          \
+       . = ALIGN(align);                                               \
+       .data.init_task : {                                             \
+               INIT_TASK                                               \
+       }
+
 /* init and exit section handling */
 #define INIT_DATA                                                      \
        *(.init.data)                                                   \
        CPU_DISCARD(exit.text)                                          \
        MEM_DISCARD(exit.text)
 
-               /* DWARF debug sections.
-               Symbols in the DWARF debugging sections are relative to
-               the beginning of the section so we begin them at 0.  */
+/*
+ * bss (Block Started by Symbol) - uninitialized data
+ * zeroed during startup
+ */
+#define SBSS                                                           \
+       .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) {                         \
+               *(.sbss)                                                \
+               *(.scommon)                                             \
+       }
+
+#define BSS(bss_align)                                                 \
+       . = ALIGN(bss_align);                                           \
+       .bss : AT(ADDR(.bss) - LOAD_OFFSET) {                           \
+               VMLINUX_SYMBOL(__bss_start) = .;                        \
+               *(.bss.page_aligned)                                    \
+               *(.dynbss)                                              \
+               *(.bss)                                                 \
+               *(COMMON)                                               \
+               VMLINUX_SYMBOL(__bss_stop) = .;                         \
+       }
+
+/*
+ * DWARF debug sections.
+ * Symbols in the DWARF debugging sections are relative to
+ * the beginning of the section so we begin them at 0.
+ */
 #define DWARF_DEBUG                                                    \
                /* DWARF 1 */                                           \
                .debug          0 : { *(.debug) }                       \
                VMLINUX_SYMBOL(__stop_notes) = .;                       \
        }
 
+#define INIT_SETUP(initsetup_align)                                    \
+               . = ALIGN(initsetup_align);                             \
+               VMLINUX_SYMBOL(__setup_start) = .;                      \
+               *(.init.setup)                                          \
+               VMLINUX_SYMBOL(__setup_end) = .;
+
 #define INITCALLS                                                      \
        *(.initcallearly.init)                                          \
        VMLINUX_SYMBOL(__early_initcall_end) = .;                       \
        *(.initcall7.init)                                              \
        *(.initcall7s.init)
 
+#define INIT_CALLS                                                     \
+               VMLINUX_SYMBOL(__initcall_start) = .;                   \
+               INITCALLS                                               \
+               VMLINUX_SYMBOL(__initcall_end) = .;
+
+#define CON_INITCALL                                                   \
+               VMLINUX_SYMBOL(__con_initcall_start) = .;               \
+               *(.con_initcall.init)                                   \
+               VMLINUX_SYMBOL(__con_initcall_end) = .;
+
+#define SECURITY_INITCALL                                              \
+               VMLINUX_SYMBOL(__security_initcall_start) = .;          \
+               *(.security_initcall.init)                              \
+               VMLINUX_SYMBOL(__security_initcall_end) = .;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+#define INIT_RAM_FS                                                    \
+       . = ALIGN(PAGE_SIZE);                                           \
+       VMLINUX_SYMBOL(__initramfs_start) = .;                          \
+       *(.init.ramfs)                                                  \
+       VMLINUX_SYMBOL(__initramfs_end) = .;
+#else
+#define INITRAMFS
+#endif
+
 /**
  * PERCPU_VADDR - define output section for percpu area
  * @vaddr: explicit base address (optional)
                *(.data.percpu.shared_aligned)                          \
                VMLINUX_SYMBOL(__per_cpu_end) = .;                      \
        }
+
+
+/*
+ * Definition of the high level *_SECTION macros
+ * They will fit only a subset of the architectures
+ */
+
+
+/*
+ * Writeable data.
+ * All sections are combined in a single .data section.
+ * The sections following CONSTRUCTORS are arranged so their
+ * typical alignment matches.
+ * A cacheline is typical/always less than a PAGE_SIZE so
+ * the sections that has this restriction (or similar)
+ * is located before the ones requiring PAGE_SIZE alignment.
+ * NOSAVE_DATA starts and ends with a PAGE_SIZE alignment which
+ * matches the requirment of PAGE_ALIGNED_DATA.
+ *
+/* use 0 as page_align if page_aligned data is not used */
+#define RW_DATA_SECTION(cacheline, nosave, pagealigned, inittask)      \
+       . = ALIGN(PAGE_SIZE);                                           \
+       .data : AT(ADDR(.data) - LOAD_OFFSET) {                         \
+               INIT_TASK(inittask)                                     \
+               CACHELINE_ALIGNED_DATA(cacheline)                       \
+               READ_MOSTLY_DATA(cacheline)                             \
+               DATA_DATA                                               \
+               CONSTRUCTORS                                            \
+               NOSAVE_DATA(nosave)                                     \
+               PAGE_ALIGNED_DATA(pagealigned)                          \
+       }
+
+#define INIT_TEXT_SECTION(inittext_align)                              \
+       . = ALIGN(inittext_align);                                      \
+       .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {               \
+               VMLINUX_SYMBOL(_sinittext) = .;                         \
+               INIT_TEXT                                               \
+               VMLINUX_SYMBOL(_einittext) = .;                         \
+       }
+
+#define INIT_DATA_SECTION(initsetup_align)                             \
+       .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {               \
+               INIT_DATA                                               \
+               INIT_SETUP(initsetup_align)                             \
+               INIT_CALLS                                              \
+               CON_INITCALL                                            \
+               SECURITY_INITCALL                                       \
+               INIT_RAM_FS                                             \
+       }
+
+#define BSS_SECTION(sbss_align, bss_align)                             \
+       SBSS                                                            \
+       BSS(bss_align)                                                  \
+       . = ALIGN(4);                                                   \