Skip to content

Use LTO instead of removing the panic handler manually. Closes #309 #318

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bin/thumbv6m-none-eabi-lto.a
Binary file not shown.
Binary file modified bin/thumbv6m-none-eabi.a
Binary file not shown.
Binary file modified bin/thumbv7em-none-eabi-lto.a
Binary file not shown.
Binary file modified bin/thumbv7em-none-eabi.a
Binary file not shown.
Binary file modified bin/thumbv7em-none-eabihf-lto.a
Binary file not shown.
Binary file modified bin/thumbv7em-none-eabihf.a
Binary file not shown.
Binary file modified bin/thumbv7m-none-eabi-lto.a
Binary file not shown.
Binary file modified bin/thumbv7m-none-eabi.a
Binary file not shown.
Binary file modified bin/thumbv8m.base-none-eabi-lto.a
Binary file not shown.
Binary file modified bin/thumbv8m.base-none-eabi.a
Binary file not shown.
Binary file modified bin/thumbv8m.main-none-eabi-lto.a
Binary file not shown.
Binary file modified bin/thumbv8m.main-none-eabi.a
Binary file not shown.
Binary file modified bin/thumbv8m.main-none-eabihf-lto.a
Binary file not shown.
Binary file modified bin/thumbv8m.main-none-eabihf.a
Binary file not shown.
4 changes: 0 additions & 4 deletions xtask/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,3 @@ harness = false

[dependencies]
ar = "0.8.0"

[dependencies.object]
version = "0.22.0"
features = ["write"]
96 changes: 4 additions & 92 deletions xtask/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
//!
//! Also see the docs in `asm.rs`.

use object::read::{Object as _, ObjectSection as _};
use object::write::{Object, Symbol, SymbolSection};
use object::{ObjectSymbol, SymbolFlags};
use std::collections::BTreeMap;
use std::env::current_dir;
use std::fs::{self, File};
Expand All @@ -25,90 +22,6 @@ fn rustc() -> Command {
cmd
}

/// Patches an object file so that it doesn't contain a panic handler.
///
/// The panic handler defined in `asm/lib.rs` should never get linked to the final program.
/// Unfortunately, Rust uses the same symbol for all panic handlers, and doesn't really like it if
/// that ends up with multiple ones. It also demands that we define a panic handler for the inline
/// assembly shim, even though none of that code should ever be able to panic. The result of this is
/// that the supposedly unreachable panic handler does end up getting linked into the final program,
/// unless it is built with optimizations enabled.
///
/// To fix that, we put the never-to-be-used panic handler into its own section via
/// `#[link_section]`, and then use this function to delete that section.
fn trim_panic_handler(obj_file: &str) {
let objdata = fs::read(&obj_file).unwrap();
let obj = object::File::parse(&objdata).unwrap();

let mut writer = Object::new(obj.format(), obj.architecture(), obj.endianness());
writer.flags = obj.flags(); // Preserve flags of input file

for (sec_index, section) in obj.sections().enumerate() {
assert_eq!(section.index().0, sec_index);

let name = section.name().unwrap();
if name.starts_with(".ARM")
|| name.starts_with(".rel.ARM")
|| name.contains("asm_panic_handler")
|| name == ".strtab"
|| name == ".symtab"
{
// We drop the ARM exception handling tables since they refer back to the panic handler
// symbol. They aren't used either way. We also drop `.strtab` and `.symtab` since they
// otherwise end up having the wrong section type. The object crate should rebuild any
// index tables when writing the file.
continue;
}

let segment = section
.segment_name()
.unwrap()
.map(|s| s.as_bytes())
.unwrap_or(&[]);
let sec_id = writer.add_section(segment.to_vec(), name.as_bytes().to_vec(), section.kind());

let align = if section.align() == 0 {
// Not sure why but `section.align()` can return 0.
1
} else {
section.align()
};
writer.append_section_data(sec_id, section.data().unwrap(), align);

// Import all symbols from the section.
for symbol in obj.symbols() {
if symbol.section_index() == Some(section.index()) {
writer.add_symbol(Symbol {
name: symbol.name().unwrap_or("").as_bytes().to_vec(),
value: symbol.address(),
size: symbol.size(),
kind: symbol.kind(),
scope: symbol.scope(),
weak: symbol.is_weak(),
section: match symbol.section() {
object::SymbolSection::Unknown => unimplemented!(),
object::SymbolSection::None => SymbolSection::None,
object::SymbolSection::Undefined => SymbolSection::Undefined,
object::SymbolSection::Absolute => SymbolSection::Absolute,
object::SymbolSection::Common => SymbolSection::Common,
object::SymbolSection::Section(_) => SymbolSection::Section(sec_id),
},
flags: match symbol.flags() {
SymbolFlags::None => SymbolFlags::None,
SymbolFlags::Elf { st_info, st_other } => {
SymbolFlags::Elf { st_info, st_other }
}
_ => unimplemented!(),
},
});
}
}
}

let obj = writer.write().unwrap();
fs::write(&obj_file, obj).unwrap();
}

fn assemble_really(target: &str, cfgs: &[&str], plugin_lto: bool) {
let mut cmd = rustc();

Expand All @@ -122,6 +35,10 @@ fn assemble_really(target: &str, cfgs: &[&str], plugin_lto: bool) {
// We always optimize the assembly shims. There's not really any reason not to.
cmd.arg("-O");

// We use LTO on the archive to ensure the (unused) panic handler is removed, preventing
// a linker error when the archives are linked into final crates with two panic handlers.
cmd.arg("-Clto=yes");

// rustc will usually add frame pointers by default to aid with debugging, but that is a high
// overhead for the tiny assembly routines.
cmd.arg("-Cforce-frame-pointers=no");
Expand Down Expand Up @@ -158,11 +75,6 @@ fn assemble_really(target: &str, cfgs: &[&str], plugin_lto: bool) {
let status = cmd.status().unwrap();
assert!(status.success());

if !plugin_lto {
// Post-process the object file.
trim_panic_handler(&obj_file);
}

// Archive `target.o` -> `bin/target.a`.
let mut builder = ar::Builder::new(File::create(format!("bin/{}.a", file_stub)).unwrap());

Expand Down