4
4
//!
5
5
//! Also see the docs in `asm.rs`.
6
6
7
- use process:: Stdio ;
7
+ use object:: {
8
+ read:: { Object as _, ObjectSection as _} ,
9
+ write:: { Object , Symbol , SymbolSection } ,
10
+ SymbolFlags ,
11
+ } ;
8
12
use std:: env:: current_dir;
9
13
use std:: {
10
14
collections:: BTreeMap ,
11
15
fs:: { self , File } ,
12
- process:: { self , Command } ,
16
+ process:: { Command , Stdio } ,
13
17
} ;
14
18
15
19
fn toolchain ( ) -> String {
@@ -25,6 +29,88 @@ fn rustc() -> Command {
25
29
cmd
26
30
}
27
31
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
+
28
114
fn assemble_really ( target : & str , cfgs : & [ & str ] , plugin_lto : bool ) {
29
115
let mut cmd = rustc ( ) ;
30
116
@@ -74,6 +160,11 @@ fn assemble_really(target: &str, cfgs: &[&str], plugin_lto: bool) {
74
160
let status = cmd. status ( ) . unwrap ( ) ;
75
161
assert ! ( status. success( ) ) ;
76
162
163
+ if !plugin_lto {
164
+ // Post-process the object file.
165
+ trim_panic_handler ( & obj_file) ;
166
+ }
167
+
77
168
// Archive `target.o` -> `bin/target.a`.
78
169
let mut builder = ar:: Builder :: new ( File :: create ( format ! ( "bin/{}.a" , file_stub) ) . unwrap ( ) ) ;
79
170
0 commit comments