Skip to content

Commit 0811b16

Browse files
authored
Rollup merge of #145578 - vexide:armv7a-vex-v5+linked-files, r=davidtwco
Add VEXos "linked files" support to `armv7a-vex-v5` Third-party programs running on the VEX V5 platform need a linker script to ensure code and data are always placed in the allowed range `0x3800000-0x8000000` which is read/write/execute. However, developers can also configure the operating system (VEXos) to preload a separate file at any location between these two addresses before the program starts (as a sort of basic linking or configuration loading system). Programs have to know about this at compile time - in the linker script - to avoid placing data in a spot that overlaps where the linked file will be loaded. This is a very popular feature with existing V5 runtimes because it can be used to modify a program's behavior without re-uploading the entire binary to the robot controller. It's important for Rust to support this because while VEXos's runtime user-exposed file system APIs may only read data from an external SD card, linked files are allowed to load data directly from the device's onboard storage. This PR adds the `__linked_file_start` symbol to the existing VEX V5 linker script which can be used to shrink the stack and heap so that they do not overlap with a memory region containing a linked file. It expects the linked file to be loaded in the final N bytes of user RAM (this is not technically required but every existing runtime does it this way to avoid having discontinuous memory regions). With these changes, a developer targeting VEX V5 might add a second linker script to their project by specifying `-Clink-arg=-Tcustom.ld` and creating the file `custom.ld` to configure their custom memory layout. The linker would prepend this to the builtin target linker script. ```c /* custom.ld: Reserves 10MiB for a linked file. */ /* (0x7600000-0x8000000) */ __linked_file_length = 10M; /* The above line is equivalent to -Clink-arg=--defsym=__linked_file_length=10M */ /* Optional: specify one or more sections that */ /* represent the developer's custom format. */ SECTIONS { .linked_file_metadata (NOLOAD) : { __linked_file_metadata_start = .; . += 1M; __linked_file_metadata_end = .; } .linked_file_data (NOLOAD) : { __linked_file_data_start = .; . += 9M; __linked_file_data_end = .; } } INSERT AFTER .stack; ``` Then, using an external tool like the `vex-v5-serial` crate, they would configure the metadata of their uploaded program to specify the path of their linked file and the address where it should be loaded into memory (in the above example, `0x7600000`).
2 parents 4a4247a + 0e47f19 commit 0811b16

File tree

2 files changed

+26
-10
lines changed

2 files changed

+26
-10
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2435,6 +2435,13 @@ fn linker_with_args(
24352435
// Passed after compiler-generated options to support manual overriding when necessary.
24362436
add_user_defined_link_args(cmd, sess);
24372437

2438+
// ------------ Builtin configurable linker scripts ------------
2439+
// The user's link args should be able to overwrite symbols in the compiler's
2440+
// linker script that were weakly defined (i.e. defined with `PROVIDE()`). For this
2441+
// to work correctly, the user needs to be able to specify linker arguments like
2442+
// `--defsym` and `--script` *before* any builtin linker scripts are evaluated.
2443+
add_link_script(cmd, sess, tmpdir, crate_type);
2444+
24382445
// ------------ Object code and libraries, order-dependent ------------
24392446

24402447
// Post-link CRT objects.
@@ -2469,8 +2476,6 @@ fn add_order_independent_options(
24692476

24702477
let apple_sdk_root = add_apple_sdk(cmd, sess, flavor);
24712478

2472-
add_link_script(cmd, sess, tmpdir, crate_type);
2473-
24742479
if sess.target.os == "fuchsia"
24752480
&& crate_type == CrateType::Executable
24762481
&& !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))

compiler/rustc_target/src/spec/targets/armv7a_vex_v5_linker_script.ld

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,25 @@ PROVIDE(__vcodesig_type = 0); /* V5_SIG_TYPE_USER */
1717
PROVIDE(__vcodesig_owner = 2); /* V5_SIG_OWNER_PARTNER */
1818
PROVIDE(__vcodesig_options = 0); /* none (0) */
1919

20-
PROVIDE(__user_ram_start = 0x03800000);
21-
PROVIDE(__user_ram_length = 48M);
22-
PROVIDE(__user_ram_end = __user_ram_start + __user_ram_length); /* 0x8000000 */
20+
__user_ram_start = 0x03800000;
21+
__user_ram_end = 0x08000000;
22+
/* (0x48 =) 72 MiB length */
23+
__user_ram_length = __user_ram_start - __user_ram_end;
2324

24-
PROVIDE(__code_signature_length = 0x20);
25+
/*
26+
* VEXos provides a method for pre-loading a "linked file" at a specified
27+
* address in User RAM, conventionally near the end, after the primary
28+
* program binary. We need to be sure not to place any data in that location,
29+
* so we allow the user of this linker script to inform the start address of
30+
* this blob.
31+
*/
32+
PROVIDE(__linked_file_length = 0);
33+
PROVIDE(__linked_file_end = __user_ram_end);
34+
PROVIDE(__linked_file_start = __linked_file_end - __linked_file_length);
2535

2636
PROVIDE(__stack_length = 4M);
27-
PROVIDE(__heap_end = __user_ram_end - __stack_length);
28-
PROVIDE(__user_length = __heap_start - __user_ram_start);
37+
PROVIDE(__stack_top = __linked_file_start);
38+
PROVIDE(__stack_bottom = __linked_file_start - __stack_length);
2939

3040
MEMORY {
3141
USER_RAM (RWX) : ORIGIN = __user_ram_start, LENGTH = __user_ram_length
@@ -44,7 +54,7 @@ SECTIONS {
4454
LONG(__vcodesig_options)
4555

4656
FILL(0)
47-
. = __user_ram_start + __code_signature_length;
57+
. = __user_ram_start + 0x20;
4858
} > USER_RAM
4959

5060
/*
@@ -125,7 +135,8 @@ SECTIONS {
125135
*/
126136
.heap (NOLOAD) : {
127137
__heap_start = .;
128-
. = __heap_end;
138+
. = __stack_bottom;
139+
__heap_end = .;
129140
} > USER_RAM
130141

131142
.stack (NOLOAD) : ALIGN(8) {

0 commit comments

Comments
 (0)