Skip to content

Commit 0f23877

Browse files
Patch out the asm shim panic handler
1 parent 6714e7f commit 0f23877

9 files changed

+97
-2
lines changed

bin/thumbv6m-none-eabi.a

-2.11 KB
Binary file not shown.

bin/thumbv7em-none-eabi.a

-2.86 KB
Binary file not shown.

bin/thumbv7em-none-eabihf.a

-3.06 KB
Binary file not shown.

bin/thumbv7m-none-eabi.a

-2.68 KB
Binary file not shown.

bin/thumbv8m.base-none-eabi.a

-2.52 KB
Binary file not shown.

bin/thumbv8m.main-none-eabi.a

-3.48 KB
Binary file not shown.

bin/thumbv8m.main-none-eabihf.a

-3.7 KB
Binary file not shown.

xtask/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@ harness = false
1111

1212
[dependencies]
1313
ar = "0.8.0"
14+
15+
[dependencies.object]
16+
version = "0.21.1"
17+
features = ["write"]

xtask/src/lib.rs

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
//!
55
//! Also see the docs in `asm.rs`.
66
7-
use process::Stdio;
7+
use object::{
8+
read::{Object as _, ObjectSection as _},
9+
write::{Object, Symbol, SymbolSection},
10+
SymbolFlags,
11+
};
812
use std::env::current_dir;
913
use std::{
1014
collections::BTreeMap,
1115
fs::{self, File},
12-
process::{self, Command},
16+
process::{Command, Stdio},
1317
};
1418

1519
fn toolchain() -> String {
@@ -25,6 +29,88 @@ fn rustc() -> Command {
2529
cmd
2630
}
2731

32+
/// Patches an object file so that it doesn't contain a panic handler.
33+
///
34+
/// The panic handler defined in `asm/lib.rs` should never get linked to the final program.
35+
/// Unfortunately, Rust uses the same symbol for all panic handlers, and doesn't really like it if
36+
/// that ends up with multiple ones. It also demands that we define a panic handler for the inline
37+
/// assembly shim, even though none of that code should ever be able to panic. The result of this is
38+
/// that the supposedly unreachable panic handler does end up getting linked into the final program,
39+
/// unless it is built with optimizations enabled.
40+
///
41+
/// To fix that, we put the never-to-be-used panic handler into its own section via
42+
/// `#[link_section]`, and then use this function to delete that section.
43+
fn trim_panic_handler(obj_file: &str) {
44+
let objdata = fs::read(&obj_file).unwrap();
45+
let obj = object::File::parse(&objdata).unwrap();
46+
47+
let mut writer = Object::new(obj.format(), obj.architecture(), obj.endianness());
48+
for (sec_index, section) in obj.sections().enumerate() {
49+
assert_eq!(section.index().0, sec_index);
50+
51+
let name = section.name().unwrap();
52+
if name.starts_with(".ARM")
53+
|| name.starts_with(".rel.ARM")
54+
|| name.contains("cortex_m_asm_panic")
55+
|| name == ".strtab"
56+
|| name == ".symtab"
57+
{
58+
// We drop the ARM exception handling tables since they refer back to the panic handler
59+
// symbol. They aren't used either way. We also drop `.strtab` and `.symtab` since they
60+
// otherwise end up having the wrong section type. The object crate should rebuild any
61+
// index tables when writing the file.
62+
continue;
63+
}
64+
65+
let segment = section
66+
.segment_name()
67+
.unwrap()
68+
.map(|s| s.as_bytes())
69+
.unwrap_or(&[]);
70+
let sec_id = writer.add_section(segment.to_vec(), name.as_bytes().to_vec(), section.kind());
71+
72+
let align = if section.align() == 0 {
73+
// Not sure why but `section.align()` can return 0.
74+
1
75+
} else {
76+
section.align()
77+
};
78+
writer.append_section_data(sec_id, section.data().unwrap(), align);
79+
80+
// Import all symbols from the section.
81+
for (_sym_idx, symbol) in obj.symbols() {
82+
if symbol.section_index() == Some(section.index()) {
83+
writer.add_symbol(Symbol {
84+
name: symbol.name().unwrap_or("").as_bytes().to_vec(),
85+
value: symbol.address(),
86+
size: symbol.size(),
87+
kind: symbol.kind(),
88+
scope: symbol.scope(),
89+
weak: symbol.is_weak(),
90+
section: match symbol.section() {
91+
object::SymbolSection::Unknown => unimplemented!(),
92+
object::SymbolSection::None => SymbolSection::None,
93+
object::SymbolSection::Undefined => SymbolSection::Undefined,
94+
object::SymbolSection::Absolute => SymbolSection::Absolute,
95+
object::SymbolSection::Common => SymbolSection::Common,
96+
object::SymbolSection::Section(_) => SymbolSection::Section(sec_id),
97+
},
98+
flags: match symbol.flags() {
99+
SymbolFlags::None => SymbolFlags::None,
100+
SymbolFlags::Elf { st_info, st_other } => {
101+
SymbolFlags::Elf { st_info, st_other }
102+
}
103+
_ => unimplemented!(),
104+
},
105+
});
106+
}
107+
}
108+
}
109+
110+
let obj = writer.write().unwrap();
111+
fs::write(&obj_file, obj).unwrap();
112+
}
113+
28114
fn assemble_really(target: &str, cfgs: &[&str], plugin_lto: bool) {
29115
let mut cmd = rustc();
30116

@@ -74,6 +160,11 @@ fn assemble_really(target: &str, cfgs: &[&str], plugin_lto: bool) {
74160
let status = cmd.status().unwrap();
75161
assert!(status.success());
76162

163+
if !plugin_lto {
164+
// Post-process the object file.
165+
trim_panic_handler(&obj_file);
166+
}
167+
77168
// Archive `target.o` -> `bin/target.a`.
78169
let mut builder = ar::Builder::new(File::create(format!("bin/{}.a", file_stub)).unwrap());
79170

0 commit comments

Comments
 (0)