no_stdExecutable files in the environment

Author: Wu Feixiang @Pymongo/Post editor: Zhang Handong

No_std binary

Since the author only has Linux operating system devices around, this article only discusses the executable files of Rust/C/C++ under Linux operating system no_STD

This article is more about compiling and generating a purely statically linked no_STD executable without dynamic links. It is not only the Rust standard library, but also the OPERATING system’s own C standard library

Making Our Own Executable Packer (Linux)

Before explaining how Rust compiles executables that run no_STD, let’s look at how assembly and C/C++ compile executables for no_std

Assembler language compiles executable files

X86 assembly has two main syntax, one is AT&T syntax for Unix and the other is Intel syntax for Windows

Since AT&T owns Bell LABS, which invented both the Unix operating system and the C language, both GCC and AS for Linux use AT&T assembly syntax

If you want to use Intel assembly syntax you can use LLVM or NASM tools

The assembly generated by RUSTC defaults to Intel syntax, and you can pass the LLVM parameter to ruSTC to generate assembly code for AT&T syntax

rustc –emit asm -C llvm-args=-x86-asm-syntax=att main.rs

Refer to the first section of assembly code described in the GNU Assembler Examples section of this site

Compilation runs this code in two ways:

gcc -c s.s && ld s.o && ./a.out

Or use the AS tool (GNU Assembler (GNU Binutils))

as s.s && ld s.o && ./a.out

Use the LDD tool to verify that compiled executables are statically linked (no dynamic link libraries introduced)

The disadvantage of assembly is that the code is tied to the hardware architecture. GCC compiles this assembly code with the -m32 parameter specifying that a 32-bit executable is generated

C Compiles the no_std executable

It’s easy to generate an executable without a dynamically linked library using GCC or clang’s -nostdlib parameter

[w@w-manjaro temp]$ echo "int main(){return 0; }" > main.c && gcc -nostdlib main.c && ldd ./a.out /usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000001000 statically linkedCopy the code

C In the no_std environment, the entry function name cannot be main, should be changed to _start

[w@w-manjaro temp]$ echo "int _start(){return 0; }" > main.c && gcc -nostdlib main.c && ldd ./a.out statically linkedCopy the code

It is also possible to use GCC with the -m32 argument to generate a 32-bit executable

Note that using GCC or clang’s -nostdlib parameter on MAC or Windows might cause an error

$ clang -nostdlib c.c
ld: dynamic main executables must link with libSystem.dylib for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Copy the code

According to the Apple developer documentation, Apple does not support statically linked binaries on Mac OS X

MacOS may need special LD tools or slightly more complicated methods to compile purely statically linked executables, but that is beyond the scope of this article

Rust compiles no_STD executables

#! [no_std]
#! [no_main]
#! [feature(lang_items,asm)]

/// entry_point/start_address of process, since the linker looks for a function named `_start` by default
#[no_mangle]
extern "C" fn _start() -> ! {
    exit(0); // macOS: illegal hardware instruction
}

fn exit(code: isize) -> ! {
    unsafe{ asm! ("syscall".in("rax") 60.// exit
            in("rdi") code, options(noreturn) ); }}#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[panic_handler]
fn my_panic(_info: &core::panic::PanicInfo) -> ! {
    loop{}}Copy the code

Source code in my warehouse, Linux under the compilation method:

rustc -C link-arg=-nostartfiles main.rs

Or write the following two lines to cargo/config.toml

[target.'cfg(target_os = "linux")']
rustflags = ["-C", "link-arg=-nostartfiles"]
Copy the code

If you only compile dynamically linked libraries (cdylib) in the NO_STD environment, you do not need to add the above ruSTC parameter

Contents: Rust Chinese Collection (Rust_Magazine) march issue