How create .obj file from Rust code (without core::panicking::panic)

I need simple .o object code file without any dependencies like
core::panicking::panic

How creating my C code or how create Cargo.toml for this?

I have simple function

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

You can ask rustc to emit object files with rustc lib.rs --emit=obj.

Cargo can be told to pass extra flags down to rustc with cargo rustc, so when compiling you could run cargo rustc -- --emit=obj and the object files will be somewhere under target/ (exact location depends on your crate's name).

Not including core::panicking::panic seems oddly specific. Are you able to explain why you need the object files without core::panicking::panic? If so, we may be able to find a better solution.

Yes,
I need clear .obj because I need create program without thread, gcc_s etc.
I need create minimal program

or

static

now I get

linux-vdso.so.1 (0x00007ffca7ffc000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f68cf15e000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f68cf144000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f68cf13d000)
libc.so.6 => /lib64/libc.so.6 (0x00007f68cef74000)
/lib64/ld-linux-x86-64.so.2 (0x00007f68cf1ab000)

You may find MUSL support for fully static binaries useful. It lets you generate an executable/library which is fully statically linked.

I need obj no static rust program.
I write a library in Rust no whole program

I think what you're looking for is #![no_std], which allows you to write a program that doesn't rely on the Rust stdlib (and hence on Rust stdlib dependencies like libc, libpthread...).

1 Like

@HadrienG Can You show any working example? I read many tutorials but any not working.

src/lib.rs

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

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

Cargo.toml

[lib]
crate-type = [ "staticlib" ] # to generate a `lib<package_name>.a`
                             # i.e. an archive of `.o` files

[package]
name = "foo"
version = "0.1.0"
edition = "2018"

[dependencies] # you may depend on libc if you so wish:
# libc = { version = "*", default-features = false }

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

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

so that cargo build and cargo build --release will compile a libfoo.a in the ./target/{debug,release}/ directories

C file (e.g., bar.c)

#include <inttypes.h> // for int32_t, PRId32, etc.
#include <stdio.h>
#include <stdlib.h>

int32_t suma (int32_t a, int32_t b);

int main (int argc, char const * const argv[])
{
    printf("%" PRId32 "\n", suma(42, 27));
    return EXIT_SUCCESS;
}

Compilation command

cc -o bar{,.c} -l foo -L ./target/debug/  # or ./target/release/
  • Feel free to throw a -static in there
3 Likes

@Yandros Your code works fine with -static options.

Many tkanks. I lost week for this problem.

I have one small question: Is possible create normal object .o in Rust too?
I create it with:

rustc --crate-type=staticlib --print native-static-libs --emit=obj -C panic=abort src/lib.rs -o foo.o

but can't compiling

clang -W -Wall -O0 -std=c11 -pedantic -pedantic-errors --static -o mainzo foo.o main.o

lib.3a1fbbbh-cgu.0:(.text.suma+0x1e): undefined reference to `core::panicking::panic'
clang-6.0: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:19: mainzo] Błąd 1

but everything else work fine. THANKS!!!

If you want a Rust crate to be usable from C, you should be compiling as the cdylib crate type.

See also:

As I reminded in the comment written in th .toml file, a libsmth.a "static library" is an archive of .o files, so you can always unarchive them and work with the .o files directly if you so wish (I think it's a pretty fragile thing to do, the .o files are bundled for a reason, but just for science know that you can do it):

For this very simple example the following command succeeded:

cc -o bar{,.c} extracted/foo-7614dab58c0f1398.4pz13prj75amce65.rcgu.o

@Yandros I'm not sure, what You segest.
I create forum version of code for better communication: https://gitlab.com/0xtrzy/returnrustfunctionfromc/-/tree/master/forum

instruction $make create a static exec file form library .a

if You type: make mainzo

Make create a foo.o file

rustc --crate-type=staticlib --print native-static-libs --emit=obj -C panic=abort src/lib.rs -o foo.o

But, this file have too many functions.

clang -W -Wall -O0 -std=c11 -pedantic -pedantic-errors --static -o mainzo foo.o main.o
foo.o: In function suma': lib.3a1fbbbh-cgu.0:(.text.suma+0x1e): undefined reference to core::panicking::panic'
clang-6.0: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:19: mainzo] Błąd 1

You can look what are inside foo.o

$nm foo.o
0000000000000000 T rust_begin_unwind
0000000000000000 r str.0
0000000000000000 r str.1
0000000000000000 T suma
U _ZN4core9panicking5panic17h51226486788c5f84E

if I extract a foo from libfoo.a

$ar x ar x libfoo.a

I get

$nm foo-d414f01448490e63.1uby80184uel37yz.rcgu.o
0000000000000000 T rust_begin_unwind
0000000000000000 V rustc_debug_gdb_scripts_section
0000000000000000 T suma

still not possible join for my C code.
Sorry, I'm not good programmer. Meybe This are very simple. Meybe repo on gitlab will help for explaining to me.

This is emitted when debuginfo is enabled to tell gdb to load pretty printers for several types like Vec and HashMap.

Is there any reason you don't compile with --crate-type=staticlib and then link the .a file, not any .o files in it?

@bjorn3

Is there any reason you don't compile with

size

Try enabling LTO. It should remove all dead code. I don't know if it works for staticlibs though.

@bjorn3 Do You have code, makefile
show ours how

$ cat example.rs
#![no_std]

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

#[no_mangle]
pub extern "C" fn suma(a: i32, b: i32) -> i32
{
  a + b
}
$ rustc --crate-type staticlib -Cpanic=abort -Clto -Cdebuginfo=0 -Coverflow-checks=no example.rs -o libexample.a

The resulting .a file will still contain unnecessary object files like clzti2.o, but those will simply be omitted during linking when no functions in them are used. These object files are part of compiler_builtins, which is a set of functions that are called when you are doing something that your processor doesn't have native support for, like multiplying 128bit integers or raising a float to a given power. The only thing you may want to do is stripping all debuginfo after you linked everything together by using strip -d linked_program. While -Cdebuginfo=0 disabled debuginfo for the current program, it didn't remove it from the already compiled libcore.

If you want to use cargo, you can add lto = false on a new line after both overflow-checks = false in the example of @Yandros.

$ cat main.c
#include <stdint.h>

int32_t suma(int32_t, int32_t);

int main(int argc, char* argv) {
    return suma(1, 2);
}
$ gcc -c main.c -o main.o 
$ gcc main.o libexample.a -o main
$ nm main
0000000000004028 B __bss_start
0000000000004028 b completed.7325
                 w __cxa_finalize@@GLIBC_2.2.5
0000000000004018 D __data_start
0000000000004018 W data_start
0000000000001070 t deregister_tm_clones
00000000000010e0 t __do_global_dtors_aux
0000000000003e20 t __do_global_dtors_aux_fini_array_entry
0000000000004020 D __dso_handle
0000000000003e28 d _DYNAMIC
0000000000004028 D _edata
0000000000004030 B _end
00000000000011c4 T _fini
0000000000001120 t frame_dummy
0000000000003e18 t __frame_dummy_init_array_entry
0000000000002144 r __FRAME_END__
0000000000004000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000001000 t _init
0000000000003e20 t __init_array_end
0000000000003e18 t __init_array_start
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
00000000000011c0 T __libc_csu_fini
0000000000001160 T __libc_csu_init
                 U __libc_start_main@@GLIBC_2.2.5
0000000000001125 T main
00000000000010a0 t register_tm_clones
0000000000001040 T _start
0000000000001150 T suma
0000000000004028 D __TMC_END__

The only symbols not coming from the C runtime are main and suma, which are precisely the symbols that we want.

$ ls -l main
-rwxr-xr-x 1 bjorn bjorn 41744 apr  8 12:14 main
$ strip -d main
$ ls -l main
-rwxr-xr-x 1 bjorn bjorn 16368 apr  8 12:15 main
1 Like

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