4
4
//!
5
5
//! Also see the docs in `asm.rs`.
6
6
7
- use object:: read:: { Object as _, ObjectSection as _} ;
8
- use object:: write:: { Object , Symbol , SymbolSection } ;
9
- use object:: { ObjectSymbol , SymbolFlags } ;
10
7
use std:: collections:: BTreeMap ;
11
8
use std:: env:: current_dir;
12
9
use std:: fs:: { self , File } ;
@@ -25,90 +22,6 @@ fn rustc() -> Command {
25
22
cmd
26
23
}
27
24
28
- /// Patches an object file so that it doesn't contain a panic handler.
29
- ///
30
- /// The panic handler defined in `asm/lib.rs` should never get linked to the final program.
31
- /// Unfortunately, Rust uses the same symbol for all panic handlers, and doesn't really like it if
32
- /// that ends up with multiple ones. It also demands that we define a panic handler for the inline
33
- /// assembly shim, even though none of that code should ever be able to panic. The result of this is
34
- /// that the supposedly unreachable panic handler does end up getting linked into the final program,
35
- /// unless it is built with optimizations enabled.
36
- ///
37
- /// To fix that, we put the never-to-be-used panic handler into its own section via
38
- /// `#[link_section]`, and then use this function to delete that section.
39
- fn trim_panic_handler ( obj_file : & str ) {
40
- let objdata = fs:: read ( & obj_file) . unwrap ( ) ;
41
- let obj = object:: File :: parse ( & objdata) . unwrap ( ) ;
42
-
43
- let mut writer = Object :: new ( obj. format ( ) , obj. architecture ( ) , obj. endianness ( ) ) ;
44
- writer. flags = obj. flags ( ) ; // Preserve flags of input file
45
-
46
- for ( sec_index, section) in obj. sections ( ) . enumerate ( ) {
47
- assert_eq ! ( section. index( ) . 0 , sec_index) ;
48
-
49
- let name = section. name ( ) . unwrap ( ) ;
50
- if name. starts_with ( ".ARM" )
51
- || name. starts_with ( ".rel.ARM" )
52
- || name. contains ( "asm_panic_handler" )
53
- || name == ".strtab"
54
- || name == ".symtab"
55
- {
56
- // We drop the ARM exception handling tables since they refer back to the panic handler
57
- // symbol. They aren't used either way. We also drop `.strtab` and `.symtab` since they
58
- // otherwise end up having the wrong section type. The object crate should rebuild any
59
- // index tables when writing the file.
60
- continue ;
61
- }
62
-
63
- let segment = section
64
- . segment_name ( )
65
- . unwrap ( )
66
- . map ( |s| s. as_bytes ( ) )
67
- . unwrap_or ( & [ ] ) ;
68
- let sec_id = writer. add_section ( segment. to_vec ( ) , name. as_bytes ( ) . to_vec ( ) , section. kind ( ) ) ;
69
-
70
- let align = if section. align ( ) == 0 {
71
- // Not sure why but `section.align()` can return 0.
72
- 1
73
- } else {
74
- section. align ( )
75
- } ;
76
- writer. append_section_data ( sec_id, section. data ( ) . unwrap ( ) , align) ;
77
-
78
- // Import all symbols from the section.
79
- for symbol in obj. symbols ( ) {
80
- if symbol. section_index ( ) == Some ( section. index ( ) ) {
81
- writer. add_symbol ( Symbol {
82
- name : symbol. name ( ) . unwrap_or ( "" ) . as_bytes ( ) . to_vec ( ) ,
83
- value : symbol. address ( ) ,
84
- size : symbol. size ( ) ,
85
- kind : symbol. kind ( ) ,
86
- scope : symbol. scope ( ) ,
87
- weak : symbol. is_weak ( ) ,
88
- section : match symbol. section ( ) {
89
- object:: SymbolSection :: Unknown => unimplemented ! ( ) ,
90
- object:: SymbolSection :: None => SymbolSection :: None ,
91
- object:: SymbolSection :: Undefined => SymbolSection :: Undefined ,
92
- object:: SymbolSection :: Absolute => SymbolSection :: Absolute ,
93
- object:: SymbolSection :: Common => SymbolSection :: Common ,
94
- object:: SymbolSection :: Section ( _) => SymbolSection :: Section ( sec_id) ,
95
- } ,
96
- flags : match symbol. flags ( ) {
97
- SymbolFlags :: None => SymbolFlags :: None ,
98
- SymbolFlags :: Elf { st_info, st_other } => {
99
- SymbolFlags :: Elf { st_info, st_other }
100
- }
101
- _ => unimplemented ! ( ) ,
102
- } ,
103
- } ) ;
104
- }
105
- }
106
- }
107
-
108
- let obj = writer. write ( ) . unwrap ( ) ;
109
- fs:: write ( & obj_file, obj) . unwrap ( ) ;
110
- }
111
-
112
25
fn assemble_really ( target : & str , cfgs : & [ & str ] , plugin_lto : bool ) {
113
26
let mut cmd = rustc ( ) ;
114
27
@@ -122,6 +35,10 @@ fn assemble_really(target: &str, cfgs: &[&str], plugin_lto: bool) {
122
35
// We always optimize the assembly shims. There's not really any reason not to.
123
36
cmd. arg ( "-O" ) ;
124
37
38
+ // We use LTO on the archive to ensure the (unused) panic handler is removed, preventing
39
+ // a linker error when the archives are linked into final crates with two panic handlers.
40
+ cmd. arg ( "-Clto=yes" ) ;
41
+
125
42
// rustc will usually add frame pointers by default to aid with debugging, but that is a high
126
43
// overhead for the tiny assembly routines.
127
44
cmd. arg ( "-Cforce-frame-pointers=no" ) ;
@@ -158,11 +75,6 @@ fn assemble_really(target: &str, cfgs: &[&str], plugin_lto: bool) {
158
75
let status = cmd. status ( ) . unwrap ( ) ;
159
76
assert ! ( status. success( ) ) ;
160
77
161
- if !plugin_lto {
162
- // Post-process the object file.
163
- trim_panic_handler ( & obj_file) ;
164
- }
165
-
166
78
// Archive `target.o` -> `bin/target.a`.
167
79
let mut builder = ar:: Builder :: new ( File :: create ( format ! ( "bin/{}.a" , file_stub) ) . unwrap ( ) ) ;
168
80
0 commit comments