mirror of
https://github.com/golang/go
synced 2024-10-14 03:43:28 +00:00
cmd/link: support -fno-plt compiled gcc objects on ppc64le
This is the initial trivial implemenation. Further improvements can be made for local calls. A test is added, but the -fno-plt option is ignored by gcc if binutils does not support inline plt relocations, so the test is effectively skipped on such hosts. Fixes #53345 Change-Id: Ibf31c26b1a8551c942b21019df8782c00b7a563e Reviewed-on: https://go-review.googlesource.com/c/go/+/412714 Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Run-TryBot: Paul Murphy <murp@ibm.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Jenny Rakoczy <jenny@golang.org> Auto-Submit: Jenny Rakoczy <jenny@golang.org> Run-TryBot: Jenny Rakoczy <jenny@golang.org>
This commit is contained in:
parent
e7a2014fac
commit
7fda98a8d9
38
src/cmd/go/testdata/script/test_ppc64le_cgo_inline_plt.txt
vendored
Normal file
38
src/cmd/go/testdata/script/test_ppc64le_cgo_inline_plt.txt
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Verify the linker will correctly resolve
|
||||
# ppc64le objects compiled with gcc's -fno-plt
|
||||
# option. This inlines PLT calls, and generates
|
||||
# additional reloc types which the internal linker
|
||||
# should handle.
|
||||
#
|
||||
# Verifies golang.org/issue/53345
|
||||
#
|
||||
# Note, older gcc/clang may accept this option, but
|
||||
# ignore it if binutils does not support the relocs.
|
||||
[!gc] skip
|
||||
[!cgo] skip
|
||||
[!ppc64le] skip
|
||||
|
||||
env CGO_CFLAGS='-fno-plt -O2 -g'
|
||||
|
||||
go build -ldflags='-linkmode=internal'
|
||||
exec ./noplttest
|
||||
stdout helloworld
|
||||
|
||||
-- go.mod --
|
||||
module noplttest
|
||||
|
||||
-- noplttest.go --
|
||||
package main
|
||||
|
||||
/*
|
||||
#include <stdio.h>
|
||||
void helloworld(void) {
|
||||
printf("helloworld\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
C.helloworld()
|
||||
}
|
|
@ -1108,8 +1108,19 @@ func relSize(arch *sys.Arch, pn string, elftype uint32) (uint8, uint8, error) {
|
|||
PPC64 | uint32(elf.R_PPC64_TOC16_LO_DS)<<16,
|
||||
PPC64 | uint32(elf.R_PPC64_REL16_LO)<<16,
|
||||
PPC64 | uint32(elf.R_PPC64_REL16_HI)<<16,
|
||||
PPC64 | uint32(elf.R_PPC64_REL16_HA)<<16:
|
||||
PPC64 | uint32(elf.R_PPC64_REL16_HA)<<16,
|
||||
PPC64 | uint32(elf.R_PPC64_PLT16_HA)<<16,
|
||||
PPC64 | uint32(elf.R_PPC64_PLT16_LO_DS)<<16:
|
||||
return 2, 4, nil
|
||||
|
||||
// PPC64 inline PLT sequence hint relocations (-fno-plt)
|
||||
// These are informational annotations to assist linker optimizations.
|
||||
case PPC64 | uint32(elf.R_PPC64_PLTSEQ)<<16,
|
||||
PPC64 | uint32(elf.R_PPC64_PLTCALL)<<16,
|
||||
PPC64 | uint32(elf.R_PPC64_PLTCALL_NOTOC)<<16,
|
||||
PPC64 | uint32(elf.R_PPC64_PLTSEQ_NOTOC)<<16:
|
||||
return 0, 0, nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -476,6 +476,53 @@ func addelfdynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s lo
|
|||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HA|sym.RV_CHECK_OVERFLOW)
|
||||
su.SetRelocAdd(rIdx, r.Add()+2)
|
||||
return true
|
||||
|
||||
// When compiling with gcc's -fno-plt option (no PLT), the following code and relocation
|
||||
// sequences may be present to call an external function:
|
||||
//
|
||||
// 1. addis Rx,foo@R_PPC64_PLT16_HA
|
||||
// 2. ld 12,foo@R_PPC64_PLT16_LO_DS(Rx)
|
||||
// 3. mtctr 12 ; foo@R_PPC64_PLTSEQ
|
||||
// 4. bctrl ; foo@R_PPC64_PLTCALL
|
||||
// 5. ld r2,24(r1)
|
||||
//
|
||||
// Note, 5 is required to follow the R_PPC64_PLTCALL. Similarly, relocations targeting
|
||||
// instructions 3 and 4 are zero sized informational relocations.
|
||||
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_PLT16_HA),
|
||||
objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_PLT16_LO_DS):
|
||||
su := ldr.MakeSymbolUpdater(s)
|
||||
isPLT16_LO_DS := r.Type() == objabi.ElfRelocOffset+objabi.RelocType(elf.R_PPC64_PLT16_LO_DS)
|
||||
if isPLT16_LO_DS {
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_DS)
|
||||
} else {
|
||||
ldr.SetRelocVariant(s, rIdx, sym.RV_POWER_HA|sym.RV_CHECK_OVERFLOW)
|
||||
}
|
||||
su.SetRelocType(rIdx, objabi.R_POWER_TOC)
|
||||
if targType == sym.SDYNIMPORT {
|
||||
// This is an external symbol, make space in the GOT and retarget the reloc.
|
||||
ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_PPC64_GLOB_DAT))
|
||||
su.SetRelocSym(rIdx, syms.GOT)
|
||||
su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
|
||||
} else if targType == sym.STEXT {
|
||||
// This is the half-way solution to transforming a PLT sequence into nops + bl targ
|
||||
// We turn it into an indirect call by transforming step 2 into an addi.
|
||||
// Fixing up the whole sequence is a bit more involved.
|
||||
if isPLT16_LO_DS {
|
||||
const MASK_OP_LD = 63<<26 | 0x3
|
||||
const OP_LD = 58 << 26
|
||||
const OP_ADDI = 14 << 26
|
||||
op := target.Arch.ByteOrder.Uint32(su.Data()[r.Off():])
|
||||
if op&MASK_OP_LD != OP_LD {
|
||||
ldr.Errorf(s, "relocation R_PPC64_PLT16_LO_DS expected an ld opcode. Found non-ld opcode %08X.", op)
|
||||
}
|
||||
op = (op &^ MASK_OP_LD) | OP_ADDI
|
||||
su.MakeWritable()
|
||||
su.SetUint32(target.Arch, int64(r.Off()), op)
|
||||
}
|
||||
} else {
|
||||
ldr.Errorf(s, "unexpected PLT relocation target symbol type %s", targType.String())
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
|
|
Loading…
Reference in a new issue