From 99841150dbe004be8a73e2a08946ad7e717e76a2 Mon Sep 17 00:00:00 2001 From: Dan Callaghan Date: Sat, 23 Jun 2018 17:41:49 +1000 Subject: [PATCH 1/5] mark .init and .trap sections as executable This is needed for lld, otherwise it will complain about section flag mismatch: ld.lld: error: incompatible section flags for .text >>> target/riscv32imac-unknown-none/debug/deps/libriscv_rt-7850ee1a6233fbe9.rlib(riscv_rt-7850ee1a6233fbe9.4tmuw4s4crjeqbm5.rcgu.o):(.trap): 0x4 >>> output section .text: 0x6 --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cabb2cb..822d9ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -205,7 +205,7 @@ extern "C" { /// pointer. Then it calls _start_rust. #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] global_asm!(r#" -.section .init +.section .init, "ax" .globl _start _start: .cfi_startproc @@ -295,7 +295,7 @@ macro_rules! entry { /// restores caller saved registers and then returns. #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] global_asm!(r#" - .section .trap + .section .trap, "ax" .align 4 .global _start_trap From 7451011e09bd429c8c3daab1cf187b4c73a6e283 Mon Sep 17 00:00:00 2001 From: Dan Callaghan Date: Sun, 24 Jun 2018 14:53:48 +1000 Subject: [PATCH 2/5] remove hackery for .debug_gdb_scripts section This is no longer necessary now that we can configure the target to exclude the .debug_gdb_scripts section. See: https://github.com/rust-lang/rust/pull/53139 --- link.x | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/link.x b/link.x index 5af49bf..6458683 100644 --- a/link.x +++ b/link.x @@ -73,22 +73,6 @@ SECTIONS KEEP(*(.got .got.*)); _egot = .; } > RAM AT > FLASH /* LLD fails on AT > FLASH */ - - - /* Due to an unfortunate combination of legacy concerns, - toolchain drawbacks, and insufficient attention to detail, - rustc has no choice but to mark .debug_gdb_scripts as allocatable. - We really do not want to upload it to our target, so we - remove the allocatable bit. Unfortunately, it appears - that the only way to do this in a linker script is - the extremely obscure "INFO" output section type specifier. */ - /* a rustc hack will force the program to read the first byte of this section, - so we'll set the (fake) start address of this section to something we're - sure can be read at runtime: the start of the .text section */ - /* LLD fails to parse _stext (INFO) */ - .debug_gdb_scripts _stext (INFO) : { - KEEP(*(.debug_gdb_scripts)) - } } /* Do not exceed this mark in the error messages below | */ From ef3a278cb8a2ee3457072e28f7c059688c747730 Mon Sep 17 00:00:00 2001 From: Dan Callaghan Date: Mon, 13 Aug 2018 22:38:29 +1000 Subject: [PATCH 3/5] align VMA not LMA This aligns the VMA (virtual adddress at runtime): .rodata ALIGN(4) : { ... whereas this aligns the LMA (load address): .rodata : ALIGN(4) { ... If we ensure the VMA is aligned the linker will keep the corresponding LMA in sync (and it will be aligned too). Previously, by forcing the LMA to be aligned but leaving the VMA unspecified, the linker would split .text and .rodata into two separate loads because their addresses fell out of sync. --- link.x | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/link.x b/link.x index 6458683..6a666da 100644 --- a/link.x +++ b/link.x @@ -7,7 +7,7 @@ SECTIONS { PROVIDE(_stext = ORIGIN(FLASH)); - .text _stext : ALIGN(4) + .text ALIGN(_stext,4) : { /* Put reset handler first in .text section so it ends up as the entry */ /* point of the program. */ @@ -19,21 +19,20 @@ SECTIONS *(.text .text.*); } > FLASH - .rodata : ALIGN(4) + .rodata ALIGN(4) : { *(.rodata .rodata.*); - . = ALIGN(4); } > FLASH PROVIDE(_sbss = ORIGIN(RAM)); - .bss _sbss : ALIGN(4) + .bss ALIGN(_sbss,4) : { *(.bss .bss.*); . = ALIGN(4); _ebss = .; } > RAM - .data _ebss : ALIGN(4) + .data _ebss : { _sidata = LOADADDR(.data); _sdata = .; From 90966abf0f65a425886655be1cbf9f8f1fdab035 Mon Sep 17 00:00:00 2001 From: Dan Callaghan Date: Wed, 15 Aug 2018 14:38:35 +1000 Subject: [PATCH 4/5] discard .eh_frame sections The .cfi_* assembler directives cause call frame information to be emitted in a special .eh_frame section. But this is not needed in the final binary, because we are not doing panic unwinding. GNU ld already discards this section with its (default) --gc-sections behaviour. Lld doesn't do that by default though, instead it complains: rust-lld: error: no memory region specified for section '.eh_frame' So let's explicitly discard the .eh_frame section. --- link.x | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/link.x b/link.x index 6a666da..0e2bd98 100644 --- a/link.x +++ b/link.x @@ -72,6 +72,12 @@ SECTIONS KEEP(*(.got .got.*)); _egot = .; } > RAM AT > FLASH /* LLD fails on AT > FLASH */ + + /* Discard .eh_frame, we are not doing unwind on panic so it is not needed */ + /DISCARD/ : + { + *(.eh_frame); + } } /* Do not exceed this mark in the error messages below | */ From 52095e9374166a6d4be7d4a1beb8dcaf84f23dce Mon Sep 17 00:00:00 2001 From: Dan Callaghan Date: Wed, 15 Aug 2018 16:57:26 +1000 Subject: [PATCH 5/5] make the linker script compatible with lld To work around a bug in lld, we need to avoid starting the .bss section from a fixed address (previously, the _sbss symbol). Otherwise lld incorrectly tries to extend the FLASH output region up to the start of the RAM output region, which is too large. To work around another bug in lld, we need to avoid starting sections marked with (INFO) from a specific starting address. Its parser does not accept both a start address and the (INFO) attribute. Specifying these start addresses is redundant anyway, the linker will lay them out in sequential order for us. --- link.x | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/link.x b/link.x index 0e2bd98..5f24965 100644 --- a/link.x +++ b/link.x @@ -24,15 +24,15 @@ SECTIONS *(.rodata .rodata.*); } > FLASH - PROVIDE(_sbss = ORIGIN(RAM)); - .bss ALIGN(_sbss,4) : + .bss : { + _sbss = .; *(.bss .bss.*); . = ALIGN(4); _ebss = .; } > RAM - .data _ebss : + .data : AT(LOADADDR(.rodata) + SIZEOF(.rodata)) { _sidata = LOADADDR(.data); _sdata = .; @@ -41,37 +41,35 @@ SECTIONS *(.data .data.*); . = ALIGN(4); _edata = .; - } > RAM AT > FLASH /* LLD fails on AT > FLASH */ + } > RAM PROVIDE(_heap_size = 0); /* fictitious region that represents the memory available for the heap */ - .heap _edata (INFO) : ALIGN(4) + .heap (INFO) : { _sheap = .; . += _heap_size; . = ALIGN(4); _eheap = .; - } + } > RAM /* fictitious region that represents the memory available for the stack */ - .stack _eheap (INFO) : ALIGN(4) + .stack (INFO) : { _estack = .; . = _stack_start; _sstack = .; - } + } > RAM /* fake output .got section */ /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in the input files and raise an error if relocatable code is found */ - .got : + .got (INFO) : { - _sgot = .; KEEP(*(.got .got.*)); - _egot = .; - } > RAM AT > FLASH /* LLD fails on AT > FLASH */ + } /* Discard .eh_frame, we are not doing unwind on panic so it is not needed */ /DISCARD/ : @@ -81,7 +79,7 @@ SECTIONS } /* Do not exceed this mark in the error messages below | */ -ASSERT(_sgot == _egot, " +ASSERT(SIZEOF(.got) == 0, " .got section detected in the input files. Dynamic relocations are not supported. If you are linking to C code compiled using the `gcc` crate then modify your build script to compile the C code _without_ the