Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verify initial stack-pointer to be inside static RAM #41

Merged
merged 3 commits into from
Jun 23, 2021
Merged

Conversation

Urhengulas
Copy link
Member

This PR verifies that the initial stack-pointer of each of the four example apps is inside the static RAM region, after being linked with flip-link.

I've made the choice to have one test for all example apps, instead of one test for each test. This approach is a bit easier to implement, but has the drawback of less error-resolution. E.g. if one of the examples would fail to compile the tests fail completely, instead of running the other ones successfully.

Depends on #40 and fixes #25.

@Urhengulas Urhengulas requested a review from japaric June 16, 2021 14:09
@Urhengulas Urhengulas marked this pull request as ready for review June 16, 2021 14:09
Copy link
Member

@japaric japaric left a comment

Choose a reason for hiding this comment

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

looks good to me except for the assertion (see inline comment)

tests/verify.rs Outdated
let bounds = elf::get_bounds(&[data, bss, uninit])?;

// Is the initial stack-pointer inside 'static RAM'?
assert!(bounds.contains(&initial_sp));
Copy link
Member

Choose a reason for hiding this comment

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

This is not the correct thing to assert even though the test passes.

the bounds range span all static variables in RAM. flip-link will put the stack right below that. we want to check (assert) that the stack and the static variables do not overlap

the tricky bit is that initial_sp points to the start of the stack but when you use the stack that address will not be written to: data is written to the address immediately below that (this is because on ARM the stack is of the full descending type).

So if the SP is 0x2000_3000 and you push 0xAAAA_AAAA (32-bit word) onto it the memory that is written is:

  • 0x2000_3000 this address is not written to
  • 0x2000_2FFF = 0xAA
  • 0x2000_2FFE = 0xAA
  • 0x2000_2FFD = 0xAA
  • 0x2000_2FFC = 0xAA
  • new SP value = 0x2000_2FFC

On the other hand if you have a static variable located at 0x2000_3000 and write to it then address 0x2000_3000 will be written to. Thus initial_sp can be equal to bounds.start().

so the cases here are

  • initial_sp <= bounds.start = OK (stack is below static variables)
  • initial_sp > bounds.start && initial_sp < bounds.end = BAD (overlap)
  • initial_sp > bounds.end = BAD (stack is above static variables -> if the stack grows it could corrupt static variables)

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah kay. Thank you for the elaborate explanation! 😄

Copy link
Member Author

Choose a reason for hiding this comment

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

I am thinking of putting this explanation either into a doc-comment or some kind of CONTRIBUTING.md, since I found it very useful. What do you think would be a good place for it?

Copy link
Member

Choose a reason for hiding this comment

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

I tend to favor 'put it where it's hard to miss' and to me that's usually near the code that implements or verifies the thing because (hurried) devs tend to miss markdown files that are not the README (:raising_hand: ).

A separate markdown file would also be OK but then we need to link back from the related code ("before working on this module / function read some-file.md). Keeping that link up to date could become a chore -- though this code base is small and doesn't change much.

@japaric japaric added the pr waits on: author Pull Request requires changes from the author label Jun 22, 2021
@Urhengulas Urhengulas removed the pr waits on: author Pull Request requires changes from the author label Jun 23, 2021
@japaric
Copy link
Member

japaric commented Jun 23, 2021

bors r+

@bors
Copy link
Contributor

bors bot commented Jun 23, 2021

Build succeeded:

@bors bors bot merged commit 0edc3fa into main Jun 23, 2021
@bors bors bot deleted the verify-memory branch June 23, 2021 10:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CI: verify memory layout of test-app
2 participants