x64: support PC-rel symbol references using the GOT when in PIC mode.
This commit is contained in:
@@ -2690,6 +2690,30 @@ pub(crate) fn emit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Inst::LoadExtName { dst, name, offset } => {
|
Inst::LoadExtName { dst, name, offset } => {
|
||||||
|
if info.flags().is_pic() {
|
||||||
|
// Generates: movq symbol@GOTPCREL(%rip), %dst
|
||||||
|
let enc_dst = int_reg_enc(dst.to_reg());
|
||||||
|
sink.put1(0x48 | ((enc_dst >> 3) & 1) << 2);
|
||||||
|
sink.put1(0x8B);
|
||||||
|
sink.put1(0x05 | ((enc_dst & 7) << 3));
|
||||||
|
emit_reloc(sink, state, Reloc::X86GOTPCRel4, name, -4);
|
||||||
|
sink.put4(0);
|
||||||
|
// Offset in the relocation above applies to the address of the *GOT entry*, not
|
||||||
|
// the loaded address; so we emit a separate add or sub instruction if needed.
|
||||||
|
if *offset < 0 {
|
||||||
|
assert!(*offset >= -i32::MAX as i64);
|
||||||
|
sink.put1(0x48 | ((enc_dst >> 3) & 1));
|
||||||
|
sink.put1(0x81);
|
||||||
|
sink.put1(0xe8 | (enc_dst & 7));
|
||||||
|
sink.put4((-*offset) as u32);
|
||||||
|
} else if *offset > 0 {
|
||||||
|
assert!(*offset <= i32::MAX as i64);
|
||||||
|
sink.put1(0x48 | ((enc_dst >> 3) & 1));
|
||||||
|
sink.put1(0x81);
|
||||||
|
sink.put1(0xc0 | (enc_dst & 7));
|
||||||
|
sink.put4(*offset as u32);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// The full address can be encoded in the register, with a relocation.
|
// The full address can be encoded in the register, with a relocation.
|
||||||
// Generates: movabsq $name, %dst
|
// Generates: movabsq $name, %dst
|
||||||
let enc_dst = int_reg_enc(dst.to_reg());
|
let enc_dst = int_reg_enc(dst.to_reg());
|
||||||
@@ -2702,6 +2726,7 @@ pub(crate) fn emit(
|
|||||||
sink.put8(0);
|
sink.put8(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Inst::LockCmpxchg { ty, src, dst } => {
|
Inst::LockCmpxchg { ty, src, dst } => {
|
||||||
// lock cmpxchg{b,w,l,q} %src, (dst)
|
// lock cmpxchg{b,w,l,q} %src, (dst)
|
||||||
|
|||||||
@@ -2778,6 +2778,46 @@ fn test_x64_emit() {
|
|||||||
"call *321(%r10,%rdx,4)",
|
"call *321(%r10,%rdx,4)",
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// LoadExtName
|
||||||
|
// N.B.: test harness below sets is_pic.
|
||||||
|
insns.push((
|
||||||
|
Inst::LoadExtName {
|
||||||
|
dst: Writable::from_reg(r11),
|
||||||
|
name: Box::new(ExternalName::User {
|
||||||
|
namespace: 0,
|
||||||
|
index: 0,
|
||||||
|
}),
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
"4C8B1D00000000",
|
||||||
|
"load_ext_name u0:0+0, %r11",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::LoadExtName {
|
||||||
|
dst: Writable::from_reg(r11),
|
||||||
|
name: Box::new(ExternalName::User {
|
||||||
|
namespace: 0,
|
||||||
|
index: 0,
|
||||||
|
}),
|
||||||
|
offset: 0x12345678,
|
||||||
|
},
|
||||||
|
"4C8B1D000000004981C378563412",
|
||||||
|
"load_ext_name u0:0+305419896, %r11",
|
||||||
|
));
|
||||||
|
insns.push((
|
||||||
|
Inst::LoadExtName {
|
||||||
|
dst: Writable::from_reg(r11),
|
||||||
|
name: Box::new(ExternalName::User {
|
||||||
|
namespace: 0,
|
||||||
|
index: 0,
|
||||||
|
}),
|
||||||
|
offset: -0x12345678,
|
||||||
|
},
|
||||||
|
"4C8B1D000000004981EB78563412",
|
||||||
|
"load_ext_name u0:0+-305419896, %r11",
|
||||||
|
));
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
// Ret
|
// Ret
|
||||||
insns.push((Inst::ret(), "C3", "ret"));
|
insns.push((Inst::ret(), "C3", "ret"));
|
||||||
@@ -3693,7 +3733,9 @@ fn test_x64_emit() {
|
|||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
// Actually run the tests!
|
// Actually run the tests!
|
||||||
let flags = settings::Flags::new(settings::builder());
|
let mut flag_builder = settings::builder();
|
||||||
|
flag_builder.enable("is_pic").unwrap();
|
||||||
|
let flags = settings::Flags::new(flag_builder);
|
||||||
|
|
||||||
use crate::settings::Configurable;
|
use crate::settings::Configurable;
|
||||||
let mut isa_flag_builder = x64::settings::builder();
|
let mut isa_flag_builder = x64::settings::builder();
|
||||||
|
|||||||
@@ -396,7 +396,10 @@ pub enum Inst {
|
|||||||
/// An instruction that will always trigger the illegal instruction exception.
|
/// An instruction that will always trigger the illegal instruction exception.
|
||||||
Ud2 { trap_code: TrapCode },
|
Ud2 { trap_code: TrapCode },
|
||||||
|
|
||||||
/// Loads an external symbol in a register, with a relocation: movabsq $name, dst
|
/// Loads an external symbol in a register, with a relocation:
|
||||||
|
///
|
||||||
|
/// movq $name@GOTPCREL(%rip), dst if PIC is enabled, or
|
||||||
|
/// movabsq $name, dst otherwise.
|
||||||
LoadExtName {
|
LoadExtName {
|
||||||
dst: Writable<Reg>,
|
dst: Writable<Reg>,
|
||||||
name: Box<ExternalName>,
|
name: Box<ExternalName>,
|
||||||
@@ -1692,7 +1695,7 @@ impl PrettyPrint for Inst {
|
|||||||
dst, name, offset, ..
|
dst, name, offset, ..
|
||||||
} => format!(
|
} => format!(
|
||||||
"{} {}+{}, {}",
|
"{} {}+{}, {}",
|
||||||
ljustify("movaps".into()),
|
ljustify("load_ext_name".into()),
|
||||||
name,
|
name,
|
||||||
offset,
|
offset,
|
||||||
show_ireg_sized(dst.to_reg(), mb_rru, 8),
|
show_ireg_sized(dst.to_reg(), mb_rru, 8),
|
||||||
|
|||||||
Reference in New Issue
Block a user