1
Fork 0
rust/src/backend.rs

203 lines
7.1 KiB
Rust
Raw Normal View History

2020-05-01 19:21:29 +02:00
use std::convert::{TryFrom, TryInto};
2020-04-05 14:01:02 +02:00
use rustc_data_structures::fx::FxHashMap;
use rustc_session::Session;
2019-10-18 17:19:13 +02:00
use cranelift_module::{FuncId, Module};
use object::write::*;
use object::{RelocationEncoding, RelocationKind, SectionKind, SymbolFlags};
2019-10-19 10:56:35 +02:00
use cranelift_object::{ObjectBackend, ObjectBuilder, ObjectProduct};
use gimli::SectionId;
use crate::debuginfo::{DebugReloc, DebugRelocName};
pub(crate) trait WriteMetadata {
fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool);
}
impl WriteMetadata for object::write::Object {
2019-10-19 10:52:56 +02:00
fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
let segment = self
.segment_name(object::write::StandardSegment::Data)
.to_vec();
let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
let offset = self.append_section_data(section_id, &data, 1);
2019-10-19 10:52:56 +02:00
// For MachO and probably PE this is necessary to prevent the linker from throwing away the
// .rustc section. For ELF this isn't necessary, but it also doesn't harm.
self.add_symbol(object::write::Symbol {
name: symbol_name.into_bytes(),
value: offset,
size: data.len() as u64,
kind: object::SymbolKind::Data,
scope: object::SymbolScope::Dynamic,
2019-10-19 10:52:56 +02:00
weak: false,
2020-01-10 13:12:49 +01:00
section: SymbolSection::Section(section_id),
flags: SymbolFlags::None,
2019-10-19 10:52:56 +02:00
});
}
}
pub(crate) trait WriteDebugInfo {
2020-04-25 18:23:31 +02:00
type SectionId: Copy;
fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
fn add_debug_reloc(
&mut self,
2020-04-05 14:01:02 +02:00
section_map: &FxHashMap<SectionId, Self::SectionId>,
from: &Self::SectionId,
reloc: &DebugReloc,
);
}
impl WriteDebugInfo for ObjectProduct {
type SectionId = (object::write::SectionId, object::write::SymbolId);
fn add_debug_section(
&mut self,
id: SectionId,
data: Vec<u8>,
) -> (object::write::SectionId, object::write::SymbolId) {
2020-06-16 10:38:12 +02:00
let name = if self.object.format() == object::BinaryFormat::MachO {
id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
} else {
id.name().to_string()
}
.into_bytes();
let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
let section_id = self.object.add_section(segment, name, SectionKind::Debug);
self.object.section_mut(section_id).set_data(data, 1);
let symbol_id = self.object.section_symbol(section_id);
(section_id, symbol_id)
}
fn add_debug_reloc(
&mut self,
2020-04-05 14:01:02 +02:00
section_map: &FxHashMap<SectionId, Self::SectionId>,
from: &Self::SectionId,
reloc: &DebugReloc,
) {
let (symbol, symbol_offset) = match reloc.name {
DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
DebugRelocName::Symbol(id) => {
2020-05-01 19:21:29 +02:00
let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
self.object
.symbol_section_and_offset(symbol_id)
.expect("Debug reloc for undef sym???")
}
};
self.object
.add_relocation(
from.0,
Relocation {
offset: u64::from(reloc.offset),
symbol,
kind: RelocationKind::Absolute,
encoding: RelocationEncoding::Generic,
size: reloc.size * 8,
addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
},
)
.unwrap();
}
}
2019-10-18 17:19:13 +02:00
// FIXME remove once atomic instructions are implemented in Cranelift.
pub(crate) trait AddConstructor {
fn add_constructor(&mut self, func_id: FuncId);
}
impl AddConstructor for ObjectProduct {
fn add_constructor(&mut self, func_id: FuncId) {
let symbol = self.function_symbol(func_id);
let segment = self
.object
.segment_name(object::write::StandardSegment::Data);
let init_array_section =
self.object
.add_section(segment.to_vec(), b".init_array".to_vec(), SectionKind::Data);
self.object.append_section_data(
init_array_section,
&std::iter::repeat(0)
.take(8 /*FIXME pointer size*/)
.collect::<Vec<u8>>(),
8,
);
self.object
.add_relocation(
init_array_section,
object::write::Relocation {
offset: 0,
size: 64, // FIXME pointer size
kind: RelocationKind::Absolute,
encoding: RelocationEncoding::Generic,
symbol,
addend: 0,
},
)
.unwrap();
}
}
pub(crate) trait Emit {
2019-10-18 17:19:13 +02:00
fn emit(self) -> Vec<u8>;
}
impl Emit for ObjectProduct {
fn emit(self) -> Vec<u8> {
self.object.write().unwrap()
}
}
pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
2019-10-18 17:19:13 +02:00
let triple = crate::build_isa(sess, true).triple().clone();
2020-06-16 10:38:12 +02:00
let binary_format = match triple.binary_format {
target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
2020-09-21 19:23:39 +02:00
binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)),
2020-06-16 10:38:12 +02:00
};
let architecture = match triple.architecture {
2020-09-21 19:23:39 +02:00
target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
2020-06-16 10:38:12 +02:00
target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
architecture => sess.fatal(&format!(
"target architecture {:?} is unsupported",
architecture,
)),
2020-06-16 10:38:12 +02:00
};
let endian = match triple.endianness().unwrap() {
target_lexicon::Endianness::Little => object::Endianness::Little,
target_lexicon::Endianness::Big => object::Endianness::Big,
};
let mut metadata_object = object::write::Object::new(binary_format, architecture, endian);
2019-10-18 17:19:13 +02:00
metadata_object.add_file_symbol(name.as_bytes().to_vec());
f(&mut metadata_object);
metadata_object.write().unwrap()
}
pub(crate) type Backend =
impl cranelift_module::Backend<Product: AddConstructor + Emit + WriteDebugInfo>;
2019-10-18 17:19:13 +02:00
pub(crate) fn make_module(sess: &Session, name: String) -> Module<Backend> {
let mut builder = ObjectBuilder::new(
crate::build_isa(sess, true),
name + ".o",
cranelift_module::default_libcall_names(),
)
.unwrap();
if std::env::var("CG_CLIF_FUNCTION_SECTIONS").is_ok() {
builder.per_function_section(true);
}
2019-10-18 17:19:13 +02:00
let module: Module<ObjectBackend> = Module::new(
builder,
2019-10-18 17:19:13 +02:00
);
module
}