Embedded development, #define A B

In C langue, "#define A B", the result of #A is B

In RUST, how to convert "#define A B" ,the result of stringfy(A) is B.

or other methods.

Thanks

1 Like

short answer is you cannot: stringify!(A) is always, by definition, "A".

I think this is probably an XY problem, what end goals do you want to achieve exactly?

5 Likes

For example, in C, I define a macro "#define Temp el2" and a asm "asm("mov x, " #Temp)", and the result is "mov x, el2". How do I convert it in rust?

asm! can allocate registers (it’s right in the example on the linked page). LLVM will pick a register it isn’t using for the moment and can optimize with that information.

core::arch::asm!(
    "mov x, {tmp}",
    tmp = out(reg) _,
);

(I’m not completely sure reg is the right register class here, it depends on your use case)
If you need specifically el2 for some reason:

core::arch::asm!(
    "mov x, {tmp}",
    tmp = out("el2") _,
)
1 Like

i know, but i want the tmp is variable. This variable has no data type defined by a macro in c.

In C langue:
#define Temp el2
asm("msr x, " #Temp)

=> asm("msr x, el2")

In Rust langue:
const Temp: &str = "el2";
asm!(concat!("msr x, " , stringfy!(Temp)))

=> asm!("msr x, Temp")

The results are different

I think by changing “const Temp: &str = "el2";” or stringfy!(Temp), the result is the same as C.

using concat!() and stringify!() in this way is, non idiomatic, to say the least. it feels like to me that you are seeking for a rust solution for a C problem, not for the underlying domain problem.

you didn't specify but the example seems to be for the ARM architecture, right? I'm not familiar with ARM assembly, but if I remember correctly, the msr instruction has something to do about system registers.

in your example, msr x, el2, I would assume x is a general register, while el2 is a special register? what I don't quite understand is, why don't you write it down directly as the instruction operand? what's the reason you are using a preprocessor macro in the first place?

if you can provide more details and context, it'll be easier for people to understand the problem you are trying to solve, and find more useful and idiomatic solutions.

NOT THE SOLUTION

WARNING: DO NOT USE THIS IN YOUR PROJECT!

the way you use concat!() for the assember template is (kind of) supported in rust, but you mis-used stringify!(). I think this should be roughtly the same as your original C code:

macro_rules! Temp {
    () => { "el2" }
}
asm!(concat!("msr x, ", Temp!()))
2 Likes

btw, if you are trying to mimic C using rust, chances are you'll end up with a solution that is worse than either the original C solution, or an idiomatic rust solution.

7 Likes

A bad option is to define a macro that carries the register name, but this doesn't work in the register specifier:

use std::arch::asm;
macro_rules! tempreg {
    () => {
        "el2"
    };
}

fn foo() {
    unsafe {
        asm!(concat!("msr x, ", tempreg!()),),
        _ = out("el2"), // macro invalid in this position
    }
}

Your other option is to put the entire assembly block inside a macro taking idents, which lets you swap out the register specifiers:

macro_rules! the_asm {
    ($tempreg:ident) => {
        #[unsafe(no_mangle)]
        fn foo2() {
            unsafe {
                asm!(
                    concat!("msr 3, ", stringify!($tempreg))
                )
            }
        }
    }
}

the_asm!(el2);
error: invalid instruction mnemonic 'msr'
  --> src/lib.rs:21:21
   |
21 |                     concat!("msr 3, ", stringify!($tempreg))
   |                     ^
   |
note: instantiated into assembly here
  --> <inline asm>:2:2
   |
2  |     msr 3, el2
   |     ^^^

edit: NVM, solution 2 doesn't let you specify inputs and outputs

2 Likes

I see this thread is a duplicate of this one: Replacing Macros

As an alternative to using the eager-expansion of macros in the concat! macro's arguments; you could also use my new crate, preinterpret, which works by pre-processing the code.

But the register definition has to be set in the same block as its use, which may not fit your needs:

// If asm! takes a string
preinterpret::preinterpret!{
    [!set! #temp = "el2"]
    asm!(
        [!string! "msr x, " #temp]
    )
}
1 Like

In Rust, you can achieve similar functionality by using a const or a macro like macro_rules! , but to directly stringify a symbol (A ) and map it to a value (B ), you would use a macro:

    ($name:ident, $value:expr) => {
        const $name: &str = stringify!($value);
    };
}

define!(A, B); // A will hold the string "B"
1 Like

I'm sorry, I don't quite understand .

Writing assembly in Rust is more dangerous than in C in general and almost never what you want to do. Are you sure you cannot use a function from the cortex-m crate for this?

1 Like