From 1046a9cb1b348a91e551ed2d1714e0926a1b04b1 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Mon, 4 Nov 2019 01:05:46 +1100 Subject: [PATCH] cmd/link,cmd/internal/obj/riscv: implement archreloc for riscv64 Based on the riscv-go port. Updates #27532 Change-Id: I478254306441c253d3a2c09c10932ad1ac0be3c6 Reviewed-on: https://go-review.googlesource.com/c/go/+/204625 Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot --- src/cmd/internal/obj/riscv/obj.go | 27 +++++++++++++-- src/cmd/link/internal/riscv64/asm.go | 50 ++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index 9a3930f5df..b90be07163 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -324,7 +324,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) { off := p.From.Offset to := p.To - low, high, err := split32BitImmediate(off) + low, high, err := Split32BitImmediate(off) if err != nil { ctxt.Diag("%v: constant %d too large: %v", p, off, err) } @@ -512,11 +512,11 @@ func signExtend(val int64, bit uint) int64 { return val << (64 - bit) >> (64 - bit) } -// split32BitImmediate splits a signed 32-bit immediate into a signed 20-bit +// Split32BitImmediate splits a signed 32-bit immediate into a signed 20-bit // upper immediate and a signed 12-bit lower immediate to be added to the upper // result. For example, high may be used in LUI and low in a following ADDI to // generate a full 32-bit constant. -func split32BitImmediate(imm int64) (low, high int64, err error) { +func Split32BitImmediate(imm int64) (low, high int64, err error) { if !immIFits(imm, 32) { return 0, 0, fmt.Errorf("immediate does not fit in 32-bits: %d", imm) } @@ -909,6 +909,27 @@ func encodeRaw(p *obj.Prog) uint32 { return uint32(a.Offset) } +func EncodeIImmediate(imm int64) (int64, error) { + if !immIFits(imm, 12) { + return 0, fmt.Errorf("immediate %#x does not fit in 12 bits", imm) + } + return imm << 20, nil +} + +func EncodeSImmediate(imm int64) (int64, error) { + if !immIFits(imm, 12) { + return 0, fmt.Errorf("immediate %#x does not fit in 12 bits", imm) + } + return ((imm >> 5) << 25) | ((imm & 0x1f) << 7), nil +} + +func EncodeUImmediate(imm int64) (int64, error) { + if !immUFits(imm, 20) { + return 0, fmt.Errorf("immediate %#x does not fit in 20 bits", imm) + } + return imm << 12, nil +} + type encoding struct { encode func(*obj.Prog) uint32 // encode returns the machine code for an *obj.Prog validate func(*obj.Prog) // validate validates an *obj.Prog, calling ctxt.Diag for any issues diff --git a/src/cmd/link/internal/riscv64/asm.go b/src/cmd/link/internal/riscv64/asm.go index 111ff9da12..b0897288fc 100644 --- a/src/cmd/link/internal/riscv64/asm.go +++ b/src/cmd/link/internal/riscv64/asm.go @@ -5,6 +5,7 @@ package riscv64 import ( + "cmd/internal/obj/riscv" "cmd/internal/objabi" "cmd/internal/sys" "cmd/link/internal/ld" @@ -40,8 +41,53 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, se } func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { - // TODO(jsing): Implement. - log.Fatalf("archreloc not implemented") + switch r.Type { + case objabi.R_CALLRISCV: + // Nothing to do. + return val, true + + case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE: + pc := s.Value + int64(r.Off) + off := ld.Symaddr(r.Sym) + r.Add - pc + + // Generate AUIPC and second instruction immediates. + low, high, err := riscv.Split32BitImmediate(off) + if err != nil { + ld.Errorf(s, "R_RISCV_PCREL_ relocation does not fit in 32-bits: %d", off) + } + + auipcImm, err := riscv.EncodeUImmediate(high) + if err != nil { + ld.Errorf(s, "cannot encode R_RISCV_PCREL_ AUIPC relocation offset for %s: %v", r.Sym.Name, err) + } + + var secondImm, secondImmMask int64 + switch r.Type { + case objabi.R_RISCV_PCREL_ITYPE: + secondImmMask = riscv.ITypeImmMask + secondImm, err = riscv.EncodeIImmediate(low) + if err != nil { + ld.Errorf(s, "cannot encode R_RISCV_PCREL_ITYPE I-type instruction relocation offset for %s: %v", r.Sym.Name, err) + } + case objabi.R_RISCV_PCREL_STYPE: + secondImmMask = riscv.STypeImmMask + secondImm, err = riscv.EncodeSImmediate(low) + if err != nil { + ld.Errorf(s, "cannot encode R_RISCV_PCREL_STYPE S-type instruction relocation offset for %s: %v", r.Sym.Name, err) + } + default: + panic(fmt.Sprintf("Unknown relocation type: %v", r.Type)) + } + + auipc := int64(uint32(val)) + second := int64(uint32(val >> 32)) + + auipc = (auipc &^ riscv.UTypeImmMask) | int64(uint32(auipcImm)) + second = (second &^ secondImmMask) | int64(uint32(secondImm)) + + return second<<32 | auipc, true + } + return val, false } -- 2.50.0