Skip to content

Cranelift: implement PIC relocations on AArch64 #2907

@syrusakbary

Description

@syrusakbary

Cranelift emits AbsoluteRelocation Reloc::Abs8 when is_pic setting is enabled in architecture aarch64

Steps to Reproduce

(module
  ;; Recursive factorial
  (func (export "fac-rec") (param i64) (result i64)
    (if (result i64) (i64.eq (local.get 0) (i64.const 0))
      (then (i64.const 1))
      (else
        (i64.mul (local.get 0) (call 0 (i64.sub (local.get 0) (i64.const 1))))
      )
    )
  )
)
$ wasmtime wasm2obj fac.wat fac.o

Code emitted fac.o has absolute relocations.

Expected Results

Is expected for Cranelift to emit a relative relocation for aarch64 when is_pic is enabled.

Actual Results

Code emitted with an absolute relocation.

Versions and Environment

Cranelift version: cranelift-codegen = "0.73.0"
Operating system: Any
Architecture: Aarch64

Extra info

Here's where the wrong code is emitted:

&Inst::LoadExtName {
rd,
ref name,
offset,
} => {
let inst = Inst::ULoad64 {
rd,
mem: AMode::Label(MemLabel::PCRel(8)),
flags: MemFlags::trusted(),
};
inst.emit(sink, emit_info, state);
let inst = Inst::Jump {
dest: BranchTarget::ResolvedOffset(12),
};
inst.emit(sink, emit_info, state);
let srcloc = state.cur_srcloc();
sink.add_reloc(srcloc, Reloc::Abs8, name, offset);
if emit_info.flags().emit_all_ones_funcaddrs() {
sink.put8(u64::max_value());
} else {
sink.put8(0);
}
}

In the new x86 backend however, the is_pic case is properly handled:

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.
// 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);
}
}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIncorrect behavior in the current implementation that needs fixingcraneliftIssues related to the Cranelift code generatorcranelift:area:aarch64Issues related to AArch64 backend.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions