Skip to content
This repository has been archived by the owner on Jan 24, 2022. It is now read-only.

link.x.in: put most __[se] symbols back into sections #323

Merged
merged 2 commits into from
Apr 15, 2021

Conversation

jordens
Copy link
Contributor

@jordens jordens commented Apr 7, 2021

This puts most start/end address symbols back into the sections.

Only __ebss and __edata are kept outside their sections so that
potential user code with external libraries can inject stuff using
INSERT AFTER .bss/.data and profit from the .bss/.data zeroing/loading
mechanism. This also leads to the __sbss and __veneer_base symbols
having the right section type (bss is B not D in nm).

Also the trust zone start and end address are aligned to 32 bytes as per
the requirements. That section does cost up to 28 byte of padding at the end of FLASH due to
that alignment even if empty. But since flash is typically a multiple of 32 bytes and since the padding is at the end, there is no downside.

The .rodata start is kept free for the linker to allocate it after .text.
This enables users to inject sections between .text and .rodata and
removes the chance to get overlapping address errors. With this the
linker will by default place .rodata after .text as before.

This commit also adds and exposes a few more stable address start/end symbols
(__[se]uninit, __stext, __srodata) that are usefull for debugging and hooking
into.

See
#287 (comment)
for discussion of the issues and description of this compromise solution.

Tested:

Topics:

  • sgstubs moved to be the last section in FLASH to minimize the impact of the 32 byte alignment. (Padding flash to 32 byte is considered benign.)
  • INSERT AFTER with binutils ld doesn't work. But that's independent of these changes. This is the sgstubs-in memory.x use case. Currently the sgstubs section is kept in link.x.

This puts most start/end address symbols back into the sections.

Only `__ebss` and `__edata` are kept outside their sections so that
potential user code with external libraries can inject stuff using
`INSERT AFTER .bss/.data` and profit from the .bss/.data zeroing/loading
mechanism. This also leads to the `__sbss` and `__veneer_base` symbols
having the right section type (B not D in nm).

Also the trust zone start and end address are aligned to 32 bytes as per
the requirements. That section does cost up to 28 byte of FLASH due to
that alignment even if empty.

The .rodata start is kep free for the linker to alocate it after .text.
This enables users to inject sections between .text and .rodata and
removes the chance to get overlapping address errors. With this the
linker will by default place .rodata after .text as before.

This commit also adds and exposes a few more stable address start/end symbols
(__[se]uninit, __stext, __srodata) that are usefull for debugging and hooking
into.

See
rust-embedded#287 (comment)
for discussion of the issues and description of this compromise solution.
@rust-highfive
Copy link

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @jonas-schievink (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@adamgreig
Copy link
Member

Also the trust zone start and end address are aligned to 32 bytes as per
the requirements. That section does cost up to 28 byte of FLASH due to
that alignment even if empty.

Could we place the trustzone section after .data to prevent this extra flash usage?

@jordens
Copy link
Contributor Author

jordens commented Apr 7, 2021

Could we place the trustzone section after .data to prevent this extra flash usage?

That would still effectively pad the flash usage to 32 byte which sound benign.
I suspect that in many cases the sgstubs would actually be placed in a fixed NSC output memory region and not in FLASH which is typically S. It's presumably better to leave that entire section to the user until cortex-m-rt decides it knows how to fully support and abstract TrustZone. It seems to me a TrustZone user would be able to write and INSERT that section themselves. But I have never used TrustZone...
(link, link, link, link)

@adamgreig
Copy link
Member

@mattico / @Dirbaio I think that your use cases should still be supported with these changes, right?

That would still effectively pad the flash usage to 32 byte which sound benign.

Yea, fair point. I think these came from @hug-dev in #297, and looking back on it I also saw they said "I will update the PR as discussed but would still like to keep the __veneer_limit symbol unaligned. It could be used as a way to count the number of entry functions declared in all the dependency graph as well", which I think this would inadvertently be undoing.

Has anyone used this section? Could it just be added by TrustZone users in their memory.x as required, with INSERT AFTER .data and including whatever alignment is required, without it needing to be in our main link.x?

@mattico
Copy link
Contributor

mattico commented Apr 8, 2021

Very annoying to test this when the crates-io version is ahead of the git version... But yes, this does still work with the project that originally motivated my changes.

@jordens jordens marked this pull request as ready for review April 8, 2021 06:12
@jordens jordens requested a review from a team as a code owner April 8, 2021 06:12
@hug-dev
Copy link
Contributor

hug-dev commented Apr 8, 2021

they said "I will update the PR as discussed but would still like to keep the __veneer_limit symbol unaligned. It could be used as a way to count the number of entry functions declared in all the dependency graph as well", which I think this would inadvertently be undoing.

I actually removed that in the end in the original PR because this was not working for some reason. So it would be fine that way!

Has anyone used this section? Could it just be added by TrustZone users in their memory.x as required, with INSERT AFTER .data and including whatever alignment is required, without it needing to be in our main link.x?

I have a local TrustZone-M example I am happy to try with this PR by injecting the veneers sections manually. I guess I would do INSERT AFTER .text though? So that the veneers are in a read-only section by default? As far as I know, it is common for the veneers to be in flash but it ultimately depends on the Implementation Defined Attribution Unit (IDAU) on the particular platform to know where they can be put.

See here for other details.

@jordens
Copy link
Contributor Author

jordens commented Apr 8, 2021

I guess I would do INSERT AFTER .text though? So that the veneers are in a read-only section by default? As far as I know, it is common for the veneers to be in flash but it ultimately depends on the Implementation Defined Attribution Unit (IDAU) on the particular platform to know where they can be put.

From what I read (in the links above) they should indeed be in flash, not in the "default" flash alias region (which is S), but in the NSC alias region.

@hug-dev
Copy link
Contributor

hug-dev commented Apr 8, 2021

I tried on my example and that PR works without any modification.

I then removed the veneers section from it:

diff --git a/link.x.in b/link.x.in
index 92004b7..95a8a14 100644
--- a/link.x.in
+++ b/link.x.in
@@ -132,19 +132,6 @@ SECTIONS
   /* LMA of .data */
   __sidata = LOADADDR(.data);

-  /* ### .gnu.sgstubs
-     This section contains the TrustZone-M veneers put there by the Arm GNU linker. */
-  /* Security Attribution Unit blocks must be 32 bytes aligned. */
-  /* Note that this pads the FLASH usage to 32 byte alignment. */
-  .gnu.sgstubs : ALIGN(32)
-  {
-    . = ALIGN(32);
-    __veneer_base = .;
-    *(.gnu.sgstubs*)
-    . = ALIGN(32);
-    __veneer_limit = .;
-  } > FLASH
-
   /* ### .bss */
   .bss (NOLOAD) : ALIGN(4)
   {

and added in memory.x in my cortex-m-quickstart project:

SECTIONS {
  /* ### .gnu.sgstubs
     This section contains the TrustZone-M veneers put there by the Arm GNU linker. */
  /* Security Attribution Unit blocks must be 32 bytes aligned. */
  /* Note that this pads the FLASH usage to 32 byte alignment. */
  .gnu.sgstubs : ALIGN(32)
  {
    . = ALIGN(32);
    __veneer_base = .;
    *(.gnu.sgstubs*)
    . = ALIGN(32);
    __veneer_limit = .;
  } > FLASH
} INSERT AFTER .rodata

but I have the error when compiling:

 = note: arm-none-eabi-ld: error: no memory region specified for loadable section `.rodata'

Same error if I do INSERT AFTER .text. Not sure if I did everything right?

@jordens
Copy link
Contributor Author

jordens commented Apr 8, 2021

Same error if I do INSERT AFTER .text. Not sure if I did everything right?

In fact, that error even happens with an empty SECTIONS { } INSERT AFTER .section in memory.x for any .section with current cortex-m-rt master and arm-none-eabi-ld (GNU ld (2.34-4ubuntu1+13ubuntu1) 2.34). Doesn't seem to be a issue due to these changes.

n.b. The INSERT sections are treated like orphan sections.
https://sourceware.org/binutils/docs-2.20/ld/Location-Counter.html#Location-Counter at the end contains a good description of why their placement is tricky: "it assumes that all assignments or other statements belong to the previous output section, except for the special case of an assignment to ." leading to the . = .; trick as a placement barrier.

@adamgreig
Copy link
Member

In fact, that error even happens with an empty SECTIONS { } INSERT AFTER .section in memory.x for any .section with current cortex-m-rt master and arm-none-eabi-ld (GNU ld (2.34-4ubuntu1+13ubuntu1) 2.34). Doesn't seem to be a issue due to these changes.

Huh, that's no good. I'm fairly sure this previously worked... we should add some CI tests for the various memory.x things people might do, I guess.

What do you think is the best course of action given this, then? Go ahead with this PR as-is?

One related thought I've had (which needn't block this PR) is we can use build.rs to customise the default linker script -- for example only adding the secure veneers on v8 targets (or even just including a different link.x.in for v8 targets). That would let us get around the extra flash usage if it's a problem.

@jordens
Copy link
Contributor Author

jordens commented Apr 13, 2021

What do you think is the best course of action given this, then? Go ahead with this PR as-is?

This was tested in three cases now (I think). Maybe try to get at least two more testers on board? But then yes, I'd propose merging.

CI for several specific memory organization cases and more dynamic link.x.in would be excellent next steps after this one.

@hug-dev
Copy link
Contributor

hug-dev commented Apr 14, 2021

we can use build.rs to customise the default linker script -- for example only adding the secure veneers on v8 targets (or even just including a different link.x.in for v8 targets). That would let us get around the extra flash usage if it's a problem.

Agree! Maybe it's also possible to put the veneer sections (or others) in a #ifdef preprocessor block so that it's only included for the good targets. I am sure I have seen that being done on linker scripts before.

As far as I am concerned, I would be ok to merge this since it works on Armv8-M 👌

Copy link
Member

@adamgreig adamgreig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now also tested this on an STM32 using a custom USB memory section which also continues to work fine, so I think let's get it merged and then we can think about other improvements. Thanks again for this PR!

bors merge

@bors
Copy link
Contributor

bors bot commented Apr 15, 2021

@bors bors bot merged commit c7b26c5 into rust-embedded:master Apr 15, 2021
@jordens jordens deleted the rj/robustify-link-script branch April 15, 2021 05:15
adamgreig pushed a commit to rust-embedded/cortex-m that referenced this pull request Jan 12, 2022
323: link.x.in: put most __[se] symbols back into sections r=adamgreig a=jordens

This puts most start/end address symbols back into the sections.

Only `__ebss` and `__edata` are kept outside their sections so that
potential user code with external libraries can inject stuff using
`INSERT AFTER .bss/.data` and profit from the .bss/.data zeroing/loading
mechanism. This also leads to the `__sbss` and `__veneer_base` symbols
having the right section type (bss is B not D in nm).

Also the trust zone start and end address are aligned to 32 bytes as per
the requirements. That section does cost up to 28 byte of padding at the end of FLASH due to
that alignment even if empty. But since flash is typically a multiple of 32 bytes and since the padding is at the end, there is no downside.

The .rodata start is kept free for the linker to allocate it after .text.
This enables users to inject sections between .text and .rodata and
removes the chance to get overlapping address errors. With this the
linker will by default place .rodata after .text as before.

This commit also adds and exposes a few more stable address start/end symbols
(__[se]uninit, __stext, __srodata) that are usefull for debugging and hooking
into.

See
rust-embedded/cortex-m-rt#287 (comment)
for discussion of the issues and description of this compromise solution.

Tested:

* [x] [stm32h7 ITCM](quartiq/stabilizer#322)
* [x] [sgstubs](rust-embedded/cortex-m-rt#323 (comment))
* [x] `INSERT AFTER` for bss/data still works (rust-embedded/cortex-m-rt#323 (comment))

Topics:

* [x] `sgstubs` moved to be the last section in FLASH to minimize the impact of the 32 byte alignment. (Padding flash to 32 byte is considered benign.)
* [ ] `INSERT AFTER` with binutils ld doesn't work. But that's independent of these changes. This is the `sgstubs`-in `memory.x` use case. Currently the `sgstubs` section is kept in `link.x`.

Co-authored-by: Robert Jördens <rj@quartiq.de>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants