]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link,cmd/internal/obj/riscv: implement archreloc for riscv64
authorJoel Sing <joel@sing.id.au>
Sun, 3 Nov 2019 14:05:46 +0000 (01:05 +1100)
committerJoel Sing <joel@sing.id.au>
Tue, 19 Nov 2019 06:08:56 +0000 (06:08 +0000)
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 <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/internal/obj/riscv/obj.go
src/cmd/link/internal/riscv64/asm.go

index 9a3930f5df8cb256e91fe63f46709d03a1890ce1..b90be07163db0344190fe265ccbf5d5ed4d7cf73 100644 (file)
@@ -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
index 111ff9da126104773aabe59ba717c898caf5cfde..b0897288fcf13b99c51fad4dad144ff05fbc6493 100644 (file)
@@ -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
 }