Skip to content
This repository has been archived by the owner on Jan 24, 2022. It is now read-only.

empty thumb binary on macOS with 1.31.0 to 1.41.1 #251

Closed
jac-cbi opened this issue Mar 3, 2020 · 7 comments
Closed

empty thumb binary on macOS with 1.31.0 to 1.41.1 #251

jac-cbi opened this issue Mar 3, 2020 · 7 comments

Comments

@jac-cbi
Copy link

jac-cbi commented Mar 3, 2020

All,

I'm walking through the Rust Embedded Discovery book to familiarize myself with how Rust on microcontrollers works. I'm on a MacBook Pro with macOS 10.15.3 (Catalina) and up-to-date MacPorts for arm-none-eabi-{gcc,gdb,binutils}. Both OpenOCD and arm-none-eabi-gdb run fine and communicate. I first detected the error in Chapter 05, when I attempted to load the first binary built. I got the following result:

(gdb) load
Start address 0x0, load size 0
Transfer rate: 0 bits in <1 sec.

Diagnosis in #rust-embedded on Matrix revealed the following:

$ arm-none-eabi-size target/thumbv7em-none-eabihf/debug/led-roulette
   text    data     bss     dec     hex filename
      0       0       0       0       0 target/thumbv7em-none-eabihf/debug/led-roulette

So, I repeated the book in my Gentoo Linux VM, and received sane results. IOW, it looks like a bug in Rust on macOS.

I'm using rustup to install Rust, on vanilla macOS, latest MacPorts, and I'm using the source repository for the Discovery book: https://github.com/rust-embedded/discovery

I've tried every major version of Rust from 1.31.0 through 1.41.1 with similar results. Copying the binary to my Linux system yield the same output

$ arm-none-eabi-size target/thumbv7em-none-eabihf/debug/led-roulette
   text    data     bss     dec     hex filename
   1732       0       0    1732     6c4 target/thumbv7em-none-eabihf/debug/led-roulette
$ arm-none-eabi-size ~/led-roulette                                  text    data     bss     dec     hex filename
      0       0       0       0       0 /home/jason/led-roulette

You can see above that I get a sane build product on Linux, but the binary from macOS (in my home directory) is obviously not right.

I've no idea how to further debug this as I'm relatively new to Rust. I'm hoping that someone on macOS can reproduce this (you don't need the board, openocd, or gdb to test). and dig in a little further.

STR:

$ git clone https://github.com/rust-embedded/discovery
$ cd discovery
$ rustup update
$ cargo install itm --vers 0.3.1 # may not be necessary for reproducing
$ rustup component add llvm-tools-preview
$ cargo install cargo-binutils --vers 0.1.4
$ cd src/05-led-roulette
$ cargo build --target thumbv7em-none-eabihf
$ arm-none-eabi-size target/thumbv7em-none-eabihf/debug/led-roulette
### OR ###
$ cargo readobj --target thumbv7em-none-eabihf --bin led-roulette -- -file-headers

If you use cargo readobj ..., here's the difference between a good binary (built on Linux) and a bad binary (built on macOS)

--- ../../../good_readobj.txt   2020-03-03 16:35:14.000000000 -0500
+++ ../../../bad_readobj.txt    2020-03-03 16:39:15.000000000 -0500
@@ -1,5 +1,3 @@
-$ cargo readobj --target thumbv7em-none-eabihf --bin led-roulette -- -file-headers
-    Finished dev [unoptimized + debuginfo] target(s) in 0.07s

 ELF Header:
   Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
@@ -11,13 +9,13 @@
   Type:                              EXEC (Executable file)
   Machine:                           ARM
   Version:                           0x1
-  Entry point address:               0x800019D
+  Entry point address:               0x0
   Start of program headers:          52 (bytes into file)
-  Start of section headers:          853336 (bytes into file)
+  Start of section headers:          1288 (bytes into file)
   Flags:                             0x5000400
   Size of this header:               52 (bytes)
   Size of program headers:           32 (bytes)
-  Number of program headers:         2
+  Number of program headers:         3
   Size of section headers:           40 (bytes)
-  Number of section headers:         22
-  Section header string table index: 20
+  Number of section headers:         15
+  Section header string table index: 13
@jac-cbi
Copy link
Author

jac-cbi commented Mar 3, 2020

Update: I had a stale environment variable in my shell. Specifically, RUSTFLAGS=-L/usr/lib/libiconv. After I unset that, everything worked as expected:

$ arm-none-eabi-gdb -q target/thumbv7em-none-eabihf/debug/led-roulette
Reading symbols from target/thumbv7em-none-eabihf/debug/led-roulette...done.
(gdb) target remote :3333
Remote debugging using :3333
0x08003cc8 in ?? ()
(gdb) load
Loading section .vector_table, size 0x188 lma 0x8000000
Loading section .text, size 0x674 lma 0x8000188
Loading section .rodata, size 0x2c4 lma 0x8000800
Start address 0x800019c, load size 2752
Transfer rate: 8 KB/sec, 917 bytes/write.

Woo-hoo! Thanks to @jonas-schievink for the hint!

Now, to prevent future foot guns, could I get a "WARN: $RUSTFLAGS overrides .cargo/config" ?

@jonas-schievink
Copy link
Contributor

I tried to make cortex-m-rt detect this, by having #[entry] reference an extern { static linker_script_missing: u8; }, and have it defined in link.x, but when -Tlink.x is missing the linker will use the default linker script, which simply discards everything before it could notice the missing symbol. If anyone has an alternative idea of implementing this, please let me know, since I'm out of ideas now.

The best way to fix this would be via proper #[link_args] support: rust-lang/rust#29596.

@jac-cbi
Copy link
Author

jac-cbi commented Mar 3, 2020

Well, imho, this needs to happen in the toolchain: if RUSTFLAGS is set and .cargo/config exists, throw an error. There's no valid use case for both, right?

@jonas-schievink
Copy link
Contributor

That seems to be tracked in rust-lang/cargo#5376, but that looks stalled.

@jonas-schievink
Copy link
Contributor

I tried doing some linker trickery to detect this mistake, but couldn't find any way to do it so far.

One remaining idea: Put a function that refers to an undefined symbol into a section used only by the default linker script. When linking with the correct linker script, the function will be disposed and the program doesn't fail to link. (This is basically the opposite of what I tried and failed to do earlier).

@jonas-schievink
Copy link
Contributor

Ah, I don't think there is a default linker script since Rust links with LLD directly instead of calling a driver like GCC. Oh well.

@jonas-schievink
Copy link
Contributor

Closing as wontfix/upstream issue, as per the discussion above.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants