diff options
| author | Joel Sing <joel@sing.id.au> | 2023-08-17 01:13:32 +1000 |
|---|---|---|
| committer | Joel Sing <joel@sing.id.au> | 2023-09-19 18:10:13 +0000 |
| commit | bda5e6c3d07c23d477f68f09e3414e495b12a87e (patch) | |
| tree | 0dc955380cf1ba0bf7c9819e4a6ff5f9eb7192c6 /src/cmd/internal/obj | |
| parent | 3c4f12a7d6bc6839b3dd2f4b04aeca962745afb3 (diff) | |
| download | go-bda5e6c3d07c23d477f68f09e3414e495b12a87e.tar.xz | |
cmd/internal/obj/riscv,cmd/link: rework riscv64 call relocations
The riscv64 assembler and linker generate three types of calls.
Most calls are made via a single JAL instruction, however this is
limited to +/-1MB of text. In the case where a call target is
unreachable (or unknown), the JAL targets an AUIPC+JALR trampoline.
All other cases use AUIPC+JALR pairs, including the case where a
single function exceeds 1MB in text size, potentially making it
impossible to reach trampolines.
Currently, the single instruction JAL call is marked with R_RISCV_CALL
and the two instruction AUIPC+JALR call is marked with
R_RISCV_PCREL_ITYPE, which is also used for memory load instructions.
This means that we have no way to identify that the latter is a call.
Switch to using R_RISCV_CALL to mark the AUIPC+JALR pair (aligning
somewhat with the elf.R_RISCV_CALL, which is deprecated in favour of
elf.R_RISCV_CALL_PLT). Add R_RISCV_JAL and use this to mark the single
instruction JAL direct calls. This is clearer and allows us to map
elf.R_RISCV_CALL_PLT to Go's R_RISCV_CALL.
Add all three types to IsDirectCall, so that direct calls are correctly
identified when a function exceeds 1MB of text.
Fixes #62465
Change-Id: Id3eea09688a2b7d6e481eae9ed0aa0d1f9a3a48f
Reviewed-on: https://go-review.googlesource.com/c/go/+/520095
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Joel Sing <joel@sing.id.au>
Reviewed-by: Than McIntosh <thanm@google.com>
Diffstat (limited to 'src/cmd/internal/obj')
| -rw-r--r-- | src/cmd/internal/obj/riscv/cpu.go | 9 | ||||
| -rw-r--r-- | src/cmd/internal/obj/riscv/obj.go | 15 |
2 files changed, 16 insertions, 8 deletions
diff --git a/src/cmd/internal/obj/riscv/cpu.go b/src/cmd/internal/obj/riscv/cpu.go index bfd5153da4..edd1ac820b 100644 --- a/src/cmd/internal/obj/riscv/cpu.go +++ b/src/cmd/internal/obj/riscv/cpu.go @@ -260,8 +260,13 @@ const ( // corresponding *obj.Prog uses the temporary register. USES_REG_TMP = 1 << iota - // NEED_CALL_RELOC is set on JAL instructions to indicate that a - // R_RISCV_CALL relocation is needed. + // NEED_JAL_RELOC is set on JAL instructions to indicate that a + // R_RISCV_JAL relocation is needed. + NEED_JAL_RELOC + + // NEED_CALL_RELOC is set on an AUIPC instruction to indicate that it + // is the first instruction in an AUIPC + JAL pair that needs a + // R_RISCV_CALL relocation. NEED_CALL_RELOC // NEED_PCREL_ITYPE_RELOC is set on AUIPC instructions to indicate that diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index 4df28a43f6..501d518019 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -41,7 +41,7 @@ func jalToSym(ctxt *obj.Link, p *obj.Prog, lr int16) { } p.As = AJAL - p.Mark |= NEED_CALL_RELOC + p.Mark |= NEED_JAL_RELOC p.From.Type = obj.TYPE_REG p.From.Reg = lr p.Reg = obj.REG_NONE @@ -610,7 +610,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { var callCount int for p := cursym.Func().Text; p != nil; p = p.Link { markRelocs(p) - if p.Mark&NEED_CALL_RELOC == NEED_CALL_RELOC { + if p.Mark&NEED_JAL_RELOC == NEED_JAL_RELOC { callCount++ } } @@ -664,7 +664,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { jmp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_TMP} p.As = AAUIPC - p.Mark = (p.Mark &^ NEED_CALL_RELOC) | NEED_PCREL_ITYPE_RELOC + p.Mark = (p.Mark &^ NEED_JAL_RELOC) | NEED_CALL_RELOC p.AddRestSource(obj.Addr{Type: obj.TYPE_CONST, Offset: p.To.Offset, Sym: p.To.Sym}) p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: 0} p.Reg = obj.REG_NONE @@ -2345,13 +2345,13 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { for p := cursym.Func().Text; p != nil; p = p.Link { switch p.As { case AJAL: - if p.Mark&NEED_CALL_RELOC == NEED_CALL_RELOC { + if p.Mark&NEED_JAL_RELOC == NEED_JAL_RELOC { rel := obj.Addrel(cursym) rel.Off = int32(p.Pc) rel.Siz = 4 rel.Sym = p.To.Sym rel.Add = p.To.Offset - rel.Type = objabi.R_RISCV_CALL + rel.Type = objabi.R_RISCV_JAL } case AJALR: if p.To.Sym != nil { @@ -2361,7 +2361,10 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { case AAUIPC, AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD: var addr *obj.Addr var rt objabi.RelocType - if p.Mark&NEED_PCREL_ITYPE_RELOC == NEED_PCREL_ITYPE_RELOC { + if p.Mark&NEED_CALL_RELOC == NEED_CALL_RELOC { + rt = objabi.R_RISCV_CALL + addr = &p.From + } else if p.Mark&NEED_PCREL_ITYPE_RELOC == NEED_PCREL_ITYPE_RELOC { rt = objabi.R_RISCV_PCREL_ITYPE addr = &p.From } else if p.Mark&NEED_PCREL_STYPE_RELOC == NEED_PCREL_STYPE_RELOC { |
