aboutsummaryrefslogtreecommitdiff
path: root/arch/src/armv7-m/ld.S
blob: 9b237cca98248c898b6e0be4642af7841da1be7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
 * Arm SCP/MCP Software
 * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 * Description:
 *      GNU LD linker script.
 */

#include "scatter.h"

ENTRY(arch_exception_reset)

MEMORY {
#if FMW_MEM_MODE == ARCH_MEM_MODE_SINGLE_REGION
    /*
     * Single region memory layout:
     *  - MEM0 accepts:
     *      - Read-only sections
     *      - Read-write sections
     *      - Executable sections
     */

    mem0 (rwx) : ORIGIN = FMW_MEM0_BASE, LENGTH = FMW_MEM0_SIZE
#elif FMW_MEM_MODE == ARCH_MEM_MODE_DUAL_REGION_RELOCATION
    /*
     * Dual region memory layout with initialized data relocation:
     *  - MEM0 accepts:
     *      - Read-only sections
     *      - Executable sections
     *
     *  - MEM1 accepts:
     *      - Read-write sections
     */

    mem0 (rx) : ORIGIN = FMW_MEM0_BASE, LENGTH = FMW_MEM0_SIZE
    mem1 (w) : ORIGIN = FMW_MEM1_BASE, LENGTH = FMW_MEM1_SIZE
#elif FMW_MEM_MODE == ARCH_MEM_MODE_DUAL_REGION_NO_RELOCATION
    /*
     * Dual region memory layout without initialized data relocation:
     *  - MEM0 accepts:
     *      - Executable sections
     *
     *  - MEM1 accepts:
     *      - Read-only sections
     *      - Read-write sections
     */

    mem0 (x) : ORIGIN = FMW_MEM0_BASE, LENGTH = FMW_MEM0_SIZE
    mem1 (rw) : ORIGIN = FMW_MEM1_BASE, LENGTH = FMW_MEM1_SIZE
#endif
}

#if FMW_MEM_MODE == ARCH_MEM_MODE_SINGLE_REGION
    REGION_ALIAS("r", mem0);
    REGION_ALIAS("w", mem0);
    REGION_ALIAS("x", mem0);
#elif FMW_MEM_MODE == ARCH_MEM_MODE_DUAL_REGION_RELOCATION
    REGION_ALIAS("r", mem0);
    REGION_ALIAS("w", mem1);
    REGION_ALIAS("x", mem0);
#elif FMW_MEM_MODE == ARCH_MEM_MODE_DUAL_REGION_NO_RELOCATION
    REGION_ALIAS("r", mem1);
    REGION_ALIAS("w", mem1);
    REGION_ALIAS("x", mem0);
#endif

SECTIONS {
    /*
     * Variables defined here:
     *   - __data_load__: Load address of .data
     *   - __data_start__: Start address of .data
     *   - __data_end__: End address of .data and .data-like orphans
     *   - __bss_start__: Start address of .bss
     *   - __bss_end__: End address of .bss and .bss-like orphans
     *   - __stackheap_start__: Start address of .stackheap
     *   - __stackheap_end__: End address of .stackheap
     *   - __stack: Initial stack pointer
     */

    .exceptions : {
        KEEP(*(.exceptions))
    } > x

    .text : {
        *(.text .text.*)
    } > x

    /*
     * .init and .fini below refer to sections containing functions meant to
     * run before program startup and after program shutdown. While we don't use
     * these functions, Newlib refers to them unconditionally and they are,
     * perhaps counterintuitively, stripped from the binary unless marked as
     * KEEP.
     */

    .init : {
        KEEP(*(.init))
    } > x

    .fini : {
        KEEP(*(.fini))
    } > x

    .init_array : {
        __init_array_start = .;
        KEEP(*(.init_array))
        __init_array_end = .;
    } > r

    .rodata : {
        *(.rodata .rodata.*)
    } > r

    .data : {
        __data_load__ = LOADADDR(.data);
        __data_start__ = ABSOLUTE(.);

        *(.data .data.*)
    } > w AT> r

    .bss (NOLOAD) : {
        __bss_start__ = ABSOLUTE(.);

        *(.bss .bss.*)
    } > w

    .stackheap (NOLOAD) : {
        __stackheap_start__ = ABSOLUTE(.);

        . = ORIGIN(w) + LENGTH(w);

        __stackheap_end__ = ABSOLUTE(.);
    } > w

    /*
     * By default the linker places orphan sections after the section with the
     * closest matching attributes. Calculating the end of a section based on
     * the beginning of the next one that we know about means we can include BSS
     * and DATA sections that we don't know about in these values.
     */

    __data_end__ = __bss_start__;
    __bss_end__ = __stackheap_start__;

    __stack = __stackheap_end__;
}