From 3293ca6b69155c5ce60947f5d68428a091b34d94 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Mon, 6 May 2019 16:34:16 +1000 Subject: [PATCH] Add cranelift-object --- cranelift/Cargo.toml | 1 + cranelift/codegen/src/ir/libcall.rs | 2 +- cranelift/faerie/src/backend.rs | 25 +- cranelift/module/src/backend.rs | 17 +- cranelift/module/src/module.rs | 46 ++- cranelift/object/Cargo.toml | 20 + cranelift/object/LICENSE | 220 +++++++++++ cranelift/object/README.md | 4 + cranelift/object/src/backend.rs | 584 ++++++++++++++++++++++++++++ cranelift/object/src/lib.rs | 38 ++ cranelift/object/src/traps.rs | 32 ++ cranelift/simplejit/src/backend.rs | 10 +- 12 files changed, 977 insertions(+), 22 deletions(-) create mode 100644 cranelift/object/Cargo.toml create mode 100644 cranelift/object/LICENSE create mode 100644 cranelift/object/README.md create mode 100644 cranelift/object/src/backend.rs create mode 100644 cranelift/object/src/lib.rs create mode 100644 cranelift/object/src/traps.rs diff --git a/cranelift/Cargo.toml b/cranelift/Cargo.toml index 8fee3b6dbe..c48ef7f71f 100644 --- a/cranelift/Cargo.toml +++ b/cranelift/Cargo.toml @@ -29,6 +29,7 @@ cranelift-native = { path = "cranelift-native", version = "0.42.0" } cranelift-filetests = { path = "cranelift-filetests", version = "0.42.0" } cranelift-module = { path = "cranelift-module", version = "0.42.0" } cranelift-faerie = { path = "cranelift-faerie", version = "0.42.0" } +cranelift-object = { path = "cranelift-object", version = "0.42.0" } cranelift-simplejit = { path = "cranelift-simplejit", version = "0.42.0" } cranelift-preopt = { path = "cranelift-preopt", version = "0.42.0" } cranelift = { path = "cranelift-umbrella", version = "0.42.0" } diff --git a/cranelift/codegen/src/ir/libcall.rs b/cranelift/codegen/src/ir/libcall.rs index 59fb951a32..1e19891221 100644 --- a/cranelift/codegen/src/ir/libcall.rs +++ b/cranelift/codegen/src/ir/libcall.rs @@ -18,7 +18,7 @@ use serde::{Deserialize, Serialize}; /// convention in the embedding VM's runtime library. /// /// This list is likely to grow over time. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum LibCall { /// probe for stack overflow. These are emitted for functions which need diff --git a/cranelift/faerie/src/backend.rs b/cranelift/faerie/src/backend.rs index 4a4d189612..585866ca98 100644 --- a/cranelift/faerie/src/backend.rs +++ b/cranelift/faerie/src/backend.rs @@ -8,8 +8,8 @@ use cranelift_codegen::binemit::{ use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::{self, binemit, ir}; use cranelift_module::{ - Backend, DataContext, DataDescription, Init, Linkage, ModuleError, ModuleNamespace, - ModuleResult, + Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleError, + ModuleNamespace, ModuleResult, }; use faerie; use failure::Error; @@ -123,13 +123,20 @@ impl Backend for FaerieBackend { &*self.isa } - fn declare_function(&mut self, name: &str, linkage: Linkage) { + fn declare_function(&mut self, _id: FuncId, name: &str, linkage: Linkage) { self.artifact .declare(name, translate_function_linkage(linkage)) .expect("inconsistent declarations"); } - fn declare_data(&mut self, name: &str, linkage: Linkage, writable: bool, align: Option) { + fn declare_data( + &mut self, + _id: DataId, + name: &str, + linkage: Linkage, + writable: bool, + align: Option, + ) { self.artifact .declare(name, translate_data_linkage(linkage, writable, align)) .expect("inconsistent declarations"); @@ -137,6 +144,7 @@ impl Backend for FaerieBackend { fn define_function( &mut self, + _id: FuncId, name: &str, ctx: &cranelift_codegen::Context, namespace: &ModuleNamespace, @@ -194,6 +202,7 @@ impl Backend for FaerieBackend { fn define_data( &mut self, + _id: DataId, name: &str, _writable: bool, _align: Option, @@ -274,6 +283,7 @@ impl Backend for FaerieBackend { fn finalize_function( &mut self, + _id: FuncId, _func: &FaerieCompiledFunction, _namespace: &ModuleNamespace, ) { @@ -284,7 +294,12 @@ impl Backend for FaerieBackend { // Nothing to do. } - fn finalize_data(&mut self, _data: &FaerieCompiledData, _namespace: &ModuleNamespace) { + fn finalize_data( + &mut self, + _id: DataId, + _data: &FaerieCompiledData, + _namespace: &ModuleNamespace, + ) { // Nothing to do. } diff --git a/cranelift/module/src/backend.rs b/cranelift/module/src/backend.rs index 316c0a3e2b..89b610bdba 100644 --- a/cranelift/module/src/backend.rs +++ b/cranelift/module/src/backend.rs @@ -1,6 +1,8 @@ //! Defines the `Backend` trait. use crate::DataContext; +use crate::DataId; +use crate::FuncId; use crate::Linkage; use crate::ModuleNamespace; use crate::ModuleResult; @@ -56,16 +58,24 @@ where fn isa(&self) -> &dyn TargetIsa; /// Declare a function. - fn declare_function(&mut self, name: &str, linkage: Linkage); + fn declare_function(&mut self, id: FuncId, name: &str, linkage: Linkage); /// Declare a data object. - fn declare_data(&mut self, name: &str, linkage: Linkage, writable: bool, align: Option); + fn declare_data( + &mut self, + id: DataId, + name: &str, + linkage: Linkage, + writable: bool, + align: Option, + ); /// Define a function, producing the function body from the given `Context`. /// /// Functions must be declared before being defined. fn define_function( &mut self, + id: FuncId, name: &str, ctx: &Context, namespace: &ModuleNamespace, @@ -77,6 +87,7 @@ where /// Data objects must be declared before being defined. fn define_data( &mut self, + id: DataId, name: &str, writable: bool, align: Option, @@ -107,6 +118,7 @@ where /// and `Export` entities referenced to be defined. fn finalize_function( &mut self, + id: FuncId, func: &Self::CompiledFunction, namespace: &ModuleNamespace, ) -> Self::FinalizedFunction; @@ -118,6 +130,7 @@ where /// `Local` and `Export` entities referenced to be defined. fn finalize_data( &mut self, + id: DataId, data: &Self::CompiledData, namespace: &ModuleNamespace, ) -> Self::FinalizedData; diff --git a/cranelift/module/src/module.rs b/cranelift/module/src/module.rs index d9cb1e00c5..f19dcfab21 100644 --- a/cranelift/module/src/module.rs +++ b/cranelift/module/src/module.rs @@ -224,26 +224,32 @@ impl ModuleContents where B: Backend, { - fn get_function_info(&self, name: &ir::ExternalName) -> &ModuleFunction { + fn get_function_id(&self, name: &ir::ExternalName) -> FuncId { if let ir::ExternalName::User { namespace, index } = *name { debug_assert_eq!(namespace, 0); - let func = FuncId::from_u32(index); - &self.functions[func] + FuncId::from_u32(index) } else { panic!("unexpected ExternalName kind {}", name) } } - /// Get the `DataDeclaration` for the function named by `name`. - fn get_data_info(&self, name: &ir::ExternalName) -> &ModuleData { + fn get_data_id(&self, name: &ir::ExternalName) -> DataId { if let ir::ExternalName::User { namespace, index } = *name { debug_assert_eq!(namespace, 1); - let data = DataId::from_u32(index); - &self.data_objects[data] + DataId::from_u32(index) } else { panic!("unexpected ExternalName kind {}", name) } } + + fn get_function_info(&self, name: &ir::ExternalName) -> &ModuleFunction { + &self.functions[self.get_function_id(name)] + } + + /// Get the `DataDeclaration` for the function named by `name`. + fn get_data_info(&self, name: &ir::ExternalName) -> &ModuleData { + &self.data_objects[self.get_data_id(name)] + } } /// This provides a view to the state of a module which allows `ir::ExternalName`s to be translated @@ -259,12 +265,22 @@ impl<'a, B> ModuleNamespace<'a, B> where B: Backend, { + /// Get the `FuncId` for the function named by `name`. + pub fn get_function_id(&self, name: &ir::ExternalName) -> FuncId { + self.contents.get_function_id(name) + } + + /// Get the `DataId` for the data object named by `name`. + pub fn get_data_id(&self, name: &ir::ExternalName) -> DataId { + self.contents.get_data_id(name) + } + /// Get the `FunctionDeclaration` for the function named by `name`. pub fn get_function_decl(&self, name: &ir::ExternalName) -> &FunctionDeclaration { &self.contents.get_function_info(name).decl } - /// Get the `DataDeclaration` for the function named by `name`. + /// Get the `DataDeclaration` for the data object named by `name`. pub fn get_data_decl(&self, name: &ir::ExternalName) -> &DataDeclaration { &self.contents.get_data_info(name).decl } @@ -407,7 +423,8 @@ where FuncOrDataId::Func(id) => { let existing = &mut self.contents.functions[id]; existing.merge(linkage, signature)?; - self.backend.declare_function(name, existing.decl.linkage); + self.backend + .declare_function(id, name, existing.decl.linkage); Ok(id) } FuncOrDataId::Data(..) => { @@ -424,7 +441,7 @@ where compiled: None, }); entry.insert(FuncOrDataId::Func(id)); - self.backend.declare_function(name, linkage); + self.backend.declare_function(id, name, linkage); Ok(id) } } @@ -451,6 +468,7 @@ where let existing = &mut self.contents.data_objects[id]; existing.merge(linkage, writable, align); self.backend.declare_data( + id, name, existing.decl.linkage, existing.decl.writable, @@ -474,7 +492,8 @@ where compiled: None, }); entry.insert(FuncOrDataId::Data(id)); - self.backend.declare_data(name, linkage, writable, align); + self.backend + .declare_data(id, name, linkage, writable, align); Ok(id) } } @@ -536,7 +555,6 @@ where ); ModuleError::Compilation(e) })?; - let info = &self.contents.functions[func]; if info.compiled.is_some() { return Err(ModuleError::DuplicateDefinition(info.decl.name.clone())); @@ -546,6 +564,7 @@ where } let compiled = Some(self.backend.define_function( + func, &info.decl.name, ctx, &ModuleNamespace:: { @@ -570,6 +589,7 @@ where return Err(ModuleError::InvalidImportDefinition(info.decl.name.clone())); } Some(self.backend.define_data( + data, &info.decl.name, info.decl.writable, info.decl.align, @@ -638,6 +658,7 @@ where let info = &self.contents.functions[func]; debug_assert!(info.decl.linkage.is_definable()); self.backend.finalize_function( + func, info.compiled .as_ref() .expect("function must be compiled before it can be finalized"), @@ -650,6 +671,7 @@ where let info = &self.contents.data_objects[data]; debug_assert!(info.decl.linkage.is_definable()); self.backend.finalize_data( + data, info.compiled .as_ref() .expect("data object must be compiled before it can be finalized"), diff --git a/cranelift/object/Cargo.toml b/cranelift/object/Cargo.toml new file mode 100644 index 0000000000..22613d65db --- /dev/null +++ b/cranelift/object/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "cranelift-object" +version = "0.42.0" +authors = ["The Cranelift Project Developers"] +description = "Emit Cranelift output to native object files with `object`" +repository = "https://github.com/CraneStation/cranelift" +documentation = "https://cranelift.readthedocs.io/" +license = "Apache-2.0 WITH LLVM-exception" +readme = "README.md" +edition = "2018" + +[dependencies] +cranelift-codegen = { path = "../cranelift-codegen", version = "0.42.0" } +cranelift-module = { path = "../cranelift-module", version = "0.42.0" } +object = { version = "0.14.0", default-features = false, features = ["write"] } +target-lexicon = "0.8.1" + +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "CraneStation/cranelift" } diff --git a/cranelift/object/LICENSE b/cranelift/object/LICENSE new file mode 100644 index 0000000000..f9d81955f4 --- /dev/null +++ b/cranelift/object/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/cranelift/object/README.md b/cranelift/object/README.md new file mode 100644 index 0000000000..3a0fc51356 --- /dev/null +++ b/cranelift/object/README.md @@ -0,0 +1,4 @@ +This crate contains a library that enables +[Cranelift](https://crates.io/crates/cranelift) +to emit native object (".o") files, using the +[object](https://crates.io/crates/object) library. diff --git a/cranelift/object/src/backend.rs b/cranelift/object/src/backend.rs new file mode 100644 index 0000000000..78dc246324 --- /dev/null +++ b/cranelift/object/src/backend.rs @@ -0,0 +1,584 @@ +//! Defines `ObjectBackend`. + +use crate::traps::{ObjectTrapSink, ObjectTrapSite}; +use cranelift_codegen::binemit::{ + Addend, CodeOffset, NullStackmapSink, NullTrapSink, Reloc, RelocSink, +}; +use cranelift_codegen::entity::SecondaryMap; +use cranelift_codegen::isa::TargetIsa; +use cranelift_codegen::{self, binemit, ir}; +use cranelift_module::{ + Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleNamespace, + ModuleResult, +}; +use object::write::{Object, Relocation, SectionId, StandardSection, Symbol, SymbolId}; +use object::{RelocationEncoding, RelocationKind, SymbolKind, SymbolScope}; +use std::collections::HashMap; +use target_lexicon::PointerWidth; + +#[derive(Debug)] +/// Setting to enable collection of traps. Setting this to `Enabled` in +/// `ObjectBuilder` means that `ObjectProduct` will contains trap sites. +pub enum ObjectTrapCollection { + /// `ObjectProduct::traps` will be empty + Disabled, + /// `ObjectProduct::traps` will contain trap sites + Enabled, +} + +/// A builder for `ObjectBackend`. +pub struct ObjectBuilder { + isa: Box, + name: String, + collect_traps: ObjectTrapCollection, + libcall_names: Box String>, + function_alignment: u64, +} + +impl ObjectBuilder { + /// Create a new `ObjectBuilder` using the given Cranelift target, that + /// can be passed to + /// [`Module::new`](cranelift_module/struct.Module.html#method.new]. + /// + /// `collect_traps` setting determines whether trap information is collected in the + /// `ObjectProduct`. + /// + /// The `libcall_names` function provides a way to translate `cranelift_codegen`'s `ir::LibCall` + /// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain + /// floating point instructions, and for stack probes. If you don't know what to use for this + /// argument, use `cranelift_module::default_libcall_names()`. + pub fn new( + isa: Box, + name: String, + collect_traps: ObjectTrapCollection, + libcall_names: Box String>, + ) -> ModuleResult { + Ok(Self { + isa, + name, + collect_traps, + libcall_names, + function_alignment: 1, + }) + } + + /// Set the alignment used for functions. + pub fn function_alignment(&mut self, alignment: u64) -> &mut Self { + self.function_alignment = alignment; + self + } +} + +/// A `ObjectBackend` implements `Backend` and emits ".o" files using the `object` library. +/// +/// See the `ObjectBuilder` for a convenient way to construct `ObjectBackend` instances. +pub struct ObjectBackend { + isa: Box, + object: Object, + functions: SecondaryMap>, + data_objects: SecondaryMap>, + traps: SecondaryMap>, + libcalls: HashMap, + libcall_names: Box String>, + collect_traps: ObjectTrapCollection, + function_alignment: u64, +} + +impl Backend for ObjectBackend { + type Builder = ObjectBuilder; + + type CompiledFunction = ObjectCompiledFunction; + type CompiledData = ObjectCompiledData; + + // There's no need to return individual artifacts; we're writing them into + // the output file instead. + type FinalizedFunction = (); + type FinalizedData = (); + + type Product = ObjectProduct; + + /// Create a new `ObjectBackend` using the given Cranelift target. + fn new(builder: ObjectBuilder) -> Self { + let triple = builder.isa.triple(); + let mut object = Object::new(triple.binary_format, triple.architecture); + object.add_file_symbol(builder.name.as_bytes().to_vec()); + Self { + isa: builder.isa, + object, + functions: SecondaryMap::new(), + data_objects: SecondaryMap::new(), + traps: SecondaryMap::new(), + libcalls: HashMap::new(), + libcall_names: builder.libcall_names, + collect_traps: builder.collect_traps, + function_alignment: builder.function_alignment, + } + } + + fn isa(&self) -> &dyn TargetIsa { + &*self.isa + } + + fn declare_function(&mut self, id: FuncId, name: &str, linkage: Linkage) { + let (scope, weak) = translate_linkage(linkage); + + if let Some(function) = self.functions[id] { + let symbol = self.object.symbol_mut(function); + symbol.scope = scope; + symbol.weak = weak; + } else { + let symbol_id = self.object.add_symbol(Symbol { + name: name.as_bytes().to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Text, + scope, + weak, + section: None, + }); + self.functions[id] = Some(symbol_id); + } + } + + fn declare_data( + &mut self, + id: DataId, + name: &str, + linkage: Linkage, + _writable: bool, + _align: Option, + ) { + let (scope, weak) = translate_linkage(linkage); + + if let Some(data) = self.data_objects[id] { + let symbol = self.object.symbol_mut(data); + symbol.scope = scope; + symbol.weak = weak; + } else { + let symbol_id = self.object.add_symbol(Symbol { + name: name.as_bytes().to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope, + weak, + section: None, + }); + self.data_objects[id] = Some(symbol_id); + } + } + + fn define_function( + &mut self, + func_id: FuncId, + _name: &str, + ctx: &cranelift_codegen::Context, + _namespace: &ModuleNamespace, + code_size: u32, + ) -> ModuleResult { + let mut code: Vec = vec![0; code_size as usize]; + let mut reloc_sink = ObjectRelocSink::default(); + let mut trap_sink = ObjectTrapSink::default(); + let mut stackmap_sink = NullStackmapSink {}; + + if let ObjectTrapCollection::Enabled = self.collect_traps { + unsafe { + ctx.emit_to_memory( + &*self.isa, + code.as_mut_ptr(), + &mut reloc_sink, + &mut trap_sink, + &mut stackmap_sink, + ) + }; + } else { + let mut trap_sink = NullTrapSink {}; + unsafe { + ctx.emit_to_memory( + &*self.isa, + code.as_mut_ptr(), + &mut reloc_sink, + &mut trap_sink, + &mut stackmap_sink, + ) + }; + } + + let symbol = self.functions[func_id].unwrap(); + let section = self.object.section_id(StandardSection::Text); + let offset = self + .object + .add_symbol_data(symbol, section, &code, self.function_alignment); + self.traps[func_id] = trap_sink.sites; + Ok(ObjectCompiledFunction { + offset, + size: code_size, + section, + relocs: reloc_sink.relocs, + }) + } + + fn define_data( + &mut self, + data_id: DataId, + _name: &str, + writable: bool, + align: Option, + data_ctx: &DataContext, + _namespace: &ModuleNamespace, + ) -> ModuleResult { + let &DataDescription { + ref init, + ref function_decls, + ref data_decls, + ref function_relocs, + ref data_relocs, + } = data_ctx.description(); + + let size = init.size(); + let mut data = Vec::with_capacity(size); + match *init { + Init::Uninitialized => { + panic!("data is not initialized yet"); + } + Init::Zeros { .. } => { + data.resize(size, 0); + } + Init::Bytes { ref contents } => { + data.extend_from_slice(contents); + } + } + + let reloc_size = match self.isa.triple().pointer_width().unwrap() { + PointerWidth::U16 => 16, + PointerWidth::U32 => 32, + PointerWidth::U64 => 64, + }; + let mut relocs = Vec::new(); + for &(offset, id) in function_relocs { + relocs.push(RelocRecord { + offset, + name: function_decls[id].clone(), + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + size: reloc_size, + addend: 0, + }); + } + for &(offset, id, addend) in data_relocs { + relocs.push(RelocRecord { + offset, + name: data_decls[id].clone(), + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + size: reloc_size, + addend, + }); + } + + let symbol = self.data_objects[data_id].unwrap(); + let section = self.object.section_id(if writable { + StandardSection::Data + } else if relocs.is_empty() { + StandardSection::ReadOnlyData + } else { + StandardSection::ReadOnlyDataWithRel + }); + let offset = + self.object + .add_symbol_data(symbol, section, &data, u64::from(align.unwrap_or(1))); + Ok(ObjectCompiledData { + offset, + section, + relocs, + }) + } + + fn write_data_funcaddr( + &mut self, + _data: &mut ObjectCompiledData, + _offset: usize, + _what: ir::FuncRef, + ) { + unimplemented!() + } + + fn write_data_dataaddr( + &mut self, + _data: &mut ObjectCompiledData, + _offset: usize, + _what: ir::GlobalValue, + _usize: binemit::Addend, + ) { + unimplemented!() + } + + fn finalize_function( + &mut self, + _id: FuncId, + func: &ObjectCompiledFunction, + namespace: &ModuleNamespace, + ) { + for &RelocRecord { + offset, + ref name, + kind, + encoding, + size, + addend, + } in &func.relocs + { + let offset = func.offset + offset as u64; + let symbol = self.get_symbol(namespace, name); + self.object + .add_relocation( + func.section, + Relocation { + offset, + size, + kind, + encoding, + symbol, + addend, + }, + ) + .unwrap(); + } + } + + fn get_finalized_function(&self, _func: &ObjectCompiledFunction) { + // Nothing to do. + } + + fn finalize_data( + &mut self, + _id: DataId, + data: &ObjectCompiledData, + namespace: &ModuleNamespace, + ) { + for &RelocRecord { + offset, + ref name, + kind, + encoding, + size, + addend, + } in &data.relocs + { + let offset = data.offset + offset as u64; + let symbol = self.get_symbol(namespace, name); + self.object + .add_relocation( + data.section, + Relocation { + offset, + size, + kind, + encoding, + symbol, + addend, + }, + ) + .unwrap(); + } + } + + fn get_finalized_data(&self, _data: &ObjectCompiledData) { + // Nothing to do. + } + + fn publish(&mut self) { + // Nothing to do. + } + + fn finish(self) -> ObjectProduct { + ObjectProduct { + object: self.object, + functions: self.functions, + data_objects: self.data_objects, + traps: self.traps, + } + } +} + +impl ObjectBackend { + // This should only be called during finalization because it creates + // symbols for missing libcalls. + fn get_symbol( + &mut self, + namespace: &ModuleNamespace, + name: &ir::ExternalName, + ) -> SymbolId { + match *name { + ir::ExternalName::User { .. } => { + if namespace.is_function(name) { + let id = namespace.get_function_id(name); + self.functions[id].unwrap() + } else { + let id = namespace.get_data_id(name); + self.data_objects[id].unwrap() + } + } + ir::ExternalName::LibCall(ref libcall) => { + let name = (self.libcall_names)(*libcall); + if let Some(symbol) = self.object.symbol_id(name.as_bytes()) { + symbol + } else if let Some(symbol) = self.libcalls.get(libcall) { + *symbol + } else { + let symbol = self.object.add_symbol(Symbol { + name: name.as_bytes().to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Text, + scope: SymbolScope::Unknown, + weak: false, + section: None, + }); + self.libcalls.insert(*libcall, symbol); + symbol + } + } + _ => panic!("invalid ExternalName {}", name), + } + } +} + +fn translate_linkage(linkage: Linkage) -> (SymbolScope, bool) { + let scope = match linkage { + Linkage::Import => SymbolScope::Unknown, + Linkage::Local => SymbolScope::Compilation, + Linkage::Export | Linkage::Preemptible => SymbolScope::Dynamic, + }; + // TODO: this matches rustc_codegen_cranelift, but may be wrong. + let weak = linkage == Linkage::Preemptible; + (scope, weak) +} + +#[derive(Clone)] +pub struct ObjectCompiledFunction { + offset: u64, + size: u32, + section: SectionId, + relocs: Vec, +} + +#[derive(Clone)] +pub struct ObjectCompiledData { + offset: u64, + section: SectionId, + relocs: Vec, +} + +/// This is the output of `Module`'s +/// [`finish`](../cranelift_module/struct.Module.html#method.finish) function. +/// It contains the generated `Object` and other information produced during +/// compilation. +pub struct ObjectProduct { + /// Object artifact with all functions and data from the module defined. + pub object: Object, + /// Symbol IDs for functions (both declared and defined). + pub functions: SecondaryMap>, + /// Symbol IDs for data objects (both declared and defined). + pub data_objects: SecondaryMap>, + /// Trap sites for defined functions. + pub traps: SecondaryMap>, +} + +impl ObjectProduct { + /// Return the `SymbolId` for the given function. + #[inline] + pub fn function_symbol(&self, id: FuncId) -> SymbolId { + self.functions[id].unwrap() + } + + /// Return the `SymbolId` for the given data object. + #[inline] + pub fn data_symbol(&self, id: DataId) -> SymbolId { + self.data_objects[id].unwrap() + } + + /// Write the object bytes in memory. + #[inline] + pub fn emit(self) -> Result, String> { + self.object.write() + } +} + +#[derive(Clone)] +struct RelocRecord { + offset: CodeOffset, + name: ir::ExternalName, + kind: RelocationKind, + encoding: RelocationEncoding, + size: u8, + addend: Addend, +} + +#[derive(Default)] +struct ObjectRelocSink { + relocs: Vec, +} + +impl RelocSink for ObjectRelocSink { + fn reloc_ebb(&mut self, _offset: CodeOffset, _reloc: Reloc, _ebb_offset: CodeOffset) { + unimplemented!(); + } + + fn reloc_external( + &mut self, + offset: CodeOffset, + reloc: Reloc, + name: &ir::ExternalName, + addend: Addend, + ) { + let (kind, encoding, size) = match reloc { + Reloc::Abs4 => (RelocationKind::Absolute, RelocationEncoding::Generic, 32), + Reloc::Abs8 => (RelocationKind::Absolute, RelocationEncoding::Generic, 64), + Reloc::X86PCRel4 => (RelocationKind::Relative, RelocationEncoding::Generic, 32), + Reloc::X86CallPCRel4 => (RelocationKind::Relative, RelocationEncoding::X86Branch, 32), + // TODO: Get Cranelift to tell us when we can use + // R_X86_64_GOTPCRELX/R_X86_64_REX_GOTPCRELX. + Reloc::X86CallPLTRel4 => ( + RelocationKind::PltRelative, + RelocationEncoding::X86Branch, + 32, + ), + Reloc::X86GOTPCRel4 => (RelocationKind::GotRelative, RelocationEncoding::Generic, 32), + // FIXME + _ => unimplemented!(), + }; + self.relocs.push(RelocRecord { + offset, + name: name.clone(), + kind, + encoding, + size, + addend, + }); + } + + fn reloc_jt(&mut self, _offset: CodeOffset, reloc: Reloc, _jt: ir::JumpTable) { + match reloc { + Reloc::X86PCRelRodata4 => { + // Not necessary to record this unless we are going to split apart code and its + // jumptbl/rodata. + } + _ => { + panic!("Unhandled reloc"); + } + } + } + + fn reloc_constant(&mut self, _offset: CodeOffset, reloc: Reloc, _jt: ir::ConstantOffset) { + match reloc { + Reloc::X86PCRelRodata4 => { + // Not necessary to record this unless we are going to split apart code and its + // jumptbl/rodata. + } + _ => { + panic!("Unhandled reloc"); + } + } + } +} diff --git a/cranelift/object/src/lib.rs b/cranelift/object/src/lib.rs new file mode 100644 index 0000000000..162a0b47aa --- /dev/null +++ b/cranelift/object/src/lib.rs @@ -0,0 +1,38 @@ +//! Top-level lib.rs for `cranelift_object`. +//! +//! Users of this module should not have to depend on `object` directly. + +#![deny( + missing_docs, + trivial_numeric_casts, + unused_extern_crates, + unstable_features +)] +#![warn(unused_import_braces)] +#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))] +#![cfg_attr( + feature = "cargo-clippy", + allow(clippy::new_without_default, clippy::new_without_default_derive) +)] +#![cfg_attr( + feature = "cargo-clippy", + warn( + clippy::float_arithmetic, + clippy::mut_mut, + clippy::nonminimal_bool, + clippy::option_map_unwrap_or, + clippy::option_map_unwrap_or_else, + clippy::print_stdout, + clippy::unicode_not_nfc, + clippy::use_self + ) +)] + +mod backend; +mod traps; + +pub use crate::backend::{ObjectBackend, ObjectBuilder, ObjectProduct, ObjectTrapCollection}; +pub use crate::traps::{ObjectTrapSink, ObjectTrapSite}; + +/// Version number of this crate. +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/cranelift/object/src/traps.rs b/cranelift/object/src/traps.rs new file mode 100644 index 0000000000..a64f1e13fa --- /dev/null +++ b/cranelift/object/src/traps.rs @@ -0,0 +1,32 @@ +//! Records every `TrapCode` that cranelift outputs during code generation, +//! for every function in the module. This data may be useful at runtime. + +use cranelift_codegen::{binemit, ir}; + +/// Record of the arguments cranelift passes to `TrapSink::trap` +#[derive(Clone)] +pub struct ObjectTrapSite { + /// Offset into function + pub offset: binemit::CodeOffset, + /// Source location given to cranelift + pub srcloc: ir::SourceLoc, + /// Trap code, as determined by cranelift + pub code: ir::TrapCode, +} + +/// Record of the trap sites for a given function +#[derive(Default, Clone)] +pub struct ObjectTrapSink { + /// All trap sites collected in function + pub sites: Vec, +} + +impl binemit::TrapSink for ObjectTrapSink { + fn trap(&mut self, offset: binemit::CodeOffset, srcloc: ir::SourceLoc, code: ir::TrapCode) { + self.sites.push(ObjectTrapSite { + offset, + srcloc, + code, + }); + } +} diff --git a/cranelift/simplejit/src/backend.rs b/cranelift/simplejit/src/backend.rs index 372f112e8d..68d603af30 100644 --- a/cranelift/simplejit/src/backend.rs +++ b/cranelift/simplejit/src/backend.rs @@ -7,7 +7,8 @@ use cranelift_codegen::binemit::{ use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::{self, ir, settings}; use cranelift_module::{ - Backend, DataContext, DataDescription, Init, Linkage, ModuleNamespace, ModuleResult, + Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleNamespace, + ModuleResult, }; use cranelift_native; #[cfg(not(windows))] @@ -222,12 +223,13 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { &*self.isa } - fn declare_function(&mut self, _name: &str, _linkage: Linkage) { + fn declare_function(&mut self, _id: FuncId, _name: &str, _linkage: Linkage) { // Nothing to do. } fn declare_data( &mut self, + _id: DataId, _name: &str, _linkage: Linkage, _writable: bool, @@ -238,6 +240,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { fn define_function( &mut self, + _id: FuncId, name: &str, ctx: &cranelift_codegen::Context, _namespace: &ModuleNamespace, @@ -283,6 +286,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { fn define_data( &mut self, + _id: DataId, _name: &str, writable: bool, align: Option, @@ -372,6 +376,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { fn finalize_function( &mut self, + _id: FuncId, func: &Self::CompiledFunction, namespace: &ModuleNamespace, ) -> Self::FinalizedFunction { @@ -425,6 +430,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { fn finalize_data( &mut self, + _id: DataId, data: &Self::CompiledData, namespace: &ModuleNamespace, ) -> Self::FinalizedData {