Skip to content

Commit 9654318

Browse files
Merge pull request #16 from itzandroidtab/linkerscript
changed so the linkerscript is passed through the preprocessor
2 parents 648d954 + 306ae58 commit 9654318

23 files changed

Lines changed: 430 additions & 1058 deletions

File tree

klib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# set the sources
22
set(SOURCES
33
${CMAKE_CURRENT_SOURCE_DIR}/entry/entry.c
4+
${CMAKE_CURRENT_SOURCE_DIR}/entry/secondary.cpp
45
)
56

67
set(HEADERS_PRIVATE

klib/entry/secondary.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include <stdint.h>
2+
3+
#pragma pack(push, 1)
4+
5+
/**
6+
* @brief Struct for memory segments that are loaded after the startup code is run
7+
*
8+
*/
9+
struct data_memory_segment_t {
10+
const uint32_t *rom_start;
11+
uint32_t *start;
12+
uint32_t *end;
13+
};
14+
15+
/**
16+
* @brief Struct for bss memory segments that are cleared after the startup code is run
17+
*
18+
*/
19+
struct bss_memory_segment_t {
20+
uint32_t *start;
21+
uint32_t *end;
22+
};
23+
24+
#pragma pack(pop)
25+
26+
extern "C" {
27+
// multisection data segment symbol
28+
extern const data_memory_segment_t __multisection_data_start;
29+
30+
// multisection bss segment symbol
31+
extern const bss_memory_segment_t __multisection_bss_start;
32+
}
33+
34+
namespace klib::entry {
35+
void secondary_memory_loader() {
36+
// loop over all data segments
37+
for (const data_memory_segment_t *segment = &__multisection_data_start; ; segment++) {
38+
// check if we have reached the end of the segments
39+
if (!segment->start && !segment->end && !segment->rom_start) {
40+
// invalid segment
41+
break;
42+
}
43+
44+
// get the length of the segment
45+
const uint32_t length = ((segment->end - segment->start) + (sizeof(uint32_t) - 1)) / sizeof(uint32_t);
46+
47+
// check if we have any length to copy
48+
if (!length) {
49+
continue;
50+
}
51+
52+
// copy rom to ram
53+
for (uint32_t i = 0; i < length; i++) {
54+
((volatile uint32_t*)segment->start)[i] = segment->rom_start[i];
55+
}
56+
}
57+
58+
// loop over all bss segments
59+
for (const bss_memory_segment_t *segment = &__multisection_bss_start; ; segment++) {
60+
// check if we have reached the end of the segments
61+
if (!segment->start && !segment->end) {
62+
// invalid segment
63+
break;
64+
}
65+
66+
// get the length of the segment
67+
const uint32_t length = ((segment->end - segment->start) + (sizeof(uint32_t) - 1)) / sizeof(uint32_t);
68+
69+
// check if we have any length to copy
70+
if (!length) {
71+
continue;
72+
}
73+
74+
// clear the bss segment
75+
for (uint32_t i = 0; i < length; i++) {
76+
((volatile uint32_t*)segment->start)[i] = 0x00;
77+
}
78+
}
79+
}
80+
}

klib/entry/secondary.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef KLIB_SECONDARY_HPP
2+
#define KLIB_SECONDARY_HPP
3+
4+
#include <cstdint>
5+
6+
namespace klib::entry {
7+
/**
8+
* @brief A secondary memory loader. This loader should be
9+
* called afer the memories are initialized by the user
10+
* code. Constructor(102) is reserved for this function.
11+
*
12+
*/
13+
void secondary_memory_loader();
14+
}
15+
16+
#endif

project/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# include the linkerscript generator needed to preprocess the linkerscripts
2+
include (${CMAKE_SOURCE_DIR}/targets/arm/linkerscript/linkerscript.cmake)
3+
14
# set the sources
25
set(SOURCES
36
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
@@ -40,8 +43,7 @@ target_link_libraries(klib_project PUBLIC target_cpu)
4043
target_link_libraries(klib_project PUBLIC m)
4144

4245
# link to the linkerscript of the target cpu
43-
target_link_options(klib_project PUBLIC "-T${TARGET_LINKERSCRIPT}")
44-
set_target_properties(klib_project PROPERTIES LINK_DEPENDS ${TARGET_LINKERSCRIPT})
46+
add_linkerscript(klib_project ${TARGET_LINKERSCRIPT} "")
4547

4648
# add the project directory to the include directories
4749
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# helper function to preprocess a linker script. This allows
2+
# using C preprocessor in the linkerscript files (including
3+
# macroes, conditionals, etc)
4+
function(add_linkerscript target linkerscript options)
5+
set(output "${CMAKE_BINARY_DIR}/linkerscript.ld")
6+
set(CURRENT_DIR "${CMAKE_SOURCE_DIR}/targets/arm/linkerscript")
7+
8+
# run the preprocessor on the linkerscript
9+
add_custom_command(
10+
OUTPUT ${output}
11+
# run the linkerscript through the C preprocessor. Force include the base linkerscript template.
12+
COMMAND ${CMAKE_C_COMPILER} -E -P -x c ${linkerscript} -o ${output} -include ${CURRENT_DIR}/linkerscript.ld ${options}
13+
DEPENDS ${linkerscript} ${CURRENT_DIR}/linkerscript.ld
14+
COMMENT "Preprocessing linker script ${linkerscript}"
15+
VERBATIM
16+
)
17+
18+
# create a custom target to generate the linkerscript
19+
add_custom_target(generate_linkerscript DEPENDS "${output}")
20+
add_dependencies(${target} generate_linkerscript)
21+
22+
# add the linkerscript to the target
23+
target_link_options(${target} PUBLIC "-T${output}")
24+
set_target_properties(${target} PROPERTIES LINK_DEPENDS ${output})
25+
endfunction()
26+
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/* helpers to combine strings with a parameter */
2+
#define COMBINE_STRX(a,b) a##b
3+
#define COMBINE_STR2(a,b) COMBINE_STRX(a,b)
4+
#define COMBINE_STR3(a,b,c) COMBINE_STR2(COMBINE_STR2(a,b),c)
5+
6+
/* helper macro to create a section */
7+
#define SECTION_IMPL(name, data) \
8+
.name : \
9+
{ \
10+
data \
11+
}
12+
13+
/* helper macro to create a section with a attribute */
14+
#define SECTION_IMPL_ATTR(name, attr, data) \
15+
.name (attr) : \
16+
{ \
17+
data \
18+
}
19+
20+
/* helper macro to create a alligned section */
21+
#define ALLIGNED_SECTION(name, align, data) \
22+
SECTION_IMPL( \
23+
name, \
24+
. = ALIGN(align); \
25+
data \
26+
)
27+
28+
/* helper macro to create a alligned readonly section */
29+
#define ALLIGNED_READONLY_SECTION(name, align, data) \
30+
SECTION_IMPL_ATTR( \
31+
name, \
32+
READONLY, \
33+
. = ALIGN(align); \
34+
data \
35+
)
36+
37+
/* macro to define the vectors section. Should be pointed to the correct memory region */
38+
#define VECTORS() \
39+
ALLIGNED_READONLY_SECTION( \
40+
vectors, 4, \
41+
KEEP(*(.vectors .vectors.*)); \
42+
)
43+
44+
/* macro to define the rodata section */
45+
#define RODATA() \
46+
ALLIGNED_READONLY_SECTION( \
47+
rodata, 4, \
48+
*(.rodata .rodata.* .gnu.linkonce.r.*); \
49+
)
50+
51+
/* macro to define the stack with a size in bytes */
52+
#define STACK(size) \
53+
.stack (NOLOAD) : \
54+
{ \
55+
. = ALIGN(4); \
56+
/* provide the __stack_start */ \
57+
PROVIDE(__stack_start = .); \
58+
/* add the size in bytes to the current address */ \
59+
. = . + size; \
60+
/* make sure the size is rounded off to 4 bytes */ \
61+
. = ALIGN(4); \
62+
/* provide the __stack_end */ \
63+
PROVIDE(__stack_end = .); \
64+
}
65+
66+
/* macro to define a init array. Array name is passed as an argument */
67+
#define CONSTRUCTOR_SECTION(name) \
68+
.name : \
69+
{ \
70+
. = ALIGN(4); \
71+
PROVIDE(COMBINE_STR3(__,name,_start) = .); \
72+
KEEP(*(SORT(.name.*))) \
73+
KEEP(*(SORT(.name))) \
74+
PROVIDE(COMBINE_STR3(__,name,_end) = .); \
75+
}
76+
77+
/* macro to define a data section. Note: this section is not automaticly loaded.
78+
The secondary loaded needs to be enabled to load this at startup after the
79+
startup code */
80+
#define DATA_SECTION(name, region, storage) \
81+
COMBINE_STR2(.name,_data) : \
82+
{ \
83+
. = ALIGN(4); \
84+
PROVIDE(COMBINE_STR3(__,name,_data_rom_start) = LOADADDR(COMBINE_STR2(.name,_data))); \
85+
PROVIDE(COMBINE_STR3(__,name,_data_start) = .); \
86+
*(SORT_BY_ALIGNMENT(COMBINE_STR2(.name,_data))); \
87+
*(SORT_BY_ALIGNMENT(COMBINE_STR2(.name,_data.*))); \
88+
. = ALIGN(4); \
89+
PROVIDE(COMBINE_STR3(__,name,_data_end) = .); \
90+
} > region AT > storage
91+
92+
/* data section entry for the multi section table */
93+
#define DATA_SECTION_ENTRY(name) \
94+
LONG(COMBINE_STR3(__,name,_data_rom_start)); \
95+
LONG(COMBINE_STR3(__,name,_data_start)); \
96+
LONG(COMBINE_STR3(__,name,_data_end));
97+
98+
/* end marker for the multi section table */
99+
#define DATA_SECTION_ENTRY_END() \
100+
LONG(0); \
101+
LONG(0); \
102+
LONG(0);
103+
104+
/* multisection table to automaticly load the data into the section location */
105+
#define DATA_MULTISECTION_TABLE(entries) \
106+
ALLIGNED_READONLY_SECTION( \
107+
multisection_data, 4, \
108+
PROVIDE(__multisection_data_start = .); \
109+
entries \
110+
PROVIDE(__multisection_data_end = .); \
111+
)
112+
113+
#define BSS_SECTION(name, region) \
114+
COMBINE_STR2(.name,_bss) (NOLOAD) : \
115+
{ \
116+
. = ALIGN(4); \
117+
PROVIDE(COMBINE_STR3(__,name,_bss_start) = .); \
118+
*(SORT_BY_ALIGNMENT(COMBINE_STR2(.name,_bss))); \
119+
*(SORT_BY_ALIGNMENT(COMBINE_STR2(.name,_bss.*))); \
120+
. = ALIGN(4); \
121+
PROVIDE(COMBINE_STR3(__,name,_bss_end) = .); \
122+
} > region
123+
124+
/* bss section entry for the multi section table */
125+
#define BSS_SECTION_ENTRY(name) \
126+
LONG(COMBINE_STR3(__,name,_bss_start)); \
127+
LONG(COMBINE_STR3(__,name,_bss_end));
128+
129+
/* end marker for the multi section table */
130+
#define BSS_SECTION_ENTRY_END() \
131+
LONG(0); \
132+
LONG(0);
133+
134+
/* multisection table to automaticly load all the bss sections to zero */
135+
#define BSS_MULTISECTION_TABLE(entries) \
136+
ALLIGNED_READONLY_SECTION( \
137+
multisection_bss, 4, \
138+
PROVIDE(__multisection_bss_start = .); \
139+
entries \
140+
PROVIDE(__multisection_bss_end = .); \
141+
)

targets/chip/atsam3x8e/linkerscript.ld

Lines changed: 7 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,10 @@ SECTIONS
3333
{
3434
/* Vector table. Has the initial stack pointer and the initial
3535
structure for the arm interrupts */
36-
.vectors :
37-
{
38-
. = ALIGN(4);
39-
/* vector table */
40-
KEEP(*(.vectors .vectors.*));
41-
. = ALIGN(4);
42-
} > rom
36+
VECTORS() > rom
4337

4438
/* Text segment, stores all user code */
45-
.text :
39+
.text (READONLY) :
4640
{
4741
. = ALIGN(4);
4842
/* text segment */
@@ -66,62 +60,16 @@ SECTIONS
6660
} > rom
6761

6862
/* Read only data */
69-
.rodata :
70-
{
71-
. = ALIGN(4);
72-
73-
/* Constands, strings, etc */
74-
*(.rodata .rodata.* .gnu.linkonce.r.*);
75-
76-
. = ALIGN(4);
77-
} > rom
63+
RODATA() > rom
7864

7965
/* Support C constructors, and C destructors in both user code
8066
and the C library. This also provides support for C++ code. */
81-
.preinit_array :
82-
{
83-
. = ALIGN(4);
84-
PROVIDE(__preinit_array_start = .);
85-
86-
KEEP(*(SORT(.preinit_array.*)))
87-
KEEP(*(SORT(.preinit_array)))
88-
89-
PROVIDE(__preinit_array_end = .);
90-
} > rom
91-
92-
.init_array :
93-
{
94-
. = ALIGN(4);
95-
PROVIDE(__init_array_start = .);
96-
97-
KEEP(*(SORT(.init_array.*)))
98-
KEEP(*(SORT(.init_array)))
99-
100-
PROVIDE(__init_array_end = .);
101-
} > rom
102-
103-
.fini_array :
104-
{
105-
. = ALIGN(4);
106-
PROVIDE(__fini_array_start = .);
107-
108-
KEEP(*(SORT(.fini_array.*)))
109-
KEEP(*(SORT(.fini_array)))
110-
111-
PROVIDE(__fini_array_end = .);
112-
} > rom
67+
CONSTRUCTOR_SECTION(preinit_array) > rom
68+
CONSTRUCTOR_SECTION(init_array) > rom
69+
CONSTRUCTOR_SECTION(fini_array) > rom
11370

11471
/* Stack segment */
115-
.stack (NOLOAD) :
116-
{
117-
. = ALIGN(4);
118-
PROVIDE(__stack_start = .);
119-
120-
. = . + STACK_SIZE;
121-
. = ALIGN(4);
122-
123-
PROVIDE(__stack_end = .);
124-
} > ram
72+
STACK(STACK_SIZE) > ram
12573

12674
/* Data that needs to be initialized to a value different than 0 */
12775
.data :

0 commit comments

Comments
 (0)