Win32: no_std, no_main, no libc?

When coding little windows console programs I try to avoid to C-Runtime.
I just use the Win32 API to get small, statically linked programms.
Often a few kilobytes in size. for example: https://github.com/blaubart69/findp

Very little sample. Just returing error code 99 from the little EXE (no_CRT.c):

#define WIN32_LEAN_AND_MEAN  // Exclude rarely-used 
#define STRICT
#include <windows.h>

void mainCRTStartup(void){
  ExitProcess(99);
}

compile and link with:
cl.exe no_CRT.c /link /subsystem:console /NODEFAULTLIB kernel32.lib

Now I read about #![no_std], #![no_main] and wonder if I can do that same with Rust.
Also using the winapi crate as the documentation says:

By default the std feature of winapi is disabled, allowing you to write Windows applications using nothing but core and winapi.

And also not using any C-Runtime!
So after a few days of fiddling around I’m still out of luck with this piece of code:
main.rs

#![feature(lang_items,no_std,no_main,start)]
#![no_std]
#![no_main]
#![windows_subsystem = "console"]
#![cfg(processthreadsapi)]

use core::panic::PanicInfo;

#[entry]
#[no_mangle]
pub extern "system" fn mainCRTStartup()  {
    unsafe { winapi::um::processthreadsapi::ExitProcess(99); }
}
#[panic_handler]            #[no_mangle] pub extern "C" fn panic(_info: &PanicInfo) -> ! { loop {} }
#[lang = "eh_personality"]  #[no_mangle] pub extern "C" fn eh_personality() {}

cargo.toml looks like this:

[package]
name = "bee_no_std"
version = "0.1.0"
edition = "2018"
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
[dependencies]
winapi = "0.3"

building with cargo +nightly build gives me:

error[E0601]: `main` function not found in crate `bee_no_std`
  = note: consider adding a `main` function to `src\main.rs`

Hope someone can enlighten me. :slight_smile:
Thank you very much for your help!

It might be worth reading A freestanding Rust binary.

The minimal example from that link goes something like this. First add panic=“abort” to your Cargo.toml

[package]
name = "nostd"
version = "0.1.0"
authors = ["THE AUTHOR"]
edition = "2018"

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"

Then your main should look like this:

#![no_std] // don't link the Rust standard library
#![no_main] // disable all Rust-level entry points

use core::panic::PanicInfo;

#[no_mangle] // don't mangle the name of this function
pub extern "C" fn _start() -> ! {
    // this function is the entry point, since the linker looks for a function
    // named `_start` by default
    loop {}
}

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

And you’d compile it using rustc more directly.

cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"

And run it using:

.\target\debug\nostd.exe
1 Like

Thank you for your help!
In the meantime I found what was wrong.
Just by try and error. :slight_smile:

In main.rs there was the line

#![cfg(processthreadsapi)]

to “import” the ExitProcess() API from the winapi crate.
So I thought.

But this gaves me the error:

main function not found in crate bee_no_std

I deleted this line in main.rs and added the following to cargo.toml:

[dependencies]
winapi = { version = "0.3.7", features = ["processthreadsapi"] }

Turn out! Working! After days!! :slight_smile:

Working sample:

3 Likes

you know that the Rust forum accepts markdown? https://guides.github.com/features/mastering-markdown/

The important part is the syntax highlighting. :hugs:

Thanks you for the link!
I’m an old man. :slight_smile:
I’ll try my best next time. :wave:

Why don’t you edit your first post? :wink: Other people will read it and you can help them understand it properly by formatting the code. Please edit it :heart: