summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/linker.rs28
-rw-r--r--src/main.rs23
-rw-r--r--tests/sdl.c30
3 files changed, 75 insertions, 6 deletions
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<LinkInfo> {
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<LinkInfo> {
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 <main/entry/something_else>(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<path::Path>, entry: &str) -> Result<(), String> {
+ pub fn link_to_file(&self, path: impl AsRef<path::Path>, entry: &str) -> Result<LinkInfo, String> {
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<String>,
+ /// 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 <SDL2/SDL.h>
+#include <GL/glcorearb.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+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());
+}