diff --git a/.cargo/config.toml b/.cargo/config.toml index d9f659e..2623c5a 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,29 +3,14 @@ # it as a post-link step. # See: # +# +# Binary-specific link flags live in microfetch/build.rs via cargo:rustc-link-arg-bin +# so they only affect the final binary and don't break proc-macro or build-script linking. [target.'cfg(target_os = "linux")'] linker = "scripts/ld-wrapper" rustflags = [ - # No C runtime, we provide _start ourselves - "-C", - "link-arg=-nostartfiles", - # Fully static, no dynamic linker, no .interp/.dynsym/.dynamic overhead - "-C", - "link-arg=-static", - # Static PIE is incompatible with -static :( - "-C", - "relocation-model=static", # Suppress .eh_frame emission from our own codegen (does not cover compiler_builtins; # those remnants are removed by the linker wrapper via objcopy post-link) "-C", "force-unwind-tables=no", - # Linker flags - "-C", - "link-arg=-Wl,--gc-sections", # remove unreferenced input sections - "-C", - "link-arg=-Wl,--strip-all", # strip all symbol table entries - "-C", - "link-arg=-Wl,--build-id=none", # omit the .note.gnu.build-id section - "-C", - "link-arg=-Wl,-z,norelro", # disable RELRO (removes relro_padding) ] diff --git a/microfetch/build.rs b/microfetch/build.rs new file mode 100644 index 0000000..3f43fef --- /dev/null +++ b/microfetch/build.rs @@ -0,0 +1,17 @@ +fn main() { + // These flags only apply to the microfetch binary, not to proc-macro crates + // or other host-compiled artifacts. + + // No C runtime, we provide _start ourselves + println!("cargo:rustc-link-arg-bin=microfetch=-nostartfiles"); + // Fully static, no dynamic linker, no .interp/.dynsym/.dynamic overhead + println!("cargo:rustc-link-arg-bin=microfetch=-static"); + // Remove unreferenced input sections + println!("cargo:rustc-link-arg-bin=microfetch=-Wl,--gc-sections"); + // Strip all symbol table entries + println!("cargo:rustc-link-arg-bin=microfetch=-Wl,--strip-all"); + // Omit the .note.gnu.build-id section + println!("cargo:rustc-link-arg-bin=microfetch=-Wl,--build-id=none"); + // Disable RELRO (removes relro_padding) + println!("cargo:rustc-link-arg-bin=microfetch=-Wl,-z,norelro"); +} diff --git a/scripts/ld-wrapper b/scripts/ld-wrapper index cf2cb21..c907b83 100755 --- a/scripts/ld-wrapper +++ b/scripts/ld-wrapper @@ -2,20 +2,23 @@ # Invoke mold, then strip junk sections from the output binary with objcopy. # This (more or less) removes sections that mold cannot discard itself, suck as: # - .eh_frame / .eh_frame_hdr - unwind tables from compiler_builtins -# - dynstr - mold emits this, even for fully static binaries +# - .dynstr - mold emits this, even for fully static binaries # - .comment - compiler version string # # We forward everything to mold via -fuse-ld, then post-process the output in place. set -eu -# Locate the output file +# Locate the output file and detect static linking +IS_STATIC=0 OUTPUT="" prev="" for arg in "$@"; do + case "$arg" in + -static) IS_STATIC=1 ;; + esac if [ "$prev" = "-o" ]; then OUTPUT="$arg" - break fi prev="$arg" done @@ -23,8 +26,9 @@ done # Invoke mold via the cc driver, forward all original arguments cc -fuse-ld=mold "$@" -# Remove sections that mold cannot discard -if [ -n "$OUTPUT" ] && [ -f "$OUTPUT" ]; then +# Only strip sections from fully static binaries. +# Dynamic executables (i.e. build scripts, proc-macros) need .dynstr at runtime. +if [ "$IS_STATIC" = 1 ] && [ -n "$OUTPUT" ] && [ -f "$OUTPUT" ]; then objcopy \ --remove-section=.eh_frame \ --remove-section=.eh_frame_hdr \