From 0049dc9cf781c65f5a633f51f0e705274853060c Mon Sep 17 00:00:00 2001 From: pommicket Date: Tue, 8 Nov 2022 18:36:04 -0500 Subject: more info, SDL example --- src/linker.rs | 28 +++++++++++++++++++++++----- src/main.rs | 23 ++++++++++++++++++++++- tests/sdl.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 tests/sdl.c diff --git a/src/linker.rs b/src/linker.rs index fdc1f5b..c82d1d3 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -55,6 +55,14 @@ std::ofstream cout("/dev/stdout"); std::ifstream cin("/dev/stdin"); ``` or use `printf`, `scanf` for smaller executables. + +Notes on executable size: + +- A bare minimum executable with libc is ~300 bytes, and + without libc is ~100 bytes. +- Each external symbol requires 21 + 8n + l bytes in total, + where l is the length of the name, and n is the number of times + it is used. It (thankfully) doesn't seem to be worth it to use `dlsym`. */ use crate::elf; @@ -711,7 +719,7 @@ impl LinkerOutput { } /// output the executable. - pub fn write(&self, mut out: impl Write + Seek, entry_point: u64) -> LinkResult<()> { + pub fn write(&self, mut out: impl Write + Seek, entry_point: u64) -> LinkResult { let u64_to_u32 = LinkError::u64_to_u32; let usize_to_u32 = LinkError::usize_to_u32; @@ -882,11 +890,21 @@ impl LinkerOutput { }; out.write_all(&phdr_dynamic.to_bytes())?; } - - Ok(()) + + out.seek(io::SeekFrom::End(0))?; + Ok(LinkInfo { + data_size: self.data.len() as u64, + exec_size: out.stream_position()? + }) } } +/// info about linked executable +pub struct LinkInfo { + pub exec_size: u64, + pub data_size: u64, +} + impl<'a> Linker<'a> { pub const DEFAULT_CFLAGS: [&str; 6] = [ "-Wall", @@ -1257,7 +1275,7 @@ impl<'a> Linker<'a> { } /// Link everything together. - pub fn link(&self, out: impl Write + Seek, entry: &str) -> LinkResult<()> { + pub fn link(&self, out: impl Write + Seek, entry: &str) -> LinkResult { let mut exec = LinkerOutput::new(0x400000); if self.bss_size > 0 { exec.set_bss(0x70000000, self.bss_size); @@ -1331,7 +1349,7 @@ impl<'a> Linker<'a> { /// Instead, define `void
(void)`, and make sure you call `exit`, /// or do an exit system interrupt at the end of the function --- if you just return, /// you'll get a segmentation fault. - pub fn link_to_file(&self, path: impl AsRef, entry: &str) -> Result<(), String> { + pub fn link_to_file(&self, path: impl AsRef, entry: &str) -> Result { let path = path.as_ref(); let mut out_options = fs::OpenOptions::new(); out_options.write(true).create(true).truncate(true); diff --git a/src/main.rs b/src/main.rs index 585d241..9ff86d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,8 @@ extern crate clap; +use std::io; +use io::Write; use clap::Parser; #[cfg(target_endian = "big")] @@ -52,6 +54,9 @@ struct Args { /// C++ compiler flags #[arg(long = "cxxflags", default_values = linker::Linker::DEFAULT_CXXFLAGS)] cxxflags: Vec, + /// verbose mode + #[arg(short = 'v', long = "verbose")] + verbose: bool, } fn main_() -> Result<(), String> { @@ -96,10 +101,26 @@ fn main_() -> Result<(), String> { } for input in inputs.iter() { + if args.verbose { + println!("processing source file {input}..."); + } linker.add_input(input)?; } - linker.link_to_file(&args.output, &args.entry) + if args.verbose { + print!("linking {}... ", args.output); + } + + io::stdout().flush().unwrap_or(()); + let info = linker.link_to_file(&args.output, &args.entry)?; + + if args.verbose { + println!("\x1b[92msuccess!\x1b[0m"); + println!("data size: {:7} bytes", info.data_size); + println!("executable size:{:7} bytes", info.exec_size); + } + + Ok(()) } fn main() { diff --git a/tests/sdl.c b/tests/sdl.c new file mode 100644 index 0000000..a3c3d8f --- /dev/null +++ b/tests/sdl.c @@ -0,0 +1,30 @@ +#define SDL_DISABLE_IMMINTRIN_H +#include +#include +#include +#include + +int main(void) { + SDL_Init(SDL_INIT_EVERYTHING); + SDL_Window *window = SDL_CreateWindow("hi", 0, 0, 1280, 720, SDL_WINDOW_SHOWN|SDL_WINDOW_OPENGL); + SDL_GLContext ctx = SDL_GL_CreateContext(window); + PFNGLCLEARPROC glClear = SDL_GL_GetProcAddress("glClear"); + PFNGLCLEARCOLORPROC glClearColor = SDL_GL_GetProcAddress("glClearColor"); + SDL_GL_SetSwapInterval(1); + while (true) { + SDL_Event event; + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + return 0; + } + } + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + SDL_GL_SwapWindow(window); + } + (void)ctx; +} + +void entry(void) { + exit(main()); +} -- cgit v1.2.3