Skip to content

Commit 5612518

Browse files
committed
Fix: Add separate linkerscripts for rv32 and rv64
1 parent 01711b7 commit 5612518

File tree

4 files changed

+194
-71
lines changed

4 files changed

+194
-71
lines changed

riscv-rt/build.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,17 @@ use std::env;
55
use std::fs;
66
use std::path::PathBuf;
77

8+
fn add_linker_script(bytes: &[u8]) {
9+
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
10+
11+
// Put the linker script somewhere the linker can find it
12+
fs::write(out_dir.join("link.x"), bytes).unwrap();
13+
println!("cargo:rustc-link-search={}", out_dir.display());
14+
println!("cargo:rerun-if-changed=link.x");
15+
}
16+
817
fn main() {
918
let target = env::var("TARGET").unwrap();
10-
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
1119
let _name = env::var("CARGO_PKG_NAME").unwrap();
1220

1321
// set configuration flags depending on the target
@@ -17,19 +25,16 @@ fn main() {
1725
match target.bits {
1826
32 => {
1927
println!("cargo:rustc-cfg=riscv32");
28+
add_linker_script(include_bytes!("link-rv32.x"));
2029
}
2130
64 => {
2231
println!("cargo:rustc-cfg=riscv64");
32+
add_linker_script(include_bytes!("link-rv64.x"));
2333
}
2434
_ => panic!("Unsupported bit width"),
2535
}
2636
if target.has_extension('m') {
2737
println!("cargo:rustc-cfg=riscvm"); // we can expose extensions this way
2838
}
2939
}
30-
31-
// Put the linker script somewhere the linker can find it
32-
fs::write(out_dir.join("link.x"), include_bytes!("link.x")).unwrap();
33-
println!("cargo:rustc-link-search={}", out_dir.display());
34-
println!("cargo:rerun-if-changed=link.x");
3540
}

riscv-rt/link.x renamed to riscv-rt/link-rv32.x

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,6 @@ BUG(riscv-rt): .data is not 4-byte aligned");
150150
ASSERT(_sidata % 4 == 0, "
151151
BUG(riscv-rt): the LMA of .data is not 4-byte aligned");
152152

153-
/* Make sure that we can safely perform .data initialization on RV64 */
154-
ASSERT(_sidata % 8 == _sdata % 8, "
155-
BUG(riscv-rt): .data is not similarly 8-byte aligned to the LMA of .data");
156-
157153
ASSERT(_sbss % 4 == 0 && _ebss % 4 == 0, "
158154
BUG(riscv-rt): .bss is not 4-byte aligned");
159155

riscv-rt/link-rv64.x

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
PROVIDE(_stext = ORIGIN(REGION_TEXT));
2+
PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK));
3+
PROVIDE(_max_hart_id = 0);
4+
PROVIDE(_hart_stack_size = 2K);
5+
PROVIDE(_heap_size = 0);
6+
7+
PROVIDE(UserSoft = DefaultHandler);
8+
PROVIDE(SupervisorSoft = DefaultHandler);
9+
PROVIDE(MachineSoft = DefaultHandler);
10+
PROVIDE(UserTimer = DefaultHandler);
11+
PROVIDE(SupervisorTimer = DefaultHandler);
12+
PROVIDE(MachineTimer = DefaultHandler);
13+
PROVIDE(UserExternal = DefaultHandler);
14+
PROVIDE(SupervisorExternal = DefaultHandler);
15+
PROVIDE(MachineExternal = DefaultHandler);
16+
17+
PROVIDE(DefaultHandler = DefaultInterruptHandler);
18+
PROVIDE(ExceptionHandler = DefaultExceptionHandler);
19+
20+
/* # Pre-initialization function */
21+
/* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function,
22+
then the function this points to will be called before the RAM is initialized. */
23+
PROVIDE(__pre_init = default_pre_init);
24+
25+
/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */
26+
PROVIDE(_setup_interrupts = default_setup_interrupts);
27+
28+
/* # Multi-processing hook function
29+
fn _mp_hook() -> bool;
30+
31+
This function is called from all the harts and must return true only for one hart,
32+
which will perform memory initialization. For other harts it must return false
33+
and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
34+
*/
35+
PROVIDE(_mp_hook = default_mp_hook);
36+
37+
/* # Start trap function override
38+
By default uses the riscv crates default trap handler
39+
but by providing the `_start_trap` symbol external crates can override.
40+
*/
41+
PROVIDE(_start_trap = default_start_trap);
42+
43+
SECTIONS
44+
{
45+
.text.dummy (NOLOAD) :
46+
{
47+
/* This section is intended to make _stext address work */
48+
. = ABSOLUTE(_stext);
49+
} > REGION_TEXT
50+
51+
.text _stext :
52+
{
53+
/* Put reset handler first in .text section so it ends up as the entry */
54+
/* point of the program. */
55+
KEEP(*(.init));
56+
KEEP(*(.init.rust));
57+
. = ALIGN(4);
58+
*(.trap);
59+
*(.trap.rust);
60+
*(.text.abort);
61+
*(.text .text.*);
62+
} > REGION_TEXT
63+
64+
.rodata : ALIGN(4)
65+
{
66+
*(.srodata .srodata.*);
67+
*(.rodata .rodata.*);
68+
69+
/* 4-byte align the end (VMA) of this section.
70+
This is required by LLD to ensure the LMA of the following .data
71+
section will have the correct alignment. */
72+
. = ALIGN(4);
73+
} > REGION_RODATA
74+
75+
.data : ALIGN(8)
76+
{
77+
_sidata = LOADADDR(.data);
78+
_sdata = .;
79+
/* Must be called __global_pointer$ for linker relaxations to work. */
80+
PROVIDE(__global_pointer$ = . + 0x800);
81+
*(.sdata .sdata.* .sdata2 .sdata2.*);
82+
*(.data .data.*);
83+
. = ALIGN(8);
84+
_edata = .;
85+
} > REGION_DATA AT > REGION_RODATA
86+
87+
.bss (NOLOAD) : ALIGN(8)
88+
{
89+
_sbss = .;
90+
*(.sbss .sbss.* .bss .bss.*);
91+
. = ALIGN(8);
92+
_ebss = .;
93+
} > REGION_BSS
94+
95+
/* fictitious region that represents the memory available for the heap */
96+
.heap (NOLOAD) :
97+
{
98+
_sheap = .;
99+
. += _heap_size;
100+
. = ALIGN(4);
101+
_eheap = .;
102+
} > REGION_HEAP
103+
104+
/* fictitious region that represents the memory available for the stack */
105+
.stack (NOLOAD) :
106+
{
107+
_estack = .;
108+
. = ABSOLUTE(_stack_start);
109+
_sstack = .;
110+
} > REGION_STACK
111+
112+
/* fake output .got section */
113+
/* Dynamic relocations are unsupported. This section is only used to detect
114+
relocatable code in the input files and raise an error if relocatable code
115+
is found */
116+
.got (INFO) :
117+
{
118+
KEEP(*(.got .got.*));
119+
}
120+
121+
.eh_frame (INFO) : { KEEP(*(.eh_frame)) }
122+
.eh_frame_hdr (INFO) : { *(.eh_frame_hdr) }
123+
}
124+
125+
/* Do not exceed this mark in the error messages above | */
126+
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
127+
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
128+
129+
ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, "
130+
ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned");
131+
132+
ASSERT(ORIGIN(REGION_DATA) % 8 == 0, "
133+
ERROR(riscv-rt): the start of the REGION_DATA must be 8-byte aligned");
134+
135+
ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, "
136+
ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned");
137+
138+
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
139+
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
140+
141+
ASSERT(ORIGIN(REGION_STACK) % 4 == 0, "
142+
ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned");
143+
144+
ASSERT(_stext % 4 == 0, "
145+
ERROR(riscv-rt): `_stext` must be 4-byte aligned");
146+
147+
ASSERT(_sdata % 8 == 0 && _edata % 8 == 0, "
148+
BUG(riscv-rt): .data is not 8-byte aligned");
149+
150+
ASSERT(_sidata % 8 == 0, "
151+
BUG(riscv-rt): the LMA of .data is not 8-byte aligned");
152+
153+
ASSERT(_sbss % 8 == 0 && _ebss % 8 == 0, "
154+
BUG(riscv-rt): .bss is not 8-byte aligned");
155+
156+
ASSERT(_sheap % 4 == 0, "
157+
BUG(riscv-rt): start of .heap is not 4-byte aligned");
158+
159+
ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), "
160+
ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region.
161+
Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'");
162+
163+
ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, "
164+
ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts.
165+
Consider changing `_max_hart_id` or `_hart_stack_size`.");
166+
167+
ASSERT(SIZEOF(.got) == 0, "
168+
.got section detected in the input files. Dynamic relocations are not
169+
supported. If you are linking to C code compiled using the `gcc` crate
170+
then modify your build script to compile the C code _without_ the
171+
-fPIC flag. See the documentation of the `gcc::Config.fpic` method for
172+
details.");
173+
174+
/* Do not exceed this mark in the error messages above | */

riscv-rt/src/lib.rs

Lines changed: 9 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! {
435435
436436
2:
437437
li {a},0
438+
li {input},0
438439
439440
// Zero out .bss
440441
la {start},_sbss
@@ -449,7 +450,6 @@ pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! {
449450
3:
450451
li {start},0
451452
li {end},0
452-
li {input},0
453453
",
454454
start = out(reg) _,
455455
end = out(reg) _,
@@ -465,90 +465,38 @@ pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! {
465465
la {end},_edata
466466
la {input},_sidata
467467
468-
bgeu {start},{end},3f
469-
470-
// If _sdata and _sidata are not 8-byte aligned, we copy one word before the main loop. This way, in
471-
// the main loop, we are sure `start` and `input` are 8-byte aligned. This is needed to safely
472-
// perform load and store double instructions.
473-
//
474-
// NOTE: We assert in the `link.x` file that _sdata and _sidata are similarly 8-byte aligned. This is
475-
// needed for the main loop here.
476-
andi {b},{start},4
477-
beqz {b},0f
478-
lw {a},0({input})
479-
addi {input},{input},4
480-
sw {a},0({start})
481-
addi {start},{start},4
482-
483-
0: // .data Main Loop Initialization
484-
// b = FLOOR_ALIGN(_edata, 4)
485-
andi {b},{end},4
486-
sub {b},{end},{b}
487-
488-
bgeu {start},{b},2f
468+
bgeu {start},{end},2f
469+
489470
1: // .data Main Loop
490471
ld {a},0({input})
491472
addi {input},{input},8
492473
sd {a},0({start})
493474
addi {start},{start},8
494-
bltu {start},{b},1b
495-
496-
2: // .data end align
497-
// If _edata is not 8-byte aligned, we copy one word after the main loop. This way we are sure we
498-
// copied all the data even if _edata is 4-byte aligned.
499-
andi {b},{end},4
500-
beqz {b},3f
501-
lw {a},0({input})
502-
addi {input},{input},4
503-
sw {a},0({start})
504-
addi {start},{start},4
475+
bltu {start},{end},1b
505476
506-
3: // .data zero registers
477+
2: // .data zero registers
507478
li {a},0
508479
li {input},0
509480
510-
4: // zero out .bss start
511481
la {start},_sbss
512482
la {end},_ebss
513483
514-
bgeu {start},{end},8f
484+
bgeu {start},{end},4f
515485
516-
// If _sbss is not 8-byte aligned, we zero one word before the main loop. This way, in the main
517-
// loop, we are sure `start` is 8-byte aligned. This is needed to safely perform store double
518-
// instruction.
519-
andi {b},{start},4
520-
beqz {b},5f
521-
sw zero,0({start})
522-
addi {start},{start},4
523-
524-
5: // .bss main loop initialization
525-
// b = FLOOR_ALIGN(_ebss, 4)
526-
andi {b},{end},4
527-
sub {b},{end},{b}
528-
529-
bgeu {start},{b},7f
530-
6: // .bss main loop
486+
3: // .bss main loop
531487
sd zero,0({start})
532488
addi {start},{start},8
533-
bltu {start},{b},6b
534-
535-
7: // .bss end align
536-
// If _ebss is not 8-byte aligned, we need to zero more one word after the main loop.
537-
andi {b},{end},4
538-
beqz {b},8f
539-
sw zero,0({start})
489+
bltu {start},{end},3b
540490
541-
8: // .bss zero registers
491+
4: // .bss zero registers
542492
// Zero out used registers
543-
li {b},0
544493
li {start},0
545494
li {end},0
546495
",
547496
start = out(reg) _,
548497
end = out(reg) _,
549498
input = out(reg) _,
550499
a = out(reg) _,
551-
b = out(reg) _,
552500
);
553501

554502
compiler_fence(Ordering::SeqCst);

0 commit comments

Comments
 (0)