Add support for macho relocations. (#378)
This requires splitting X86PCRel4 into two separate relocations, to distinguish the case where the instruction is a call, as Mach-O uses a different relocation in that case. This also makes it explicit that only x86-64 relocations are supported currently.
This commit is contained in:
@@ -352,7 +352,7 @@ ebb0:
|
|||||||
[-,%rsi] v351 = bint.i32 v301 ; bin: 0f b6 f2
|
[-,%rsi] v351 = bint.i32 v301 ; bin: 0f b6 f2
|
||||||
|
|
||||||
; asm: call foo
|
; asm: call foo
|
||||||
call fn0() ; bin: stk_ovf e8 PCRel4(%foo-4) 00000000
|
call fn0() ; bin: stk_ovf e8 CallPCRel4(%foo-4) 00000000
|
||||||
|
|
||||||
; asm: movl $0, %ecx
|
; asm: movl $0, %ecx
|
||||||
[-,%rcx] v400 = func_addr.i32 fn0 ; bin: b9 Abs4(%foo) 00000000
|
[-,%rcx] v400 = func_addr.i32 fn0 ; bin: b9 Abs4(%foo) 00000000
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ ebb0:
|
|||||||
; Colocated functions.
|
; Colocated functions.
|
||||||
|
|
||||||
; asm: call foo
|
; asm: call foo
|
||||||
call fn1() ; bin: stk_ovf e8 PCRel4(%bar-4) 00000000
|
call fn1() ; bin: stk_ovf e8 CallPCRel4(%bar-4) 00000000
|
||||||
|
|
||||||
; asm: lea 0x0(%rip), %rax
|
; asm: lea 0x0(%rip), %rax
|
||||||
[-,%rax] v0 = func_addr.i64 fn1 ; bin: 48 8d 05 PCRel4(%bar-4) 00000000
|
[-,%rax] v0 = func_addr.i64 fn1 ; bin: 48 8d 05 PCRel4(%bar-4) 00000000
|
||||||
@@ -49,7 +49,7 @@ ebb0:
|
|||||||
; Non-colocated functions.
|
; Non-colocated functions.
|
||||||
|
|
||||||
; asm: call foo@PLT
|
; asm: call foo@PLT
|
||||||
call fn0() ; bin: stk_ovf e8 PLTRel4(%foo-4) 00000000
|
call fn0() ; bin: stk_ovf e8 CallPLTRel4(%foo-4) 00000000
|
||||||
|
|
||||||
; asm: mov 0x0(%rip), %rax
|
; asm: mov 0x0(%rip), %rax
|
||||||
[-,%rax] v100 = func_addr.i64 fn0 ; bin: 48 8b 05 GOTPCRel4(%foo-4) 00000000
|
[-,%rax] v100 = func_addr.i64 fn0 ; bin: 48 8b 05 GOTPCRel4(%foo-4) 00000000
|
||||||
|
|||||||
@@ -485,7 +485,7 @@ ebb0:
|
|||||||
; Colocated functions.
|
; Colocated functions.
|
||||||
|
|
||||||
; asm: call bar
|
; asm: call bar
|
||||||
call fn1() ; bin: stk_ovf e8 PCRel4(%bar-4) 00000000
|
call fn1() ; bin: stk_ovf e8 CallPCRel4(%bar-4) 00000000
|
||||||
|
|
||||||
; asm: lea 0x0(%rip), %rcx
|
; asm: lea 0x0(%rip), %rcx
|
||||||
[-,%rcx] v400 = func_addr.i64 fn1 ; bin: 48 8d 0d PCRel4(%bar-4) 00000000
|
[-,%rcx] v400 = func_addr.i64 fn1 ; bin: 48 8d 0d PCRel4(%bar-4) 00000000
|
||||||
|
|||||||
@@ -1388,7 +1388,7 @@ call_id = TailRecipe(
|
|||||||
PUT_OP(bits, BASE_REX, sink);
|
PUT_OP(bits, BASE_REX, sink);
|
||||||
// The addend adjusts for the difference between the end of the
|
// The addend adjusts for the difference between the end of the
|
||||||
// instruction and the beginning of the immediate field.
|
// instruction and the beginning of the immediate field.
|
||||||
sink.reloc_external(Reloc::X86PCRel4,
|
sink.reloc_external(Reloc::X86CallPCRel4,
|
||||||
&func.dfg.ext_funcs[func_ref].name,
|
&func.dfg.ext_funcs[func_ref].name,
|
||||||
-4);
|
-4);
|
||||||
sink.put4(0);
|
sink.put4(0);
|
||||||
@@ -1399,7 +1399,7 @@ call_plt_id = TailRecipe(
|
|||||||
emit='''
|
emit='''
|
||||||
sink.trap(TrapCode::StackOverflow, func.srclocs[inst]);
|
sink.trap(TrapCode::StackOverflow, func.srclocs[inst]);
|
||||||
PUT_OP(bits, BASE_REX, sink);
|
PUT_OP(bits, BASE_REX, sink);
|
||||||
sink.reloc_external(Reloc::X86PLTRel4,
|
sink.reloc_external(Reloc::X86CallPLTRel4,
|
||||||
&func.dfg.ext_funcs[func_ref].name,
|
&func.dfg.ext_funcs[func_ref].name,
|
||||||
-4);
|
-4);
|
||||||
sink.put4(0);
|
sink.put4(0);
|
||||||
|
|||||||
@@ -33,10 +33,12 @@ pub enum Reloc {
|
|||||||
Abs8,
|
Abs8,
|
||||||
/// x86 PC-relative 4-byte
|
/// x86 PC-relative 4-byte
|
||||||
X86PCRel4,
|
X86PCRel4,
|
||||||
|
/// x86 call to PC-relative 4-byte
|
||||||
|
X86CallPCRel4,
|
||||||
|
/// x86 call to PLT-relative 4-byte
|
||||||
|
X86CallPLTRel4,
|
||||||
/// x86 GOT PC-relative 4-byte
|
/// x86 GOT PC-relative 4-byte
|
||||||
X86GOTPCRel4,
|
X86GOTPCRel4,
|
||||||
/// x86 PLT-relative 4-byte
|
|
||||||
X86PLTRel4,
|
|
||||||
/// Arm32 call target
|
/// Arm32 call target
|
||||||
Arm32Call,
|
Arm32Call,
|
||||||
/// Arm64 call target
|
/// Arm64 call target
|
||||||
@@ -53,8 +55,9 @@ impl fmt::Display for Reloc {
|
|||||||
Reloc::Abs4 => write!(f, "Abs4"),
|
Reloc::Abs4 => write!(f, "Abs4"),
|
||||||
Reloc::Abs8 => write!(f, "Abs8"),
|
Reloc::Abs8 => write!(f, "Abs8"),
|
||||||
Reloc::X86PCRel4 => write!(f, "PCRel4"),
|
Reloc::X86PCRel4 => write!(f, "PCRel4"),
|
||||||
|
Reloc::X86CallPCRel4 => write!(f, "CallPCRel4"),
|
||||||
|
Reloc::X86CallPLTRel4 => write!(f, "CallPLTRel4"),
|
||||||
Reloc::X86GOTPCRel4 => write!(f, "GOTPCRel4"),
|
Reloc::X86GOTPCRel4 => write!(f, "GOTPCRel4"),
|
||||||
Reloc::X86PLTRel4 => write!(f, "PLTRel4"),
|
|
||||||
Reloc::Arm32Call | Reloc::Arm64Call | Reloc::RiscvCall => write!(f, "Call"),
|
Reloc::Arm32Call | Reloc::Arm64Call | Reloc::RiscvCall => write!(f, "Call"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use cretonne_module::{
|
|||||||
use faerie;
|
use faerie;
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use target_lexicon::BinaryFormat;
|
use target_lexicon::Triple;
|
||||||
use traps::{FaerieTrapManifest, FaerieTrapSink};
|
use traps::{FaerieTrapManifest, FaerieTrapSink};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -29,7 +29,6 @@ pub enum FaerieTrapCollection {
|
|||||||
pub struct FaerieBuilder {
|
pub struct FaerieBuilder {
|
||||||
isa: Box<TargetIsa>,
|
isa: Box<TargetIsa>,
|
||||||
name: String,
|
name: String,
|
||||||
format: BinaryFormat,
|
|
||||||
collect_traps: FaerieTrapCollection,
|
collect_traps: FaerieTrapCollection,
|
||||||
libcall_names: Box<Fn(ir::LibCall) -> String>,
|
libcall_names: Box<Fn(ir::LibCall) -> String>,
|
||||||
}
|
}
|
||||||
@@ -51,7 +50,6 @@ impl FaerieBuilder {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
isa: Box<TargetIsa>,
|
isa: Box<TargetIsa>,
|
||||||
name: String,
|
name: String,
|
||||||
format: BinaryFormat,
|
|
||||||
collect_traps: FaerieTrapCollection,
|
collect_traps: FaerieTrapCollection,
|
||||||
libcall_names: Box<Fn(ir::LibCall) -> String>,
|
libcall_names: Box<Fn(ir::LibCall) -> String>,
|
||||||
) -> ModuleResult<Self> {
|
) -> ModuleResult<Self> {
|
||||||
@@ -63,7 +61,6 @@ impl FaerieBuilder {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
isa,
|
isa,
|
||||||
name,
|
name,
|
||||||
format,
|
|
||||||
collect_traps,
|
collect_traps,
|
||||||
libcall_names,
|
libcall_names,
|
||||||
})
|
})
|
||||||
@@ -91,7 +88,6 @@ impl FaerieBuilder {
|
|||||||
pub struct FaerieBackend {
|
pub struct FaerieBackend {
|
||||||
isa: Box<TargetIsa>,
|
isa: Box<TargetIsa>,
|
||||||
artifact: faerie::Artifact,
|
artifact: faerie::Artifact,
|
||||||
format: BinaryFormat,
|
|
||||||
trap_manifest: Option<FaerieTrapManifest>,
|
trap_manifest: Option<FaerieTrapManifest>,
|
||||||
libcall_names: Box<Fn(ir::LibCall) -> String>,
|
libcall_names: Box<Fn(ir::LibCall) -> String>,
|
||||||
}
|
}
|
||||||
@@ -120,7 +116,6 @@ impl Backend for FaerieBackend {
|
|||||||
Self {
|
Self {
|
||||||
artifact: faerie::Artifact::new(builder.isa.triple().clone(), builder.name),
|
artifact: faerie::Artifact::new(builder.isa.triple().clone(), builder.name),
|
||||||
isa: builder.isa,
|
isa: builder.isa,
|
||||||
format: builder.format,
|
|
||||||
trap_manifest: match builder.collect_traps {
|
trap_manifest: match builder.collect_traps {
|
||||||
FaerieTrapCollection::Enabled => Some(FaerieTrapManifest::new()),
|
FaerieTrapCollection::Enabled => Some(FaerieTrapManifest::new()),
|
||||||
FaerieTrapCollection::Disabled => None,
|
FaerieTrapCollection::Disabled => None,
|
||||||
@@ -158,7 +153,7 @@ impl Backend for FaerieBackend {
|
|||||||
// Non-lexical lifetimes would obviate the braces here.
|
// Non-lexical lifetimes would obviate the braces here.
|
||||||
{
|
{
|
||||||
let mut reloc_sink = FaerieRelocSink {
|
let mut reloc_sink = FaerieRelocSink {
|
||||||
format: self.format,
|
triple: self.isa.triple().clone(),
|
||||||
artifact: &mut self.artifact,
|
artifact: &mut self.artifact,
|
||||||
name,
|
name,
|
||||||
namespace,
|
namespace,
|
||||||
@@ -348,7 +343,7 @@ fn translate_data_linkage(linkage: Linkage, writable: bool) -> faerie::Decl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct FaerieRelocSink<'a> {
|
struct FaerieRelocSink<'a> {
|
||||||
format: BinaryFormat,
|
triple: Triple,
|
||||||
artifact: &'a mut faerie::Artifact,
|
artifact: &'a mut faerie::Artifact,
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
namespace: &'a ModuleNamespace<'a, FaerieBackend>,
|
namespace: &'a ModuleNamespace<'a, FaerieBackend>,
|
||||||
@@ -384,9 +379,11 @@ impl<'a> RelocSink for FaerieRelocSink<'a> {
|
|||||||
}
|
}
|
||||||
_ => panic!("invalid ExternalName {}", name),
|
_ => panic!("invalid ExternalName {}", name),
|
||||||
};
|
};
|
||||||
let addend_i32 = addend as i32;
|
let (raw_reloc, raw_addend) = container::raw_relocation(reloc, &self.triple);
|
||||||
debug_assert!(i64::from(addend_i32) == addend);
|
// TODO: Handle overflow.
|
||||||
let raw_reloc = container::raw_relocation(reloc, self.format);
|
let final_addend = addend + raw_addend;
|
||||||
|
let addend_i32 = final_addend as i32;
|
||||||
|
debug_assert!(i64::from(addend_i32) == final_addend);
|
||||||
self.artifact
|
self.artifact
|
||||||
.link_with(
|
.link_with(
|
||||||
faerie::Link {
|
faerie::Link {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//! Utilities for working with Faerie container formats.
|
//! Utilities for working with Faerie container formats.
|
||||||
|
|
||||||
use cretonne_codegen::binemit::Reloc;
|
use cretonne_codegen::binemit::Reloc;
|
||||||
use target_lexicon::BinaryFormat;
|
use target_lexicon::{Architecture, BinaryFormat, Triple};
|
||||||
|
|
||||||
/// An object file format.
|
/// An object file format.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -13,23 +13,53 @@ pub enum Format {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Translate from a Cretonne `Reloc` to a raw object-file-format-specific
|
/// Translate from a Cretonne `Reloc` to a raw object-file-format-specific
|
||||||
/// relocation code.
|
/// relocation code and relocation-implied addend.
|
||||||
pub fn raw_relocation(reloc: Reloc, format: BinaryFormat) -> u32 {
|
pub fn raw_relocation(reloc: Reloc, triple: &Triple) -> (u32, i64) {
|
||||||
match format {
|
match triple.binary_format {
|
||||||
BinaryFormat::Elf => {
|
BinaryFormat::Elf => {
|
||||||
use goblin::elf;
|
use goblin::elf;
|
||||||
|
(
|
||||||
|
match triple.architecture {
|
||||||
|
Architecture::X86_64 => {
|
||||||
match reloc {
|
match reloc {
|
||||||
Reloc::Abs4 => elf::reloc::R_X86_64_32,
|
Reloc::Abs4 => elf::reloc::R_X86_64_32,
|
||||||
Reloc::Abs8 => elf::reloc::R_X86_64_64,
|
Reloc::Abs8 => elf::reloc::R_X86_64_64,
|
||||||
Reloc::X86PCRel4 => elf::reloc::R_X86_64_PC32,
|
Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => elf::reloc::R_X86_64_PC32,
|
||||||
// TODO: Get Cretonne to tell us when we can use
|
// TODO: Get Cretonne to tell us when we can use
|
||||||
// R_X86_64_GOTPCRELX/R_X86_64_REX_GOTPCRELX.
|
// R_X86_64_GOTPCRELX/R_X86_64_REX_GOTPCRELX.
|
||||||
|
Reloc::X86CallPLTRel4 => elf::reloc::R_X86_64_PLT32,
|
||||||
Reloc::X86GOTPCRel4 => elf::reloc::R_X86_64_GOTPCREL,
|
Reloc::X86GOTPCRel4 => elf::reloc::R_X86_64_GOTPCREL,
|
||||||
Reloc::X86PLTRel4 => elf::reloc::R_X86_64_PLT32,
|
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BinaryFormat::Macho => unimplemented!("macho relocations"),
|
_ => unimplemented!("unsupported architecture: {}", triple),
|
||||||
|
},
|
||||||
|
// Most ELF relocations do not include an implicit addend.
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
BinaryFormat::Macho => {
|
||||||
|
use goblin::mach;
|
||||||
|
match triple.architecture {
|
||||||
|
Architecture::X86_64 => {
|
||||||
|
match reloc {
|
||||||
|
Reloc::Abs8 => (u32::from(mach::relocation::R_ABS), 0),
|
||||||
|
// Mach-O doesn't need us to distinguish between PC-relative calls
|
||||||
|
// and PLT calls, but it does need us to distinguish between calls
|
||||||
|
// and non-calls. And, it includes the 4-byte addend implicitly.
|
||||||
|
Reloc::X86PCRel4 => (u32::from(mach::relocation::X86_64_RELOC_SIGNED), 4),
|
||||||
|
Reloc::X86CallPCRel4 | Reloc::X86CallPLTRel4 => {
|
||||||
|
(u32::from(mach::relocation::X86_64_RELOC_BRANCH), 4)
|
||||||
|
}
|
||||||
|
Reloc::X86GOTPCRel4 => {
|
||||||
|
(u32::from(mach::relocation::X86_64_RELOC_GOT_LOAD), 4)
|
||||||
|
}
|
||||||
|
_ => unimplemented!("unsupported mach-o reloc: {}", reloc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unimplemented!("unsupported architecture: {}", triple),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unimplemented!("unsupported format"),
|
_ => unimplemented!("unsupported format"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
|
|||||||
write_unaligned(at as *mut u64, what as u64)
|
write_unaligned(at as *mut u64, what as u64)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Reloc::X86PCRel4 => {
|
Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => {
|
||||||
// TODO: Handle overflow.
|
// TODO: Handle overflow.
|
||||||
let pcrel = ((what as isize) - (at as isize)) as i32;
|
let pcrel = ((what as isize) - (at as isize)) as i32;
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(cast_ptr_alignment))]
|
#[cfg_attr(feature = "cargo-clippy", allow(cast_ptr_alignment))]
|
||||||
@@ -279,7 +279,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
|
|||||||
write_unaligned(at as *mut i32, pcrel)
|
write_unaligned(at as *mut i32, pcrel)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Reloc::X86GOTPCRel4 | Reloc::X86PLTRel4 => panic!("unexpected PIC relocation"),
|
Reloc::X86GOTPCRel4 | Reloc::X86CallPLTRel4 => panic!("unexpected PIC relocation"),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,9 +336,10 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend {
|
|||||||
write_unaligned(at as *mut u64, what as u64)
|
write_unaligned(at as *mut u64, what as u64)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Reloc::X86PCRel4 | Reloc::X86GOTPCRel4 | Reloc::X86PLTRel4 => {
|
Reloc::X86PCRel4
|
||||||
panic!("unexpected text relocation in data")
|
| Reloc::X86CallPCRel4
|
||||||
}
|
| Reloc::X86GOTPCRel4
|
||||||
|
| Reloc::X86CallPLTRel4 => panic!("unexpected text relocation in data"),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user