func mustLinkExternal(goos, goarch string, cgoEnabled bool) bool {
if cgoEnabled {
switch goarch {
- case "loong64",
- "mips", "mipsle", "mips64", "mips64le",
- "riscv64":
+ case "loong64", "mips", "mipsle", "mips64", "mips64le":
// Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/14449
return true
// Instruction encoding masks.
const (
- // JTypeImmMask is a mask including only the immediate portion of
- // J-type instructions.
- JTypeImmMask = 0xfffff000
+ // BTypeImmMask is a mask including only the immediate portion of
+ // B-type instructions.
+ BTypeImmMask = 0xfe000f80
+
+ // CBTypeImmMask is a mask including only the immediate portion of
+ // CB-type instructions.
+ CBTypeImmMask = 0x1c7c
+
+ // CJTypeImmMask is a mask including only the immediate portion of
+ // CJ-type instructions.
+ CJTypeImmMask = 0x1f7c
// ITypeImmMask is a mask including only the immediate portion of
// I-type instructions.
ITypeImmMask = 0xfff00000
+ // JTypeImmMask is a mask including only the immediate portion of
+ // J-type instructions.
+ JTypeImmMask = 0xfffff000
+
// STypeImmMask is a mask including only the immediate portion of
// S-type instructions.
STypeImmMask = 0xfe000f80
}
}
+// extractBitAndShift extracts the specified bit from the given immediate,
+// before shifting it to the requested position and returning it.
+func extractBitAndShift(imm uint32, bit, pos int) uint32 {
+ return ((imm >> bit) & 1) << pos
+}
+
// encodeR encodes an R-type RISC-V instruction.
func encodeR(as obj.As, rs1, rs2, rd, funct3, funct7 uint32) uint32 {
enc := encode(as)
return encodeS(ins.as, regI(ins.rd), regF(ins.rs1), uint32(ins.imm))
}
+// encodeBImmediate encodes an immediate for a B-type RISC-V instruction.
+func encodeBImmediate(imm uint32) uint32 {
+ return (imm>>12)<<31 | ((imm>>5)&0x3f)<<25 | ((imm>>1)&0xf)<<8 | ((imm>>11)&0x1)<<7
+}
+
// encodeB encodes a B-type RISC-V instruction.
func encodeB(ins *instruction) uint32 {
imm := immI(ins.as, ins.imm, 13)
if enc == nil {
panic("encodeB: could not encode instruction")
}
- return (imm>>12)<<31 | ((imm>>5)&0x3f)<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | ((imm>>1)&0xf)<<8 | ((imm>>11)&0x1)<<7 | enc.opcode
+ return encodeBImmediate(imm) | rs2<<20 | rs1<<15 | enc.funct3<<12 | enc.opcode
}
// encodeU encodes a U-type RISC-V instruction.
return encodeJImmediate(imm) | rd<<7 | enc.opcode
}
+// encodeCBImmediate encodes an immediate for a CB-type RISC-V instruction.
+func encodeCBImmediate(imm uint32) uint32 {
+ // Bit order - [8|4:3|7:6|2:1|5]
+ bits := extractBitAndShift(imm, 8, 7)
+ bits |= extractBitAndShift(imm, 4, 6)
+ bits |= extractBitAndShift(imm, 3, 5)
+ bits |= extractBitAndShift(imm, 7, 4)
+ bits |= extractBitAndShift(imm, 6, 3)
+ bits |= extractBitAndShift(imm, 2, 2)
+ bits |= extractBitAndShift(imm, 1, 1)
+ bits |= extractBitAndShift(imm, 5, 0)
+ return (bits>>5)<<10 | (bits&0x1f)<<2
+}
+
+// encodeCJImmediate encodes an immediate for a CJ-type RISC-V instruction.
+func encodeCJImmediate(imm uint32) uint32 {
+ // Bit order - [11|4|9:8|10|6|7|3:1|5]
+ bits := extractBitAndShift(imm, 11, 10)
+ bits |= extractBitAndShift(imm, 4, 9)
+ bits |= extractBitAndShift(imm, 9, 8)
+ bits |= extractBitAndShift(imm, 8, 7)
+ bits |= extractBitAndShift(imm, 10, 6)
+ bits |= extractBitAndShift(imm, 6, 5)
+ bits |= extractBitAndShift(imm, 7, 4)
+ bits |= extractBitAndShift(imm, 3, 3)
+ bits |= extractBitAndShift(imm, 2, 2)
+ bits |= extractBitAndShift(imm, 1, 1)
+ bits |= extractBitAndShift(imm, 5, 0)
+ return bits << 2
+}
+
func encodeRawIns(ins *instruction) uint32 {
// Treat the raw value specially as a 32-bit unsigned integer.
// Nobody wants to enter negative machine code.
return uint32(ins.imm)
}
-func EncodeJImmediate(imm int64) (int64, error) {
- if !immIFits(imm, 21) {
- return 0, fmt.Errorf("immediate %#x does not fit in 21 bits", imm)
+func EncodeBImmediate(imm int64) (int64, error) {
+ if !immIFits(imm, 13) {
+ return 0, fmt.Errorf("immediate %#x does not fit in 13 bits", imm)
}
if imm&1 != 0 {
return 0, fmt.Errorf("immediate %#x is not a multiple of two", imm)
}
- return int64(encodeJImmediate(uint32(imm))), nil
+ return int64(encodeBImmediate(uint32(imm))), nil
+}
+
+func EncodeCBImmediate(imm int64) (int64, error) {
+ if !immIFits(imm, 9) {
+ return 0, fmt.Errorf("immediate %#x does not fit in 9 bits", imm)
+ }
+ if imm&1 != 0 {
+ return 0, fmt.Errorf("immediate %#x is not a multiple of two", imm)
+ }
+ return int64(encodeCBImmediate(uint32(imm))), nil
+}
+
+func EncodeCJImmediate(imm int64) (int64, error) {
+ if !immIFits(imm, 12) {
+ return 0, fmt.Errorf("immediate %#x does not fit in 12 bits", imm)
+ }
+ if imm&1 != 0 {
+ return 0, fmt.Errorf("immediate %#x is not a multiple of two", imm)
+ }
+ return int64(encodeCJImmediate(uint32(imm))), nil
}
func EncodeIImmediate(imm int64) (int64, error) {
return imm << 20, nil
}
+func EncodeJImmediate(imm int64) (int64, error) {
+ if !immIFits(imm, 21) {
+ return 0, fmt.Errorf("immediate %#x does not fit in 21 bits", imm)
+ }
+ if imm&1 != 0 {
+ return 0, fmt.Errorf("immediate %#x is not a multiple of two", imm)
+ }
+ return int64(encodeJImmediate(uint32(imm))), nil
+}
+
func EncodeSImmediate(imm int64) (int64, error) {
if !immIFits(imm, 12) {
return 0, fmt.Errorf("immediate %#x does not fit in 12 bits", imm)
// LUI + I-type instruction sequence.
R_RISCV_TLS_LE
+ // R_RISCV_GOT_HI20 resolves the high 20 bits of a 32-bit PC-relative GOT
+ // address.
+ R_RISCV_GOT_HI20
+
+ // R_RISCV_PCREL_HI20 resolves the high 20 bits of a 32-bit PC-relative
+ // address.
+ R_RISCV_PCREL_HI20
+
+ // R_RISCV_PCREL_LO12_I resolves the low 12 bits of a 32-bit PC-relative
+ // address using an I-type instruction.
+ R_RISCV_PCREL_LO12_I
+
+ // R_RISCV_PCREL_LO12_S resolves the low 12 bits of a 32-bit PC-relative
+ // address using an S-type instruction.
+ R_RISCV_PCREL_LO12_S
+
+ // R_RISCV_BRANCH resolves a 12-bit PC-relative branch offset.
+ R_RISCV_BRANCH
+
+ // R_RISCV_RVC_BRANCH resolves an 8-bit PC-relative offset for a CB-type
+ // instruction.
+ R_RISCV_RVC_BRANCH
+
+ // R_RISCV_RVC_JUMP resolves an 11-bit PC-relative offset for a CJ-type
+ // instruction.
+ R_RISCV_RVC_JUMP
+
// R_PCRELDBL relocates s390x 2-byte aligned PC-relative addresses.
// TODO(mundaym): remove once variants can be serialized - see issue 14218.
R_PCRELDBL
_ = x[R_RISCV_PCREL_STYPE-63]
_ = x[R_RISCV_TLS_IE-64]
_ = x[R_RISCV_TLS_LE-65]
- _ = x[R_PCRELDBL-66]
- _ = x[R_ADDRLOONG64-67]
- _ = x[R_ADDRLOONG64U-68]
- _ = x[R_ADDRLOONG64TLS-69]
- _ = x[R_ADDRLOONG64TLSU-70]
- _ = x[R_CALLLOONG64-71]
- _ = x[R_LOONG64_TLS_IE_PCREL_HI-72]
- _ = x[R_LOONG64_TLS_IE_LO-73]
- _ = x[R_JMPLOONG64-74]
- _ = x[R_ADDRMIPSU-75]
- _ = x[R_ADDRMIPSTLS-76]
- _ = x[R_ADDRCUOFF-77]
- _ = x[R_WASMIMPORT-78]
- _ = x[R_XCOFFREF-79]
- _ = x[R_PEIMAGEOFF-80]
- _ = x[R_INITORDER-81]
+ _ = x[R_RISCV_GOT_HI20-66]
+ _ = x[R_RISCV_PCREL_HI20-67]
+ _ = x[R_RISCV_PCREL_LO12_I-68]
+ _ = x[R_RISCV_PCREL_LO12_S-69]
+ _ = x[R_RISCV_BRANCH-70]
+ _ = x[R_RISCV_RVC_BRANCH-71]
+ _ = x[R_RISCV_RVC_JUMP-72]
+ _ = x[R_PCRELDBL-73]
+ _ = x[R_ADDRLOONG64-74]
+ _ = x[R_ADDRLOONG64U-75]
+ _ = x[R_ADDRLOONG64TLS-76]
+ _ = x[R_ADDRLOONG64TLSU-77]
+ _ = x[R_CALLLOONG64-78]
+ _ = x[R_LOONG64_TLS_IE_PCREL_HI-79]
+ _ = x[R_LOONG64_TLS_IE_LO-80]
+ _ = x[R_JMPLOONG64-81]
+ _ = x[R_ADDRMIPSU-82]
+ _ = x[R_ADDRMIPSTLS-83]
+ _ = x[R_ADDRCUOFF-84]
+ _ = x[R_WASMIMPORT-85]
+ _ = x[R_XCOFFREF-86]
+ _ = x[R_PEIMAGEOFF-87]
+ _ = x[R_INITORDER-88]
}
-const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_USEGENERICIFACEMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_PCREL_LDST8R_ARM64_PCREL_LDST16R_ARM64_PCREL_LDST32R_ARM64_PCREL_LDST64R_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_POWER_TLS_IE_PCREL34R_POWER_TLS_LE_TPREL34R_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_GOT_PCREL34R_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_ADDRPOWER_D34R_ADDRPOWER_PCREL34R_RISCV_CALLR_RISCV_CALL_TRAMPR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IER_RISCV_TLS_LER_PCRELDBLR_ADDRLOONG64R_ADDRLOONG64UR_ADDRLOONG64TLSR_ADDRLOONG64TLSUR_CALLLOONG64R_LOONG64_TLS_IE_PCREL_HIR_LOONG64_TLS_IE_LOR_JMPLOONG64R_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREFR_PEIMAGEOFFR_INITORDER"
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_USEGENERICIFACEMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_PCREL_LDST8R_ARM64_PCREL_LDST16R_ARM64_PCREL_LDST32R_ARM64_PCREL_LDST64R_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_POWER_TLS_IE_PCREL34R_POWER_TLS_LE_TPREL34R_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_GOT_PCREL34R_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_ADDRPOWER_D34R_ADDRPOWER_PCREL34R_RISCV_CALLR_RISCV_CALL_TRAMPR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IER_RISCV_TLS_LER_RISCV_GOT_HI20R_RISCV_PCREL_HI20R_RISCV_PCREL_LO12_IR_RISCV_PCREL_LO12_SR_RISCV_BRANCHR_RISCV_RVC_BRANCHR_RISCV_RVC_JUMPR_PCRELDBLR_ADDRLOONG64R_ADDRLOONG64UR_ADDRLOONG64TLSR_ADDRLOONG64TLSUR_CALLLOONG64R_LOONG64_TLS_IE_PCREL_HIR_LOONG64_TLS_IE_LOR_JMPLOONG64R_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREFR_PEIMAGEOFFR_INITORDER"
-var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 194, 210, 233, 244, 250, 261, 271, 280, 293, 307, 321, 335, 351, 362, 375, 394, 414, 434, 454, 467, 481, 495, 509, 524, 538, 552, 563, 585, 607, 621, 636, 659, 676, 694, 715, 730, 749, 761, 779, 798, 817, 831, 845, 855, 868, 882, 898, 915, 928, 953, 972, 984, 995, 1008, 1019, 1031, 1041, 1053, 1064}
+var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 194, 210, 233, 244, 250, 261, 271, 280, 293, 307, 321, 335, 351, 362, 375, 394, 414, 434, 454, 467, 481, 495, 509, 524, 538, 552, 563, 585, 607, 621, 636, 659, 676, 694, 715, 730, 749, 761, 779, 798, 817, 831, 845, 861, 879, 899, 919, 933, 951, 967, 977, 990, 1004, 1020, 1037, 1050, 1075, 1094, 1106, 1117, 1130, 1141, 1153, 1163, 1175, 1186}
func (i RelocType) String() string {
i -= 1
return -1
}
-func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
+func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
if plt.Size() == 0 {
// pushq got+8(IP)
plt.AddUint8(0xff)
return true
}
-func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
+func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
if plt.Size() == 0 {
// str lr, [sp, #-4]!
plt.AddUint32(ctxt.Arch, 0xe52de004)
return loader.ExtReloc{}, false
}
-func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
+func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
if plt.Size() == 0 {
// stp x16, x30, [sp, #-16]!
// identifying information
case 1:
P[off] = byte(int8(o))
case 2:
- if o != int64(int16(o)) {
- st.err.Errorf(s, "relocation address for %s is too big: %#x", ldr.SymName(rs), o)
+ if (rt == objabi.R_PCREL || rt == objabi.R_CALL) && o != int64(int16(o)) {
+ st.err.Errorf(s, "pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), o)
+ } else if o != int64(int16(o)) && o != int64(uint16(o)) {
+ st.err.Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), uint64(o))
}
target.Arch.ByteOrder.PutUint16(P[off:], uint16(o))
case 4:
- if rt == objabi.R_PCREL || rt == objabi.R_CALL {
- if o != int64(int32(o)) {
- st.err.Errorf(s, "pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), o)
- }
- } else {
- if o != int64(int32(o)) && o != int64(uint32(o)) {
- st.err.Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), uint64(o))
- }
+ if (rt == objabi.R_PCREL || rt == objabi.R_CALL) && o != int64(int32(o)) {
+ st.err.Errorf(s, "pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), o)
+ } else if o != int64(int32(o)) && o != int64(uint32(o)) {
+ st.err.Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), uint64(o))
}
target.Arch.ByteOrder.PutUint32(P[off:], uint32(o))
case 8:
Reloc1 func(*Link, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int, int64) bool
RelocSize uint32 // size of an ELF relocation record, must match Reloc1.
- SetupPLT func(ctxt *Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
+ SetupPLT func(ctxt *Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
// DynamicReadOnly can be set to true to make the .dynamic
// section read-only. By default it is writable.
// S390X uses .got instead of .got.plt
gotplt = got
}
- thearch.ELF.SetupPLT(ctxt, plt, gotplt, dynamic.Sym())
+ thearch.ELF.SetupPLT(ctxt, ctxt.loader, plt, gotplt, dynamic.Sym())
/*
* .dynamic table
"internal/buildcfg"
"os"
"path/filepath"
+ "strings"
)
const funcSize = 11 * 4 // funcSize is the size of the _func object in runtime/runtime2.go
}
func emitPcln(ctxt *Link, s loader.Sym, container loader.Bitmap) bool {
+ if ctxt.Target.IsRISCV64() {
+ // Avoid adding local symbols to the pcln table - RISC-V
+ // linking generates a very large number of these, particularly
+ // for HI20 symbols (which we need to load in order to be able
+ // to resolve relocations). Unnecessarily including all of
+ // these symbols quickly blows out the size of the pcln table
+ // and overflows hash buckets.
+ symName := ctxt.loader.SymName(s)
+ if symName == "" || strings.HasPrefix(symName, ".L") {
+ return false
+ }
+ }
+
// We want to generate func table entries only for the "lowest
// level" symbols, not containers of subsymbols.
return !container.Has(s)
}
sect = &elfobj.sect[elfsym.shndx]
if sect.sym == 0 {
- if strings.HasPrefix(elfsym.name, ".Linfo_string") { // clang does this
- continue
- }
+ if elfsym.type_ == 0 {
+ if strings.HasPrefix(sect.name, ".debug_") && elfsym.name == "" {
+ // clang on arm and riscv64.
+ // This reportedly happens with clang 3.7 on ARM.
+ // See issue 13139.
+ continue
+ }
+ if strings.HasPrefix(elfsym.name, ".Ldebug_") || elfsym.name == ".L0 " {
+ // gcc on riscv64.
+ continue
+ }
+ if elfsym.name == ".Lline_table_start0" {
+ // clang on riscv64.
+ continue
+ }
- if elfsym.name == "" && elfsym.type_ == 0 && sect.name == ".debug_str" {
- // This reportedly happens with clang 3.7 on ARM.
- // See issue 13139.
- continue
+ if strings.HasPrefix(elfsym.name, "$d") && sect.name == ".debug_frame" {
+ // "$d" is a marker, not a real symbol.
+ // This happens with gcc on ARM64.
+ // See https://sourceware.org/bugzilla/show_bug.cgi?id=21809
+ continue
+ }
}
- if strings.HasPrefix(elfsym.name, "$d") && elfsym.type_ == 0 && sect.name == ".debug_frame" {
- // "$d" is a marker, not a real symbol.
- // This happens with gcc on ARM64.
- // See https://sourceware.org/bugzilla/show_bug.cgi?id=21809
+ if strings.HasPrefix(elfsym.name, ".Linfo_string") {
+ // clang does this
continue
}
- if strings.HasPrefix(elfsym.name, ".LASF") { // gcc on s390x does this
+ if strings.HasPrefix(elfsym.name, ".LASF") || strings.HasPrefix(elfsym.name, ".LLRL") || strings.HasPrefix(elfsym.name, ".LLST") {
+ // gcc on s390x and riscv64 does this.
continue
}
- return errorf("%v: sym#%d (%s): ignoring symbol in section %d (type %d)", elfsym.sym, i, elfsym.name, elfsym.shndx, elfsym.type_)
+
+ return errorf("%v: sym#%d (%q): ignoring symbol in section %d (%q) (type %d)", elfsym.sym, i, elfsym.name, elfsym.shndx, sect.name, elfsym.type_)
}
s := elfsym.sym
return true
}
-func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
+func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
return
}
return true
}
-func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
+func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
return
}
return true
}
-func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
+func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
if plt.Size() != 0 {
return
}
return true
}
-func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
+func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
if plt.Size() == 0 {
// The dynamic linker stores the address of the
// dynamic resolver and the DSO identifier in the two
// fakeLabelName matches the RISCV_FAKE_LABEL_NAME from binutils.
const fakeLabelName = ".L0 "
-func gentext(ctxt *ld.Link, ldr *loader.Loader) {
+func gentext(ctxt *ld.Link, ldr *loader.Loader) {}
+
+func findHI20Reloc(ldr *loader.Loader, s loader.Sym, val int64) *loader.Reloc {
+ outer := ldr.OuterSym(s)
+ if outer == 0 {
+ return nil
+ }
+ relocs := ldr.Relocs(outer)
+ start := sort.Search(relocs.Count(), func(i int) bool { return ldr.SymValue(outer)+int64(relocs.At(i).Off()) >= val })
+ for idx := start; idx < relocs.Count(); idx++ {
+ r := relocs.At(idx)
+ if ldr.SymValue(outer)+int64(r.Off()) != val {
+ break
+ }
+ if r.Type() == objabi.R_RISCV_GOT_HI20 || r.Type() == objabi.R_RISCV_PCREL_HI20 {
+ return &r
+ }
+ }
+ return nil
+}
+
+func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
+ targ := r.Sym()
+
+ var targType sym.SymKind
+ if targ != 0 {
+ targType = ldr.SymType(targ)
+ }
+
+ switch r.Type() {
+ case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_CALL),
+ objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_CALL_PLT):
+
+ if targType == sym.SDYNIMPORT {
+ addpltsym(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocSym(rIdx, syms.PLT)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
+ }
+ if targType == 0 || targType == sym.SXREF {
+ ldr.Errorf(s, "unknown symbol %s in RISCV call", ldr.SymName(targ))
+ }
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_ITYPE)
+ return true
+
+ case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_GOT_HI20):
+ if targType != sym.SDYNIMPORT {
+ // TODO(jsing): Could convert to non-GOT reference.
+ }
+
+ ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_RISCV_64))
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_RISCV_GOT_HI20)
+ su.SetRelocSym(rIdx, syms.GOT)
+ su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
+ return true
+
+ case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_HI20):
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_HI20)
+ return true
+
+ case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_LO12_I):
+ if r.Add() != 0 {
+ ldr.Errorf(s, "R_RISCV_PCREL_LO12_I with non-zero addend")
+ }
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_LO12_I)
+ return true
+
+ case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_PCREL_LO12_S):
+ if r.Add() != 0 {
+ ldr.Errorf(s, "R_RISCV_PCREL_LO12_S with non-zero addend")
+ }
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_LO12_S)
+ return true
+
+ case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RVC_BRANCH):
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_RISCV_RVC_BRANCH)
+ return true
+
+ case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RVC_JUMP):
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_RISCV_RVC_JUMP)
+ return true
+
+ case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_BRANCH):
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_RISCV_BRANCH)
+ return true
+
+ case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RELAX):
+ // Ignore relaxations, at least for now.
+ return true
+
+ default:
+ if r.Type() >= objabi.ElfRelocOffset {
+ ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
+ return false
+ }
+ }
+
+ // Reread the reloc to incorporate any changes in type above.
+ relocs := ldr.Relocs(s)
+ r = relocs.At(rIdx)
+
+ switch r.Type() {
+ case objabi.R_RISCV_PCREL_ITYPE:
+ if targType != sym.SDYNIMPORT {
+ // nothing to do, the relocation will be laid out in reloc
+ return true
+ }
+ if target.IsExternal() {
+ // External linker will do this relocation.
+ return true
+ }
+ // Internal linking.
+ if r.Add() != 0 {
+ ldr.Errorf(s, "PLT reference with non-zero addend (%v)", r.Add())
+ }
+ // Build a PLT entry and change the relocation target to that entry.
+ addpltsym(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocSym(rIdx, syms.PLT)
+ su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
+
+ return true
+ }
+
+ return false
}
func genSymsLate(ctxt *ld.Link, ldr *loader.Loader) {
// corresponding R_RISCV_PCREL_LO12_I or R_RISCV_PCREL_LO12_S relocation.
// Note that the LO12 relocation must point to a target that has a valid
// HI20 PC-relative relocation text symbol, which in turn points to the
- // given symbol. For further details see the ELF specification for RISC-V:
+ // given symbol. For further details see section 8.4.9 of the RISC-V ABIs
+ // Specification:
//
- // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#pc-relative-symbol-addresses
+ // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf
//
var hiRel, loRel elf.R_RISCV
switch r.Type {
return true
}
-func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
- log.Fatalf("elfsetupplt")
+func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
+ if plt.Size() != 0 {
+ return
+ }
+ if gotplt.Size() != 0 {
+ ctxt.Errorf(gotplt.Sym(), "got.plt is not empty")
+ }
+
+ // See section 8.4.6 of the RISC-V ABIs Specification:
+ //
+ // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf
+ //
+ // 1: auipc t2, %pcrel_hi(.got.plt)
+ // sub t1, t1, t3 # shifted .got.plt offset + hdr size + 12
+ // l[w|d] t3, %pcrel_lo(1b)(t2) # _dl_runtime_resolve
+ // addi t1, t1, -(hdr size + 12) # shifted .got.plt offset
+ // addi t0, t2, %pcrel_lo(1b) # &.got.plt
+ // srli t1, t1, log2(16/PTRSIZE) # .got.plt offset
+ // l[w|d] t0, PTRSIZE(t0) # link map
+ // jr t3
+
+ plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_RISCV_PCREL_HI20, 4)
+ plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x00000397) // auipc t2,0x0
+
+ sb := ldr.MakeSymbolBuilder(fakeLabelName)
+ sb.SetType(sym.STEXT)
+ sb.SetValue(ldr.SymValue(plt.Sym()) + plt.Size() - 4)
+ sb.SetLocal(true)
+ sb.SetReachable(true)
+ sb.SetVisibilityHidden(true)
+ plt.AddInteriorSym(sb.Sym())
+
+ plt.AddUint32(ctxt.Arch, 0x41c30333) // sub t1,t1,t3
+
+ plt.AddSymRef(ctxt.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
+ plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x0003be03) // ld t3,0(t2)
+
+ plt.AddUint32(ctxt.Arch, 0xfd430313) // addi t1,t1,-44
+
+ plt.AddSymRef(ctxt.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
+ plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x00038293) // addi t0,t2,0
+
+ plt.AddUint32(ctxt.Arch, 0x00135313) // srli t1,t1,0x1
+ plt.AddUint32(ctxt.Arch, 0x0082b283) // ld t0,8(t0)
+ plt.AddUint32(ctxt.Arch, 0x00008e02) // jr t3
+
+ gotplt.AddAddrPlus(ctxt.Arch, dynamic, 0) // got.plt[0] = _dl_runtime_resolve
+ gotplt.AddUint64(ctxt.Arch, 0) // got.plt[1] = link map
+}
+
+func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+ if ldr.SymPlt(s) >= 0 {
+ return
+ }
+
+ ld.Adddynsym(ldr, target, syms, s)
+
+ plt := ldr.MakeSymbolUpdater(syms.PLT)
+ gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT)
+ rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
+ if plt.Size() == 0 {
+ panic("plt is not set up")
+ }
+
+ // See section 8.4.6 of the RISC-V ABIs Specification:
+ //
+ // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/download/v1.0/riscv-abi.pdf
+ //
+ // 1: auipc t3, %pcrel_hi(function@.got.plt)
+ // l[w|d] t3, %pcrel_lo(1b)(t3)
+ // jalr t1, t3
+ // nop
+
+ plt.AddSymRef(target.Arch, gotplt.Sym(), gotplt.Size(), objabi.R_RISCV_PCREL_HI20, 4)
+ plt.SetUint32(target.Arch, plt.Size()-4, 0x00000e17) // auipc t3,0x0
+
+ sb := ldr.MakeSymbolBuilder(fakeLabelName)
+ sb.SetType(sym.STEXT)
+ sb.SetValue(ldr.SymValue(plt.Sym()) + plt.Size() - 4)
+ sb.SetLocal(true)
+ sb.SetReachable(true)
+ sb.SetVisibilityHidden(true)
+ plt.AddInteriorSym(sb.Sym())
+
+ plt.AddSymRef(target.Arch, sb.Sym(), 0, objabi.R_RISCV_PCREL_LO12_I, 4)
+ plt.SetUint32(target.Arch, plt.Size()-4, 0x000e3e03) // ld t3,0(t3)
+ plt.AddUint32(target.Arch, 0x000e0367) // jalr t1,t3
+ plt.AddUint32(target.Arch, 0x00000001) // nop
+
+ ldr.SetPlt(s, int32(plt.Size()-16))
+
+ // add to got.plt: pointer to plt[0]
+ gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
+
+ // rela
+ rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
+ sDynid := ldr.SymDynid(s)
+
+ rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_RISCV_JUMP_SLOT)))
+ rela.AddUint64(target.Arch, 0)
}
func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
return val, 0, true
- case objabi.R_RISCV_TLS_IE, objabi.R_RISCV_TLS_LE:
- // TLS relocations are not currently handled for internal linking.
- // For now, TLS is only used when cgo is in use and cgo currently
- // requires external linking. However, we need to accept these
- // relocations so that code containing TLS variables will link,
- // even when they're not being used. For now, replace these
- // instructions with EBREAK to detect accidental use.
- const ebreakIns = 0x00100073
- return ebreakIns<<32 | ebreakIns, 0, true
+ case objabi.R_RISCV_TLS_IE:
+ log.Fatalf("cannot handle R_RISCV_TLS_IE (sym %s) when linking internally", ldr.SymName(s))
+ return val, 0, false
+
+ case objabi.R_RISCV_TLS_LE:
+ // Generate LUI and ADDIW instruction immediates.
+ off := r.Add()
+
+ low, high, err := riscv.Split32BitImmediate(off)
+ if err != nil {
+ ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
+ }
+
+ luiImm, err := riscv.EncodeUImmediate(high)
+ if err != nil {
+ ldr.Errorf(s, "cannot encode R_RISCV_TLS_LE LUI relocation offset for %s: %v", ldr.SymName(rs), err)
+ }
+
+ addiwImm, err := riscv.EncodeIImmediate(low)
+ if err != nil {
+ ldr.Errorf(s, "cannot encode R_RISCV_TLS_LE I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
+ }
+
+ lui := int64(uint32(val))
+ addiw := int64(uint32(val >> 32))
+
+ lui = (lui &^ riscv.UTypeImmMask) | int64(uint32(luiImm))
+ addiw = (addiw &^ riscv.ITypeImmMask) | int64(uint32(addiwImm))
+
+ return addiw<<32 | lui, 0, true
+
+ case objabi.R_RISCV_BRANCH:
+ pc := ldr.SymValue(s) + int64(r.Off())
+ off := ldr.SymValue(rs) + r.Add() - pc
+
+ imm, err := riscv.EncodeBImmediate(off)
+ if err != nil {
+ ldr.Errorf(s, "cannot encode B-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
+ }
+ ins := (int64(uint32(val)) &^ riscv.BTypeImmMask) | int64(uint32(imm))
+
+ return ins, 0, true
+
+ case objabi.R_RISCV_RVC_BRANCH, objabi.R_RISCV_RVC_JUMP:
+ pc := ldr.SymValue(s) + int64(r.Off())
+ off := ldr.SymValue(rs) + r.Add() - pc
+
+ var err error
+ var imm, immMask int64
+ switch r.Type() {
+ case objabi.R_RISCV_RVC_BRANCH:
+ immMask = riscv.CBTypeImmMask
+ imm, err = riscv.EncodeCBImmediate(off)
+ if err != nil {
+ ldr.Errorf(s, "cannot encode CB-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
+ }
+ case objabi.R_RISCV_RVC_JUMP:
+ immMask = riscv.CJTypeImmMask
+ imm, err = riscv.EncodeCJImmediate(off)
+ if err != nil {
+ ldr.Errorf(s, "cannot encode CJ-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
+ }
+ default:
+ panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
+ }
+
+ ins := (int64(uint16(val)) &^ immMask) | int64(uint16(imm))
+
+ return ins, 0, true
+
+ case objabi.R_RISCV_GOT_HI20, objabi.R_RISCV_PCREL_HI20:
+ pc := ldr.SymValue(s) + int64(r.Off())
+ off := ldr.SymValue(rs) + r.Add() - pc
+
+ // Generate AUIPC immediates.
+ _, high, err := riscv.Split32BitImmediate(off)
+ if err != nil {
+ ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
+ }
+
+ auipcImm, err := riscv.EncodeUImmediate(high)
+ if err != nil {
+ ldr.Errorf(s, "cannot encode R_RISCV_PCREL_ AUIPC relocation offset for %s: %v", ldr.SymName(rs), err)
+ }
+
+ auipc := int64(uint32(val))
+ auipc = (auipc &^ riscv.UTypeImmMask) | int64(uint32(auipcImm))
+
+ return auipc, 0, true
+
+ case objabi.R_RISCV_PCREL_LO12_I, objabi.R_RISCV_PCREL_LO12_S:
+ hi20Reloc := findHI20Reloc(ldr, rs, ldr.SymValue(rs))
+ if hi20Reloc == nil {
+ ldr.Errorf(s, "missing HI20 relocation for LO12 relocation with %s (%d)", ldr.SymName(rs), rs)
+ }
+
+ pc := ldr.SymValue(s) + int64(hi20Reloc.Off())
+ off := ldr.SymValue(hi20Reloc.Sym()) + hi20Reloc.Add() - pc
+
+ low, _, err := riscv.Split32BitImmediate(off)
+ if err != nil {
+ ldr.Errorf(s, "relocation does not fit in 32-bits: %d", off)
+ }
+
+ var imm, immMask int64
+ switch r.Type() {
+ case objabi.R_RISCV_PCREL_LO12_I:
+ immMask = riscv.ITypeImmMask
+ imm, err = riscv.EncodeIImmediate(low)
+ if err != nil {
+ ldr.Errorf(s, "cannot encode objabi.R_RISCV_PCREL_LO12_I I-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
+ }
+ case objabi.R_RISCV_PCREL_LO12_S:
+ immMask = riscv.STypeImmMask
+ imm, err = riscv.EncodeSImmediate(low)
+ if err != nil {
+ ldr.Errorf(s, "cannot encode R_RISCV_PCREL_LO12_S S-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
+ }
+ default:
+ panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
+ }
+
+ ins := int64(uint32(val))
+ ins = (ins &^ immMask) | int64(uint32(imm))
+ return ins, 0, true
case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE:
// Generate AUIPC and second instruction immediates.
ldr.Errorf(s, "cannot encode R_RISCV_PCREL_STYPE S-type instruction relocation offset for %s: %v", ldr.SymName(rs), err)
}
default:
- panic(fmt.Sprintf("Unknown relocation type: %v", r.Type()))
+ panic(fmt.Sprintf("unknown relocation type: %v", r.Type()))
}
auipc := int64(uint32(val))
func genCallTramp(arch *sys.Arch, linkmode ld.LinkMode, ldr *loader.Loader, tramp *loader.SymbolBuilder, target loader.Sym, offset int64) {
tramp.AddUint32(arch, 0x00000f97) // AUIPC $0, X31
- tramp.AddUint32(arch, 0x000f8067) // JALR X0, (X31)
+ tramp.AddUint32(arch, 0x000f8067) // JALR X0, (X31)
r, _ := tramp.AddRel(objabi.R_RISCV_PCREL_ITYPE)
r.SetSiz(8)
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
+ Adddynrel: adddynrel,
Archinit: archinit,
Archreloc: archreloc,
Archrelocvariant: archrelocvariant,
return true
}
-func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
+func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
if plt.Size() == 0 {
// stg %r1,56(%r15)
plt.AddUint8(0xe3)
return elf.R_PPC64(nr).String()
case sys.S390X:
return elf.R_390(nr).String()
+ case sys.RISCV64:
+ return elf.R_RISCV(nr).String()
default:
panic("unreachable")
}
return -1
}
-func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
+func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
if plt.Size() == 0 {
// pushl got+4
plt.AddUint8(0xff)
func MustLinkExternal(goos, goarch string, withCgo bool) bool {
if withCgo {
switch goarch {
- case "loong64",
- "mips", "mipsle", "mips64", "mips64le",
- "riscv64":
+ case "loong64", "mips", "mipsle", "mips64", "mips64le":
// Internally linking cgo is incomplete on some architectures.
// https://go.dev/issue/14449
return true