1 //! Abstraction around the object writing crate
3 use std::convert::{TryFrom, TryInto};
5 use rustc_data_structures::fx::FxHashMap;
6 use rustc_session::Session;
8 use cranelift_module::FuncId;
11 use object::{RelocationEncoding, RelocationKind, SectionKind, SymbolFlags};
13 use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
17 use crate::debuginfo::{DebugReloc, DebugRelocName};
19 pub(crate) trait WriteMetadata {
20 fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool);
23 impl WriteMetadata for object::write::Object {
24 fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
26 .segment_name(object::write::StandardSegment::Data)
28 let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
29 let offset = self.append_section_data(section_id, &data, 1);
30 // For MachO and probably PE this is necessary to prevent the linker from throwing away the
31 // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
32 self.add_symbol(object::write::Symbol {
33 name: symbol_name.into_bytes(),
35 size: data.len() as u64,
36 kind: object::SymbolKind::Data,
37 scope: object::SymbolScope::Dynamic,
39 section: SymbolSection::Section(section_id),
40 flags: SymbolFlags::None,
45 pub(crate) trait WriteDebugInfo {
48 fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
51 section_map: &FxHashMap<SectionId, Self::SectionId>,
52 from: &Self::SectionId,
57 impl WriteDebugInfo for ObjectProduct {
58 type SectionId = (object::write::SectionId, object::write::SymbolId);
64 ) -> (object::write::SectionId, object::write::SymbolId) {
65 let name = if self.object.format() == object::BinaryFormat::MachO {
66 id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
72 let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
73 // FIXME use SHT_X86_64_UNWIND for .eh_frame
74 let section_id = self.object.add_section(
77 if id == SectionId::EhFrame {
78 SectionKind::ReadOnlyData
84 .section_mut(section_id)
85 .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 });
86 let symbol_id = self.object.section_symbol(section_id);
87 (section_id, symbol_id)
92 section_map: &FxHashMap<SectionId, Self::SectionId>,
93 from: &Self::SectionId,
96 let (symbol, symbol_offset) = match reloc.name {
97 DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
98 DebugRelocName::Symbol(id) => {
99 let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
101 .symbol_section_and_offset(symbol_id)
102 .expect("Debug reloc for undef sym???")
109 offset: u64::from(reloc.offset),
112 encoding: RelocationEncoding::Generic,
113 size: reloc.size * 8,
114 addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
121 // FIXME remove once atomic instructions are implemented in Cranelift.
122 pub(crate) trait AddConstructor {
123 fn add_constructor(&mut self, func_id: FuncId);
126 impl AddConstructor for ObjectProduct {
127 fn add_constructor(&mut self, func_id: FuncId) {
128 let symbol = self.function_symbol(func_id);
131 .segment_name(object::write::StandardSegment::Data);
132 let init_array_section =
134 .add_section(segment.to_vec(), b".init_array".to_vec(), SectionKind::Data);
135 let address_size = self
139 .expect("address_size must be known")
141 self.object.append_section_data(
143 &std::iter::repeat(0)
144 .take(address_size.into())
145 .collect::<Vec<u8>>(),
151 object::write::Relocation {
153 size: address_size * 8,
154 kind: RelocationKind::Absolute,
155 encoding: RelocationEncoding::Generic,
164 pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
165 let triple = crate::build_isa(sess).triple().clone();
167 let binary_format = match triple.binary_format {
168 target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
169 target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
170 target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
171 binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)),
173 let architecture = match triple.architecture {
174 target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
175 target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
176 target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
177 target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
178 architecture => sess.fatal(&format!(
179 "target architecture {:?} is unsupported",
183 let endian = match triple.endianness().unwrap() {
184 target_lexicon::Endianness::Little => object::Endianness::Little,
185 target_lexicon::Endianness::Big => object::Endianness::Big,
188 let mut metadata_object = object::write::Object::new(binary_format, architecture, endian);
189 metadata_object.add_file_symbol(name.as_bytes().to_vec());
190 f(&mut metadata_object);
191 metadata_object.write().unwrap()
194 pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule {
195 let mut builder = ObjectBuilder::new(
196 crate::build_isa(sess),
198 cranelift_module::default_libcall_names(),
201 // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
202 // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
203 // can easily double the amount of time necessary to perform linking.
204 builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false));
205 ObjectModule::new(builder)