]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: add internal linking support for calling SDYNIMPORT on mips64
authorJoel Sing <joel@sing.id.au>
Mon, 6 Jun 2022 20:08:51 +0000 (06:08 +1000)
committerGopher Robot <gobot@golang.org>
Wed, 22 Feb 2023 14:55:07 +0000 (14:55 +0000)
Add internal linking support for calling SDYNIMPORT symbols on mips64. This adds
code to generate appropriate PLT and GOT entries, along with the various dynamic
entries needed for the dynamic loader.

Updates #36435, #46178

Change-Id: I783e0d028510ca2bca82bcbc745f2375770813fe
Reviewed-on: https://go-review.googlesource.com/c/go/+/415815
Reviewed-by: Rong Zhang <rongrong@oss.cipunited.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Run-TryBot: Joel Sing <joel@sing.id.au>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Ian Lance Taylor <iant@google.com>

src/cmd/link/internal/ld/elf.go
src/cmd/link/internal/mips64/asm.go
src/cmd/link/internal/mips64/obj.go

index 954aaaff16643f9507dbc8803d5a126c41eccdc7..5eeb4a9993fef4c0db3597c9194cc24a8da469e7 100644 (file)
@@ -1623,6 +1623,7 @@ func (ctxt *Link) doelf() {
                // DT_JMPREL is emitted so we have to defer generation of elf.DT_PLTREL,
                // DT_PLTRELSZ, and elf.DT_JMPREL dynamic entries until after we know the
                // size of .rel(a).plt section.
+
                Elfwritedynent(ctxt.Arch, dynamic, elf.DT_DEBUG, 0)
        }
 
index 0e64af3e6ae194b4f61387b4c81d113ef1422325..bd0e0191bc8249439b7b375b44329cb806618012 100644 (file)
@@ -39,7 +39,97 @@ import (
        "debug/elf"
 )
 
-func gentext(ctxt *ld.Link, ldr *loader.Loader) {}
+var (
+       // dtOffsets contains offsets for entries within the .dynamic section.
+       // These are used to fix up symbol values once they are known.
+       dtOffsets map[elf.DynTag]int64
+
+       // dynSymCount contains the number of entries in the .dynsym section.
+       // This is used to populate the DT_MIPS_SYMTABNO entry in the .dynamic
+       // section.
+       dynSymCount uint64
+
+       // gotLocalCount contains the number of local global offset table
+       // entries. This is used to populate the DT_MIPS_LOCAL_GOTNO entry in
+       // the .dynamic section.
+       gotLocalCount uint64
+
+       // gotSymIndex contains the index of the first dynamic symbol table
+       // entry that corresponds to an entry in the global offset table.
+       // This is used to populate the DT_MIPS_GOTSYM entry in the .dynamic
+       // section.
+       gotSymIndex uint64
+)
+
+func gentext(ctxt *ld.Link, ldr *loader.Loader) {
+       if *ld.FlagD || ctxt.Target.IsExternal() {
+               return
+       }
+
+       dynamic := ldr.MakeSymbolUpdater(ctxt.ArchSyms.Dynamic)
+
+       ld.Elfwritedynent(ctxt.Arch, dynamic, elf.DT_MIPS_RLD_VERSION, 1)
+       ld.Elfwritedynent(ctxt.Arch, dynamic, elf.DT_MIPS_BASE_ADDRESS, 0)
+
+       // elfsetupplt should have been called and gotLocalCount should now
+       // have its correct value.
+       if gotLocalCount == 0 {
+               ctxt.Errorf(0, "internal error: elfsetupplt has not been called")
+       }
+       ld.Elfwritedynent(ctxt.Arch, dynamic, elf.DT_MIPS_LOCAL_GOTNO, gotLocalCount)
+
+       // DT_* entries have to exist prior to elfdynhash(), which finalises the
+       // table by adding DT_NULL. However, the values for the following entries
+       // are not know until after dynreloc() has completed. Add the symbols now,
+       // then update their values prior to code generation.
+       dts := []elf.DynTag{
+               elf.DT_MIPS_SYMTABNO,
+               elf.DT_MIPS_GOTSYM,
+       }
+       dtOffsets = make(map[elf.DynTag]int64)
+       for _, dt := range dts {
+               ld.Elfwritedynent(ctxt.Arch, dynamic, dt, 0)
+               dtOffsets[dt] = dynamic.Size() - 8
+       }
+}
+
+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)
+       }
+
+       if r.Type() >= objabi.ElfRelocOffset {
+               ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
+               return false
+       }
+
+       switch r.Type() {
+       case objabi.R_CALLMIPS, objabi.R_JMPMIPS:
+               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, build a PLT entry and change the relocation
+               // target to that entry.
+               if r.Add() != 0 {
+                       ldr.Errorf(s, "PLT call with non-zero addend (%v)", r.Add())
+               }
+               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 elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
 
@@ -95,7 +185,90 @@ func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym,
 }
 
 func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
-       return
+       if plt.Size() != 0 {
+               return
+       }
+
+       // Load resolver address from got[0] into r25.
+       plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_ADDRMIPSU, 4)
+       plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x3c0e0000) // lui   $14, %hi(&GOTPLT[0])
+       plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_ADDRMIPS, 4)
+       plt.SetUint32(ctxt.Arch, plt.Size()-4, 0xddd90000) // ld    $25, %lo(&GOTPLT[0])($14)
+
+       // Load return address into r15, the index of the got.plt entry into r24, then
+       // JALR to the resolver. The address of the got.plt entry is currently in r24,
+       // which we have to turn into an index.
+       plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 0, objabi.R_ADDRMIPS, 4)
+       plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x25ce0000) // addiu $14, $14, %lo(&GOTPLT[0])
+       plt.AddUint32(ctxt.Arch, 0x030ec023)               // subu  $24, $24, $14
+       plt.AddUint32(ctxt.Arch, 0x03e07825)               // move  $15, $31
+       plt.AddUint32(ctxt.Arch, 0x0018c0c2)               // srl   $24, $24, 3
+       plt.AddUint32(ctxt.Arch, 0x0320f809)               // jalr  $25
+       plt.AddUint32(ctxt.Arch, 0x2718fffe)               // subu  $24, $24, 2
+
+       if gotplt.Size() != 0 {
+               ctxt.Errorf(gotplt.Sym(), "got.plt is not empty")
+       }
+
+       // Reserve got[0] for resolver address (populated by dynamic loader).
+       gotplt.AddUint32(ctxt.Arch, 0)
+       gotplt.AddUint32(ctxt.Arch, 0)
+       gotLocalCount++
+
+       // Reserve got[1] for ELF object pointer (populated by dynamic loader).
+       gotplt.AddUint32(ctxt.Arch, 0)
+       gotplt.AddUint32(ctxt.Arch, 0)
+       gotLocalCount++
+}
+
+func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
+       if ldr.SymPlt(s) >= 0 {
+               return
+       }
+
+       dynamic := ldr.MakeSymbolUpdater(syms.Dynamic)
+
+       const dynSymEntrySize = 20
+       if gotSymIndex == 0 {
+               // Compute and update GOT symbol index.
+               gotSymIndex = uint64(ldr.SymSize(syms.DynSym) / dynSymEntrySize)
+               dynamic.SetUint(target.Arch, dtOffsets[elf.DT_MIPS_GOTSYM], gotSymIndex)
+       }
+       if dynSymCount == 0 {
+               dynSymCount = uint64(ldr.SymSize(syms.DynSym) / dynSymEntrySize)
+       }
+
+       ld.Adddynsym(ldr, target, syms, s)
+       dynSymCount++
+
+       if !target.IsElf() {
+               ldr.Errorf(s, "addpltsym: unsupported binary format")
+       }
+
+       plt := ldr.MakeSymbolUpdater(syms.PLT)
+       gotplt := ldr.MakeSymbolUpdater(syms.GOTPLT)
+       if plt.Size() == 0 {
+               panic("plt is not set up")
+       }
+
+       // Load got.plt entry into r25.
+       plt.AddSymRef(target.Arch, gotplt.Sym(), gotplt.Size(), objabi.R_ADDRMIPSU, 4)
+       plt.SetUint32(target.Arch, plt.Size()-4, 0x3c0f0000) // lui   $15, %hi(.got.plt entry)
+       plt.AddSymRef(target.Arch, gotplt.Sym(), gotplt.Size(), objabi.R_ADDRMIPS, 4)
+       plt.SetUint32(target.Arch, plt.Size()-4, 0xddf90000) // ld    $25, %lo(.got.plt entry)($15)
+
+       // Load address of got.plt entry into r24 and JALR to address in r25.
+       plt.AddUint32(target.Arch, 0x03200008) // jr  $25
+       plt.AddSymRef(target.Arch, gotplt.Sym(), gotplt.Size(), objabi.R_ADDRMIPS, 4)
+       plt.SetUint32(target.Arch, plt.Size()-4, 0x65f80000) // daddiu $24, $15, %lo(.got.plt entry)
+
+       // Add pointer to plt[0] to got.plt
+       gotplt.AddAddrPlus(target.Arch, plt.Sym(), 0)
+
+       ldr.SetPlt(s, int32(plt.Size()-16))
+
+       // Update dynamic symbol count.
+       dynamic.SetUint(target.Arch, dtOffsets[elf.DT_MIPS_SYMTABNO], dynSymCount)
 }
 
 func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
index a06e6f798147837010674c0d00a1380b7ab98160..7fb19e92ac74666dc441accb8e69886daefabb9e 100644 (file)
@@ -34,7 +34,6 @@ import (
        "cmd/internal/objabi"
        "cmd/internal/sys"
        "cmd/link/internal/ld"
-       "cmd/link/internal/loader"
        "internal/buildcfg"
 )
 
@@ -108,10 +107,8 @@ func archinit(ctxt *ld.Link) {
                        *ld.FlagRound = 0x10000
                }
        }
-}
-
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
-       ld.Exitf("adddynrel currently unimplemented for MIPS64")
-       return false
 
+       dynSymCount = 0
+       gotLocalCount = 0
+       gotSymIndex = 0
 }