Merge pull request #2558 from cfallin/pic-symbol-refs
x64: support PC-rel symbol references using the GOT when in PIC mode.
This commit is contained in:
@@ -2716,16 +2716,41 @@ pub(crate) fn emit(
|
||||
}
|
||||
|
||||
Inst::LoadExtName { dst, name, offset } => {
|
||||
// The full address can be encoded in the register, with a relocation.
|
||||
// Generates: movabsq $name, %dst
|
||||
let enc_dst = int_reg_enc(dst.to_reg());
|
||||
sink.put1(0x48 | ((enc_dst >> 3) & 1));
|
||||
sink.put1(0xB8 | (enc_dst & 7));
|
||||
emit_reloc(sink, state, Reloc::Abs8, name, *offset);
|
||||
if info.flags().emit_all_ones_funcaddrs() {
|
||||
sink.put8(u64::max_value());
|
||||
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 {
|
||||
sink.put8(0);
|
||||
// The full address can be encoded in the register, with a relocation.
|
||||
// Generates: movabsq $name, %dst
|
||||
let enc_dst = int_reg_enc(dst.to_reg());
|
||||
sink.put1(0x48 | ((enc_dst >> 3) & 1));
|
||||
sink.put1(0xB8 | (enc_dst & 7));
|
||||
emit_reloc(sink, state, Reloc::Abs8, name, *offset);
|
||||
if info.flags().emit_all_ones_funcaddrs() {
|
||||
sink.put8(u64::max_value());
|
||||
} else {
|
||||
sink.put8(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2860,6 +2860,46 @@ fn test_x64_emit() {
|
||||
"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
|
||||
insns.push((Inst::ret(), "C3", "ret"));
|
||||
@@ -3781,7 +3821,9 @@ fn test_x64_emit() {
|
||||
|
||||
// ========================================================
|
||||
// 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;
|
||||
let mut isa_flag_builder = x64::settings::builder();
|
||||
|
||||
@@ -397,7 +397,10 @@ pub enum Inst {
|
||||
/// An instruction that will always trigger the illegal instruction exception.
|
||||
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 {
|
||||
dst: Writable<Reg>,
|
||||
name: Box<ExternalName>,
|
||||
@@ -1726,7 +1729,7 @@ impl PrettyPrint for Inst {
|
||||
dst, name, offset, ..
|
||||
} => format!(
|
||||
"{} {}+{}, {}",
|
||||
ljustify("movaps".into()),
|
||||
ljustify("load_ext_name".into()),
|
||||
name,
|
||||
offset,
|
||||
show_ireg_sized(dst.to_reg(), mb_rru, 8),
|
||||
|
||||
Reference in New Issue
Block a user