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

RFC on low level features #55

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions active/0000-better-low-level-handling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
- Start Date: 2014-04-29
- RFC PR #: (leave this empty)
- Rust Issue #: (leave this empty)

# Summary

Add a few features that would allow to write better system-level code: weak
symbols, naked functions, pure assembly functions.

# Motivation

Those features are available in C and C++ and are often used in embedded
development.

# Detailed design

### Weak symbols

`linkage` attribute should be extended to be allowed in function context
(alternatively a new attribute should be provided):

```rust
#[no_mangle]
#[linkage(weak)]
pub fn isr_handler() {
...
}
```

This would allow to provide default implementations that could be overriden by
specific code.

### Naked functions

Provide an attribute that would allow to generate a naked function, without
stack guard prologue, common function prologue and epilogue. The only statement
that could be safely used in naked function is `asm!` that doesn't modify
operands (alternatively, naked functions are always considered _unsafe_).
Copy link
Member

Choose a reason for hiding this comment

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

Would this be addressed by allowing something like

asm!("
isr_handler:
   ...
")

as a freestanding statement?

Copy link
Author

Choose a reason for hiding this comment

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

Partially. I'm not sure there are absolutely no valid cases to have a naked function with a mangled name.

Copy link
Author

Choose a reason for hiding this comment

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

Also, this statement would be a better fit for "Pure assembly functions" below. Naked function still generates a "return-from-function" statement.

Copy link

Choose a reason for hiding this comment

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

@huonw: No. Currently, the workaround is not that simple. This statement must be reachable from Rust code so that it is not recognized as dead code and optimized away.

I believe an appropriate ABI string should be supported. (unsafe could be implied by extern "naked", and extern "ABI" unsafe fn can't be declared as per rust-lang/rust#10025)

pub extern "naked" unsafe fn isr_handler() { // alternatively extern "bare"
    asm!("mrs r0, psp
          stmdb r0!, {r4-r11}
          msr psp, r0" :::: "volatile");
    switch_stack();
}

Copy link
Member

Choose a reason for hiding this comment

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

Erm, why couldn't we just make any freestanding asm! "hardcoded" to be reachable?

Presumably the programmer didn't accidentally throw it there, and approximately knows what they're doing if they're writing raw functions in asm, so the compiler can just trust them and assume it's being used & hence is reachable.

Copy link
Author

Choose a reason for hiding this comment

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

+1 to ABI string approach, looks more elegant (extern "bare" would be the second case, if rust ends up supporting both).

Copy link
Author

Choose a reason for hiding this comment

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

why couldn't we just make any freestanding asm! "hardcoded" to be reachable

would rust parse the assembly as well? Where would dangling instructions end up?

fn test() {
  ...
}

asm!("
  bl test  //  <- this instruction is not referenced by any name, still a valid assembly.
test2:
  mov r0, 0
  bl test
" :::: "volatile");

Copy link

Choose a reason for hiding this comment

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

It wouldn't make sense for asm! statements that are not volatile. Either way, the programmer could put it somewhere in an unused function, making the compiler generate lots of dead code.

Copy link
Member

Choose a reason for hiding this comment

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

would rust parse the assembly as well?

Don't know, probably not; e.g., gcc just throws it all (essentially) verbatim into the final output.

Copy link
Author

Choose a reason for hiding this comment

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

It wouldn't make sense for asm! statements that are not volatile

Totally agree with that, but it's a bit out of scope of this RFC. Or should I add it here as well?

gcc just throws it all (essentially) verbatim into the final output

That's the problem of top-level asm!. I'm not sure what is the scope of the statement — is it the translation unit itself? What section is it going to end up in, if rust switches to "-ffunction-sections"?

Re-using the function syntax provides answers for all these questions.


```rust
#[naked]
pub fn isr_handler {
asm!("mrs r0, psp
stmdb r0!, {r4-r11}
msr psp, r0" :::: "volatile");
switch_stack();
}
```

would generate the following machine code:

```
isr_handler:
// asm! block
mrs r0, psp
stmdb r0!, {r4-r11}
msr psp, r0

// function call
bl switch_stack

// the only generated instruction
bx lr
```

Note how in this example the provided code is incorrect, as `bl` will overwrite
the contents of `lr` register, so that the final `bx lr` instruction will do
something unexpected. It might be useful to disallow function calls from naked
function unless those are done explicity from `asm!` (which is quite hard,
unless the called function has `#[no_mangle]`).

### Pure assembly functions

This the extension of naked funcations above, but no code would be generated by
compiler at all. Those functions could be written in an external .s file, but
including them in source code would allow better management, including `#[cfg]`
usage to pick the correct implementation.

# Alternatives

N/A

# Unresolved questions

N/A