Rust in embedded C demo, slim down archive?

Hi all,

I come from a embedded C background (ARM in my example below) and would like to have a few Rust functions in my demo application. So I put a function inside of a Rust crate, export it and link it to a larger embedded C application. I already figured out how to cross-compile everything correctly, so that is OK. Let's just assume that my exported function is only doing addition of two integers. I have this:

#![no_std]

#[no_mangle]
pub extern "aapcs" fn plus(a: i32, b: i32) -> i32 {
    a + b
}

use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

Linking this to my applications and calling the function works. Nice! However, I observe two problems:

  1. There are a ton of symbols that are exported in the resulting archive. How do I get rid of them? I expect there to be not much more than my plus function...
  2. My final executable increased from ~ 85 KB to ~120 KB even with LTO switched on. How could that happen? (Will investigate some more on my side, but no clue so far.)

My view here is through the C lens, I expect the object archive to contain barely anything except my functions. How do I get there?

Specifically what symbols remain? Can you get rid of them by stripping the executable?

That simply removed everything. I am on windows, so something might be wrong with my strip executable. I can't post the list of symbols here, the forum won't allow me to paste this long output. I also can't attach a txt-file.

Wow, I just tried the same on my machine (nightly rust, linux) and the static library seems to include all of core, even though plus() should only be a couple instructions. I'd expect it to be quite small because compiling in release should have removed any overflow checks, meaning we don't need to pull in any panicking or formatting machinery.

Using the code you've provided, compiling a staticlib, cdylib, and rlib gives 4.7M, 638k, and 12k respectively... This may be a codegen bug in rustc. Would you be able to report it?

My steps to reproduce:

$ rustc --version --verbose
rustc 1.45.0-nightly (7ebd87a7a 2020-05-08)
binary: rustc
commit-hash: 7ebd87a7a1e0e21767422e115c9455ef6e6d4bee
commit-date: 2020-05-08
host: x86_64-unknown-linux-gnu
release: 1.45.0-nightly
LLVM version: 9.0
$ cd /tmp
$ cargo new --lib no_std
$ cat Cargo.toml
version = "0.1.0"
authors = ["Michael-F-Bryan <michaelfbryan@gmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

[lib]
crate-type = ["cdylib", "rlib", "staticlib"]

$ cat src/lib.rs
#![no_std]
#![feature(lang_items)]

use core::panic::PanicInfo;

#[no_mangle]
pub extern "aapcs" fn plus(a: i32, b: i32) -> i32 {
    a + b
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

#[lang = "eh_personality"]
extern "C" fn rust_eh_personality() {}

$ cargo build && cargo build --release
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
    Finished release [optimized] target(s) in 0.00s

$ ls -la target/debug
.rw-r--r--    0 michael 12 May  0:00 .cargo-lock
drwxr-xr-x    - michael 12 May  0:00 .fingerprint
drwxr-xr-x    - michael 12 May  0:00 build
drwxr-xr-x    - michael 12 May  0:01 deps
drwxr-xr-x    - michael 12 May  0:00 examples
drwxr-xr-x    - michael 12 May  0:00 incremental
.rw-r--r-- 4.7M michael 12 May  0:01 libno_std.a
.rw-r--r--   61 michael 12 May  0:09 libno_std.d
.rw-r--r--  12k michael 12 May  0:01 libno_std.rlib
.rwxr-xr-x 638k michael 12 May  0:01 libno_std.so

$ ls -la target/release
.rw-r--r--    0 michael 12 May  0:04 .cargo-lock
drwxr-xr-x    - michael 12 May  0:04 .fingerprint
drwxr-xr-x    - michael 12 May  0:04 build
drwxr-xr-x    - michael 12 May  0:04 deps
drwxr-xr-x    - michael 12 May  0:04 examples
drwxr-xr-x    - michael 12 May  0:04 incremental
.rw-r--r-- 4.7M michael 12 May  0:04 libno_std.a
.rw-r--r--   63 michael 12 May  0:09 libno_std.d
.rw-r--r-- 3.0k michael 12 May  0:04 libno_std.rlib
.rwxr-xr-x 4.5k michael 12 May  0:04 libno_std.so

$ nm target/release/libno_std.a | wc
nm: rustc_std_workspace_core-428d15b56101bdc7.rustc_std_workspace_core.cipgz1ol-cgu.0.rcgu.o: no symbols
   1839    4339  134935
Loads of symbols
$ nm target/release/libno_std.rlib

no_std.no_std.dof6u294-cgu.0.rcgu.o:
0000000000000000 T plus
0000000000000000 T rust_begin_unwind
0000000000000000 T rust_eh_personality
nm: lib.rmeta: file format not recognized

$ nm target/release/libno_std.so
00000000000036f8 b completed.7393
                 w __cxa_finalize
00000000000014a0 t deregister_tm_clones
0000000000001510 t __do_global_dtors_aux
0000000000002578 d __do_global_dtors_aux_fini_array_entry
00000000000036f0 d __dso_handle
0000000000002588 d _DYNAMIC
0000000000001490 t _fini
0000000000001560 t frame_dummy
0000000000002580 d __frame_dummy_init_array_entry
0000000000000440 r __FRAME_END__
00000000000026d8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000001474 t _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000001570 T plus
00000000000014d0 t register_tm_clones
00000000000036f0 d __TMC_END__
00000000000036f0 d __TMC_LIST__

$ nm target/release/libno_std.a

no_std.no_std.dof6u294-cgu.0.rcgu.o:
0000000000000000 T plus
0000000000000000 T rust_begin_unwind
0000000000000000 T rust_eh_personality

compiler_builtins-e77b8f5da9460407.compiler_builtins.52gk5tdd-cgu.0.rcgu.o:
00000000 T _ZN17compiler_builtins5float3pow9__powidf217hed52a90ee6edf6aeE
00000000 T _ZN17compiler_builtins5float3pow9__powisf217hba9cb49bb2f435d1E
         U _ZN51_$LT$i32$u20$as$u20$compiler_builtins..int..Int$GT$12aborting_div17hf2a733f737baeb52E

compiler_builtins-e77b8f5da9460407.compiler_builtins.52gk5tdd-cgu.1.rcgu.o:
00000000 T __rust_u128_subo
         U _ZN17compiler_builtins3int6addsub16__rust_u128_subo17h31a156a26359cca4E

compiler_builtins-e77b8f5da9460407.compiler_builtins.52gk5tdd-cgu.10.rcgu.o:
00000000 T __mulodi4
         U _ZN17compiler_builtins3int3mul9__mulodi417h7a681f6af9bcd32eE

compiler_builtins-e77b8f5da9460407.compiler_builtins.52gk5tdd-cgu.100.rcgu.o:
00000000 T __multi3
         U _ZN17compiler_builtins3int3mul8__multi317h8c28629b745f2b68E

compiler_builtins-e77b8f5da9460407.compiler_builtins.52gk5tdd-cgu.101.rcgu.o:
00000000 T __eqsf2
         U _ZN17compiler_builtins5float3cmp7__eqsf217hdf1110fafc9c0512E

compiler_builtins-e77b8f5da9460407.compiler_builtins.52gk5tdd-cgu.102.rcgu.o:
00000000 T __divdf3
         U _ZN17compiler_builtins5float3div8__divdf317h07279c37c26b60f9E

compiler_builtins-e77b8f5da9460407.compiler_builtins.52gk5tdd-cgu.103.rcgu.o:
00000000 T _ZN17compiler_builtins3int5shift16__rust_i128_shlo17hca137f6405ba4143E
00000000 T _ZN17compiler_builtins3int5shift16__rust_i128_shro17h55b5c06abcfecd97E
00000000 T _ZN17compiler_builtins3int5shift16__rust_u128_shlo17h639360f13fc779a2E
00000000 T _ZN17compiler_builtins3int5shift16__rust_u128_shro17h0adf5ae26871f1c8E
00000000 T _ZN17compiler_builtins3int5shift9__ashldi317h0c12112ab7795618E
00000000 T _ZN17compiler_builtins3int5shift9__ashlti317h10dab8e5b68ce913E
00000000 T _ZN17compiler_builtins3int5shift9__ashrdi317h004295b3a6230368E
00000000 T _ZN17compiler_builtins3int5shift9__ashrti317h74dbd675c4f53c88E
00000000 T _ZN17compiler_builtins3int5shift9__lshrdi317h45f263dc98a5dcc8E
00000000 T _ZN17compiler_builtins3int5shift9__lshrti317he0ee76bdaee12a51E
         U _ZN51_$LT$i32$u20$as$u20$compiler_builtins..int..Int$GT$8unsigned17h1fd8756b3dde7736E
         U _ZN51_$LT$i64$u20$as$u20$compiler_builtins..int..Int$GT$8unsigned17hafebac0fe51d1419E
...
00000000 T _ZN96_$LT$core..str..lossy..Utf8LossyChunksIter$u20$as$u20$core..iter..traits..iterator..Iterator$GT$4next17h4b8ac9d45a36c079E
00000000 T _ZN99_$LT$core..num..TryFromIntError$u20$as$u20$core..convert..From$LT$core..convert..Infallible$GT$$GT$4from17h9bca48cd790ea862E

Thanks for reproducing. Glad you see this issue too... I will report a bug.

Funny, somebody else tried practically the exact same thing as me just a month ago: How create .obj file from Rust code (without core::panicking::panic)

Didn't find this thread when creating this one. Sorry for that.

1 Like

Hang on, I misread you symbol list. I don't see the core symbols in my case on Rust 1.43.1. So this might be a different issue in nightly. Will check on that later.

For some reason my linker wants to pull in everything from compiler_builtins.o. Need to figure out why... Solved: This is resolved when specifying "overflow-checks=false". Not true after all. Still need to investigate...

What I also don't get, is why I still see all these .ARM.exidx.* sections. I am using panic="abort" and to my understanding these are used for stack unwinding. Or is this a misunderstanding? When I am aborting, there should not be any unwinding going on, I think. Found info: I found some info on this in this closed issue: https://github.com/rust-lang/rust/issues/62781. It is suggested to discard the sections.

Yeah basically one important step here is to make sure you do not include the formatting logic necessary for the panic runtime, by adding panic = "abort" to your Cargo.toml:

[profile.dev]
panic = "abort"
overflow-checks = false

[profile.release]
panic = "abort"
2 Likes

Got that, thanks.

The issue about .ARM.exidx.* sections is really bothering me right now. The linker that I am using does not seem to allow to discard sections when putting together the final excecutable, so I can't follow the same way as in the linked issue above. How do I get rid of them in advance?

OK, got it! Was using the linker incorrectly.

SECTIONS
{
    /DISCARD/ : {"*(.ARM.exidx.*)"}

etc.
} 

helps. This seems to be an undocumented feature for my linker. Strange... but glad it works.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.