PacktPublishing / Asynchronous-Programming-in-Rust

Asynchronous Programming in Rust, published by Packt

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ch01 - compilation error on aarch64 (Mac)

2BitSalute opened this issue · comments

I'm compiling the first code example in the book on a Mac, and getting the expected compatible register or logical immediate error for the assembly code.

I searched for the error string and found people discussing similar errors specifically on aarch64.
One of the hits was a StackOverflow article with an answer suggesting to make clang use the GNU assembler rather than its integrated one. I'll do some more research and update the description if I figure it out or make more progress.

cargo run --package ch1 --bin ch1 
error: expected compatible register or logical immediate
  --> src/main.rs:20:15
   |
20 |         asm!("mov {0}, [{1}]", out(reg) res, in(reg) ptr);
   |               ^
   |
note: instantiated into assembly here
  --> <inline asm>:1:10
   |
1  |     mov x8, [x0]
   |             ^

error: could not compile `ch1` (bin "ch1") due to 1 previous error

Thanks for reporting.

I should have mentioned that I assumed x86-64 architecture for that example. I originally wrote it before new M-series Macs made ARM64 so commonplace and I forgot to test that on both platforms.

The fix is rather simple, just change mov to ldr:

fn dereference(ptr: *const usize) -> usize {
    let mut res: usize;
    unsafe {
        asm!("ldr {0}, [{1}]", out(reg) res, in(reg) ptr)
    };
    res
}

As an alternative you can emulate x86-64 on the mac by following these 4 steps (which is a technique you'll need for chapter 5 anyway): https://github.com/PacktPublishing/Asynchronous-Programming-in-Rust/blob/main/ch05/How-to-MacOS-M.md#how-to-run-these-examples-on-a-mac-with-an-m-serixes-chip

Oh, I just created a pull request with what I thought was a different solution. Ugh, I was too happy when it compiled!
Either way, thank you for looking at this so quickly.

And really cool, I didn't expect to be able to switch to a different architecture.
I found that you can also add this to the config.toml under .cargo to be able to build and run the x86_64 target by default (including the VS Code UI):

[build]
target = "x86_64-apple-darwin"

No problem, thanks for pointing out the issue.

Don't worry, I like your suggested solution, and it shows that it's multiple ways to accomplish the same thing :) You should be happy. Getting something like this to work is always gratifying, and you learn a lot by poking around and learning new stuff. Great job!

I'll decide which solution to keep today, one has the benefit of not changing the brackets, the other keeps the mov keyword the same. I like both TBH.

And yeah, you can set the build target in config.toml as well. I use that regularly when cross compiling for something like the Raspberry PI for example 👍

I re-tried the change your suggestion today, and I can't get the correct results by just removing the brackets.

I'm pretty sure I got the expected results yesterday on my M3 Mac. According to the ARMv8 developer's reference manual (page 725), mov only copies the contents of the source register (which means the pointer and not the data the pointer points to). This is pretty much the same as x86-64, but what aarch64 doesn't seem to like is the square brackets that should indicate to the assembler that we want to fetch the data from the memory location and move that into the destination register. That doesn't seem to work well with aarch64, but is pretty commonplace to do with x86-64.

By looking deeper into the ARM64 assembly reference, it seems like the preferred way to accomplish the same with aarch64 is asm!("ldr {0}, [{1}]", out(reg) res, in(reg) ptr), so I'll go with that one.

Nono, that solution I suggested is incorrect, it was my misunderstanding of mov in arm64 assembly. I assumed it would be more similar to x86-64, but it is apparently very different. So the solution you had is the only correct one.

As I said, I just got excited when it compiled and I didn't notice it didn't produce the correct result :)

mov the way I was doing it was just moving the value (the address) into the output register rather than dereferencing it.

Sorry for the confusion!

Aha, I see :) Well, thanks for suggesting anyway and at least we found a working solution.

This is now fixed by #13.