Invalid operand for inline asm constraint 'i' when writing inline x86_64 assembly - rust

The code below used to build just fine back in April (Rust version ~1.6), but it doesn't anymore.
#![feature(asm)]
enum MyEnum { One = 1 }
fn main() {
unsafe {
asm!("nop" : : "i" (MyEnum::One as isize) : : ); // broken
}
}
The error message does not point to any obvious changes that might be causing this.

The value for the "i" constraint must be a compile-time constant and you are supplying it something that isn't. If you move the addition into Rust, you could use a register as well as a constant using the constraints "ri".
Whether something is a constant for the purpose of inline assembler can be affected by optimization options.

Related

Moving context into several closures?

I have found a way to move context into several closures, but it looks ugly. I do it with help of Rc and cloning each variable I need to use for each closure. Particularly I don't like to clone every variable for every closure I want to use:
let mut context = Rc::new( Context { a : 13 } );
..
let context_clone_1 = Rc::clone( &context );
engine.on_event1( Box::new( move ||
{
println!( "on_event1 : {}", context_clone_1.a );
...
let context_clone_2 = Rc::clone( &context );
engine.on_event2( Box::new( move ||
{
println!( "on_event1 : {}", context_clone_1.a );
...
It is an extensive way to go and I feel there must be a better way to do it. Also, uncommenting line // context_clone_1.a += 1; breaks the compilation. What is the proper way of solving problems like this in Rust?
Here is a playground with minimal code.
There are two "problems" here:
Since you specifically asked about context_clone_1.a += 1;: When putting a value into an Rc, there could be multiple references to that value, derived from the independent Rc owners. If mutation was allowed, this would also allow simultaneous mutation and aliasing, which is not allowed in Rust; therefore Rc does not allow mutating its inner value. A common approach to regain mutability is to put the value into a RefCell, which provides mutability through try_borrow_mut() with a runtime check that ensures no aliasing occurs. A Rc<RefCell<T>> is commonly seen in Rust.
Regarding the use of Rc: The way your code is currently set up is actually fine, at least if that's how it should work. The way the code is currently structured allows for flexibility, including cases where multiple Context-objects provide callback implementations on different events. For example, this is currently possible:
let context1 = Context { a : 13 };
engine.on_event1(Box::new(move ||
{
println!("on_event1 : {}", context1.a );
});
let context2 = Context { a : 999 };
engine.on_event2(Box::new(move ||
{
println!("on_event1 : {}", context2.a );
});
In case you have exactly one Context (as in your example), and since the Engine needs to make sure that all callbacks are alive while it itself is alive, you'll need to put each callback - which is structured as a completely separate thing - into a Rc. In your case, all Rc end up pointing to the same object; but they don't have to and this is what your code currently allows for.
A more simple solution would be to define a trait for Context, something along the lines of
trait EventDriver {
fn event1(&mut self, &Engine);
fn event2(&mut self, &Engine);
}
... and then have Context implement the trait. The Engine-struct then becomes generic over E: EventDriver and Context becomes the E in that. This solution only allows for exactly one instance of Context to provide event callbacks. But since Engine is the owner of that object, it can be sure that all callbacks are alive while it itself is alive and the whole Rc-thing goes away.

Rust custom bare metal compile target: linker expects "_start" symbol and discards unused ones: How can I specify a custom entry symbol?

I'm cross compiling bare metal 32-bit code for x86 with Rust and I'm facing the problem, that the final object file is empty, if the entry function is not exactly called _start; the linker throws all code away because it sees it as dead. I'm familiar with the fact, that _start is a well-known entry point name, but the question is still:
What part in Rust, LLVM or Linker forces this? Also attributes like extern "C" fn ..., #[no_mangle] or #[export_name = "foobar"] do not work (get thrown away by the linker). My guess is, that it's not the Rust compiler but the linker. As you can see, I use rust-lld as linker and ld.lld as linker-flavor in my case (see below).
Where does the required _start-come from? Why does the linker throw my other code away?
Whats the best option to specify my custom entry point to the linker?
x86-unknown-bare_metal.json
{
"llvm-target": "i686-unknown-none",
"data-layout": "e-m:e-i32:32-f80:128-n8:16:32-S128-p:32:32",
"arch": "x86",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"os": "none",
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "+soft-float,+sse"
}
I'm using Rust 1.54.0 nightly and built it on a Linux 5.8.0-system.
I spend some time searching the internet and found discussions, that Rust should eventually get a #[entrypoint="foobar annotation or something like this, but I didn't found an usable solution unfortunately.
My attempt was to append
"pre-link-args": {
"ld.lld": [
"-e,foobar"
]
}
to the target definition (function also called foobar) but the object file is still empty. An other attempt was to keep all dead code. This works but this solution is dirty.
Minimal code example:
// disable rust standard library
#![no_std]
// disables Rust runtime init,
#![no_main]
// see https://docs.rust-embedded.org/embedonomicon/smallest-no-std.html
#![feature(lang_items)]
// see https://docs.rust-embedded.org/embedonomicon/smallest-no-std.html
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}
use core::panic::PanicInfo;
use core::sync::atomic;
use core::sync::atomic::Ordering;
#[no_mangle]
/// The name **must be** `_start`, otherwise the compiler doesn't output anything
/// to the object file. I don't know why it is like this.
/// Also `pub` or `pub extern "C"` doesn't work
fn _start() -> ! {
loop {}
}
#[inline(never)]
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {
atomic::compiler_fence(Ordering::SeqCst);
}
}
New Answer [Solution]
The real solution is quite simple but was hard to find, because it's hard to digg for possible options and solutions in this relatively undocumented field. I found out, that llvm-ld uses the same options, as GNU ld. So I checked against the GNU ld link options and found the solution. It has to be
"pre-link-args": {
"ld.lld": [
"--entry=entry_32_bit"
]
}
and the value is the name of the function in the file. The function must be annotated with #[no_mangle].
Also see: https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
Old Answer:
A quick and really dirty solution would be
#[no_mangle]
/// The name **must be** `_start`, otherwise the compiler doesn't output anything
/// to the object file. I don't know it is like this.
fn _start() -> ! {
entry_32_bit();
}
#[no_mangle]
#[inline(never)]
fn entry_32_bit() -> ! {
loop {}
}
With this, one can directly jump to symbol entry_32_bit from assembly. But this "solution" is far from ideal! Especially when you want to link multiple bins together, there will be a name collision.

Why can't I import `std::assert` via `use` while it works for other macros from std?

With Rust 2018, this code works (Playground):
use std::panic;
use std::format;
use std::assert_eq;
But this:
use std::assert;
Results in this error:
error[E0432]: unresolved import `std::assert`
--> src/lib.rs:4:5
|
4 | use std::assert;
| ^^^^^^^^^^^ no `assert` in the root
I read the edition guide about this topic and it says that use should work with macro_rules! macros and procedural macros. Thus, I'm confused.
use should work with macro_rules! macros and procedural macros
Except assert is neither of those:
/// Built-in macros to the compiler itself.
///
/// These macros do not have any corresponding definition with a `macro_rules!`
/// macro, but are documented here. Their implementations can be found hardcoded
/// into libsyntax itself.
It is a compiler built-in:
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_doc_only_macro]
macro_rules! assert {
($cond:expr) => ({ /* compiler built-in */ });
($cond:expr,) => ({ /* compiler built-in */ });
($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ });
}
Other faux-macros include:
compile_error
format_args
env
option_env
concat_idents
concat
line
column
file
stringify
include_str
include_bytes
module_path
cfg
include
The actual definition of assert is buried much lower in libsyntax_ext/assert.rs
Stabilize uniform paths on Rust 2018 (#56417) does mention these in passing:
Built-in macros, for example use env.
Currently an error due to some (fixable) implementation details of built-in macros.
No known issues to resolve before stabilization (after the error is removed).

Rust conflict with error-chain and websocket crates

I'm trying to use error-chain with the websocket crate, but running into an issue that I'm not sure how to resolve. WsUpgrade::accept has the following signature:
fn accept(self) -> Result<Client<S>, (S, IoError)>
Note that the Err variant is a tuple. I want to configure error-chain to handle calls to this method, so I tried to do so as follows in the relevant consuming module:
mod errors {
error_chain! {
foreign_links {
WebSock((::std::net::TcpStream, ::std::io::Error));
}
}
}
This results in the following error, seemingly related to the presence of the tuple.
error: expected identifier, found `(`
--> src/lib/websock.rs:23:21
|
23 | WebSock((::std::net::TcpStream, ::std::io::Error));
| ^
How can I resolve this? Hopefully I've missed something simple.
A simple solution would be to introduce a type alias:
mod errors {
type WebSocketError = (::std::net::TcpStream, ::std::io::Error);
error_chain! {
foreign_links {
WebSock(WebSocketError);
}
}
}
However, this type does not implement traits required by error-chain (such as Error and Display), so it can't be used there.
I think the simplest solution is to convert the error manually using Result::map_err before passing the value to error-chain. For example, the following construction will produce Result<Client<S>, IoError>:
x.accept().map_err(|e| e.1)

Declaring a map in a separate file and reading its contents

I'm trying to declare a map in a separate file, and then access it from my main function.
I want Rust's equivalent (or whatever comes closest) to this C++ map:
static const std::map<std::string, std::vector<std::string>> table = {
{ "a", { "foo" } },
{ "e", { "bar", "baz" } }
};
This is my attempt in Rust.
table.rs
use std::container::Map;
pub static table: &'static Map<~str, ~[~str]> = (~[
(~"a", ~[~"foo"]),
(~"e", ~[~"bar", ~"baz"])
]).move_iter().collect();
main.rs
mod table;
fn main() {
println(fmt!("%?", table::table));
}
The above gives two compiler errors in table.rs, saying "constant contains unimplemented expression type".
I also have the feeling that the map declaration is less than optimal for the purpose.
Finally, I'm using Rust 0.8.
As Chris Morgan noted, rust doesn't allow you to run user code in order to initialize global variables before main is entered, unlike C++. So you are mostly limited to primitive types that you can initialize with literal expressions. This is, afaik, part of the design and unlikely to change, even though the particular error message is probably not final.
Depending on your use case, you might want to change your code so you're manually passing your map as an argument to all the functions that will want to use it (ugh!), use task-local storage to initialize a tls slot with your map early on and then refer to it later in the same task (ugh?), or use unsafe code and a static mut variable to do much the same with your map wrapped in an Option maybe so it can start its life as None (ugh!).

Resources