Commit d2765de8 authored by erifan01's avatar erifan01 Committed by Cherry Zhang

cmd/link: support PIE mode with internal link on linux arm64

This CL improves internal link to provide basic support for cgo and PIE:
1, add support for GOT, PLT and GOTPLT.
2, add support for following ELF relocation types which have been used by std
   packages:
     R_AARCH64_ADR_GOT_PAGE
     R_AARCH64_LD64_GOT_LO12_NC
     R_AARCH64_ADR_PREL_PG_HI21
     R_AARCH64_ADD_ABS_LO12_NC
     R_AARCH64_LDST8_ABS_LO12_NC
     R_AARCH64_LDST32_ABS_LO12_NC
     R_AARCH64_LDST64_ABS_LO12_NC
     R_AARCH64_JUMP26
     R_AARCH64_ABS64
     R_AARCH64_PREL32
     R_AARCH64_PREL64

With this change, Go toolchain can be built in internal linking mode, and
pure Go programs can be built with PIE mode in internal linking mode on arm64.

Updates #10373
The prototype of this CL is contributed by Wei Xiao <wei.xiao@arm.com>

Change-Id: I2253923c69e855fd1524d54def309a961dce6247
Reviewed-on: https://go-review.googlesource.com/c/go/+/163579Reviewed-by: default avatarCherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
parent d2c12634
......@@ -569,7 +569,7 @@ func (t *tester) registerTests() {
}
// Test internal linking of PIE binaries where it is supported.
if goos == "linux" && goarch == "amd64" {
if goos == "linux" && (goarch == "amd64" || goarch == "arm64") {
t.tests = append(t.tests, distTest{
name: "pie_internal",
heading: "internal linking of -buildmode=pie",
......@@ -910,7 +910,7 @@ func (t *tester) internalLink() bool {
// Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/10373
// https://golang.org/issue/14449
if goarch == "arm64" || goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" {
if goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" {
return false
}
if goos == "aix" {
......@@ -1030,7 +1030,7 @@ func (t *tester) cgoTest(dt *distTest) error {
"dragonfly-amd64",
"freebsd-386", "freebsd-amd64", "freebsd-arm",
"linux-386", "linux-amd64", "linux-arm", "linux-ppc64le", "linux-s390x",
"netbsd-386", "netbsd-amd64":
"netbsd-386", "netbsd-amd64", "linux-arm64":
cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=external")
......
......@@ -132,6 +132,23 @@ const (
// slot of the referenced symbol.
R_ARM64_GOTPCREL
// R_ARM64_GOT resolves a GOT-relative instruction sequence, usually an adrp
// followed by another ld instruction.
R_ARM64_GOT
// R_ARM64_PCREL resolves a PC-relative addresses instruction sequence, usually an
// adrp followed by another add instruction.
R_ARM64_PCREL
// R_ARM64_LDST8 sets a LD/ST immediate value to bits [11:0] of a local address.
R_ARM64_LDST8
// R_ARM64_LDST32 sets a LD/ST immediate value to bits [11:2] of a local address.
R_ARM64_LDST32
// R_ARM64_LDST64 sets a LD/ST immediate value to bits [11:3] of a local address.
R_ARM64_LDST64
// PPC64.
// R_POWER_TLS_LE is used to implement the "local exec" model for tls
......
// Code generated by "stringer -type=RelocType"; DO NOT EDIT.
// Code generated by "stringer -type RelocType"; DO NOT EDIT.
package objabi
import "strconv"
const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORT"
const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST32R_ARM64_LDST64R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 251, 265, 279, 293, 309, 323, 337, 348, 362, 377, 394, 412, 433, 443, 454, 467, 478, 490}
var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 251, 265, 279, 293, 309, 320, 333, 346, 360, 374, 388, 402, 413, 427, 442, 459, 477, 498, 508, 519, 532, 543, 555, 565}
func (i RelocType) String() string {
i -= 1
......
This diff is collapsed.
......@@ -184,17 +184,16 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
}
// Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/10373
// https://golang.org/issue/14449
// https://golang.org/issue/21961
if iscgo && ctxt.Arch.InFamily(sys.ARM64, sys.MIPS64, sys.MIPS, sys.PPC64) {
if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.PPC64) {
return true, objabi.GOARCH + " does not support internal cgo"
}
// When the race flag is set, the LLVM tsan relocatable file is linked
// into the final binary, which means external linking is required because
// internal linking does not support it.
if *flagRace && ctxt.Arch.InFamily(sys.PPC64, sys.ARM64) {
if *flagRace && ctxt.Arch.InFamily(sys.PPC64) {
return true, "race on " + objabi.GOARCH
}
......@@ -206,7 +205,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
return true, "buildmode=c-shared"
case BuildModePIE:
switch objabi.GOOS + "/" + objabi.GOARCH {
case "linux/amd64":
case "linux/amd64", "linux/arm64":
default:
// Internal linking does not support TLS_IE.
return true, "buildmode=pie"
......
......@@ -2492,7 +2492,7 @@ func (ctxt *Link) callgraph() {
if r.Sym == nil {
continue
}
if (r.Type == objabi.R_CALL || r.Type == objabi.R_CALLARM || r.Type == objabi.R_CALLPOWER || r.Type == objabi.R_CALLMIPS) && r.Sym.Type == sym.STEXT {
if (r.Type == objabi.R_CALL || r.Type == objabi.R_CALLARM || r.Type == objabi.R_CALLARM64 || r.Type == objabi.R_CALLPOWER || r.Type == objabi.R_CALLMIPS) && r.Sym.Type == sym.STEXT {
ctxt.Logf("%s calls %s\n", s.Name, r.Sym.Name)
}
}
......
......@@ -794,6 +794,13 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
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
continue
}
if strings.HasPrefix(elfsym.name, ".LASF") { // gcc on s390x does this
continue
}
......@@ -1064,8 +1071,8 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym
}
case ElfSymBindLocal:
if arch.Family == sys.ARM && (strings.HasPrefix(elfsym.name, "$a") || strings.HasPrefix(elfsym.name, "$d")) {
// binutils for arm generate these mapping
if (arch.Family == sys.ARM || arch.Family == sys.ARM64) && (strings.HasPrefix(elfsym.name, "$a") || strings.HasPrefix(elfsym.name, "$d") || strings.HasPrefix(elfsym.name, "$x")) {
// binutils for arm and arm64 generate these mapping
// symbols, ignore these
break
}
......@@ -1127,81 +1134,94 @@ func relSize(arch *sys.Arch, pn string, elftype uint32) (uint8, error) {
const (
AMD64 = uint32(sys.AMD64)
ARM = uint32(sys.ARM)
ARM64 = uint32(sys.ARM64)
I386 = uint32(sys.I386)
PPC64 = uint32(sys.PPC64)
S390X = uint32(sys.S390X)
)
switch uint32(arch.Family) | elftype<<24 {
switch uint32(arch.Family) | elftype<<16 {
default:
return 0, fmt.Errorf("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype)
case S390X | uint32(elf.R_390_8)<<24:
case S390X | uint32(elf.R_390_8)<<16:
return 1, nil
case PPC64 | uint32(elf.R_PPC64_TOC16)<<24,
PPC64 | uint32(elf.R_PPC64_TOC16_LO)<<24,
PPC64 | uint32(elf.R_PPC64_TOC16_HI)<<24,
PPC64 | uint32(elf.R_PPC64_TOC16_HA)<<24,
PPC64 | uint32(elf.R_PPC64_TOC16_DS)<<24,
PPC64 | uint32(elf.R_PPC64_TOC16_LO_DS)<<24,
PPC64 | uint32(elf.R_PPC64_REL16_LO)<<24,
PPC64 | uint32(elf.R_PPC64_REL16_HI)<<24,
PPC64 | uint32(elf.R_PPC64_REL16_HA)<<24,
S390X | uint32(elf.R_390_16)<<24,
S390X | uint32(elf.R_390_GOT16)<<24,
S390X | uint32(elf.R_390_PC16)<<24,
S390X | uint32(elf.R_390_PC16DBL)<<24,
S390X | uint32(elf.R_390_PLT16DBL)<<24:
case PPC64 | uint32(elf.R_PPC64_TOC16)<<16,
PPC64 | uint32(elf.R_PPC64_TOC16_LO)<<16,
PPC64 | uint32(elf.R_PPC64_TOC16_HI)<<16,
PPC64 | uint32(elf.R_PPC64_TOC16_HA)<<16,
PPC64 | uint32(elf.R_PPC64_TOC16_DS)<<16,
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,
S390X | uint32(elf.R_390_16)<<16,
S390X | uint32(elf.R_390_GOT16)<<16,
S390X | uint32(elf.R_390_PC16)<<16,
S390X | uint32(elf.R_390_PC16DBL)<<16,
S390X | uint32(elf.R_390_PLT16DBL)<<16:
return 2, nil
case ARM | uint32(elf.R_ARM_ABS32)<<24,
ARM | uint32(elf.R_ARM_GOT32)<<24,
ARM | uint32(elf.R_ARM_PLT32)<<24,
ARM | uint32(elf.R_ARM_GOTOFF)<<24,
ARM | uint32(elf.R_ARM_GOTPC)<<24,
ARM | uint32(elf.R_ARM_THM_PC22)<<24,
ARM | uint32(elf.R_ARM_REL32)<<24,
ARM | uint32(elf.R_ARM_CALL)<<24,
ARM | uint32(elf.R_ARM_V4BX)<<24,
ARM | uint32(elf.R_ARM_GOT_PREL)<<24,
ARM | uint32(elf.R_ARM_PC24)<<24,
ARM | uint32(elf.R_ARM_JUMP24)<<24,
AMD64 | uint32(elf.R_X86_64_PC32)<<24,
AMD64 | uint32(elf.R_X86_64_PLT32)<<24,
AMD64 | uint32(elf.R_X86_64_GOTPCREL)<<24,
AMD64 | uint32(elf.R_X86_64_GOTPCRELX)<<24,
AMD64 | uint32(elf.R_X86_64_REX_GOTPCRELX)<<24,
I386 | uint32(elf.R_386_32)<<24,
I386 | uint32(elf.R_386_PC32)<<24,
I386 | uint32(elf.R_386_GOT32)<<24,
I386 | uint32(elf.R_386_PLT32)<<24,
I386 | uint32(elf.R_386_GOTOFF)<<24,
I386 | uint32(elf.R_386_GOTPC)<<24,
I386 | uint32(elf.R_386_GOT32X)<<24,
PPC64 | uint32(elf.R_PPC64_REL24)<<24,
PPC64 | uint32(elf.R_PPC_REL32)<<24,
S390X | uint32(elf.R_390_32)<<24,
S390X | uint32(elf.R_390_PC32)<<24,
S390X | uint32(elf.R_390_GOT32)<<24,
S390X | uint32(elf.R_390_PLT32)<<24,
S390X | uint32(elf.R_390_PC32DBL)<<24,
S390X | uint32(elf.R_390_PLT32DBL)<<24,
S390X | uint32(elf.R_390_GOTPCDBL)<<24,
S390X | uint32(elf.R_390_GOTENT)<<24:
case ARM | uint32(elf.R_ARM_ABS32)<<16,
ARM | uint32(elf.R_ARM_GOT32)<<16,
ARM | uint32(elf.R_ARM_PLT32)<<16,
ARM | uint32(elf.R_ARM_GOTOFF)<<16,
ARM | uint32(elf.R_ARM_GOTPC)<<16,
ARM | uint32(elf.R_ARM_THM_PC22)<<16,
ARM | uint32(elf.R_ARM_REL32)<<16,
ARM | uint32(elf.R_ARM_CALL)<<16,
ARM | uint32(elf.R_ARM_V4BX)<<16,
ARM | uint32(elf.R_ARM_GOT_PREL)<<16,
ARM | uint32(elf.R_ARM_PC24)<<16,
ARM | uint32(elf.R_ARM_JUMP24)<<16,
ARM64 | uint32(elf.R_AARCH64_CALL26)<<16,
ARM64 | uint32(elf.R_AARCH64_ADR_GOT_PAGE)<<16,
ARM64 | uint32(elf.R_AARCH64_LD64_GOT_LO12_NC)<<16,
ARM64 | uint32(elf.R_AARCH64_ADR_PREL_PG_HI21)<<16,
ARM64 | uint32(elf.R_AARCH64_ADD_ABS_LO12_NC)<<16,
ARM64 | uint32(elf.R_AARCH64_LDST8_ABS_LO12_NC)<<16,
ARM64 | uint32(elf.R_AARCH64_LDST32_ABS_LO12_NC)<<16,
ARM64 | uint32(elf.R_AARCH64_LDST64_ABS_LO12_NC)<<16,
ARM64 | uint32(elf.R_AARCH64_PREL32)<<16,
ARM64 | uint32(elf.R_AARCH64_JUMP26)<<16,
AMD64 | uint32(elf.R_X86_64_PC32)<<16,
AMD64 | uint32(elf.R_X86_64_PLT32)<<16,
AMD64 | uint32(elf.R_X86_64_GOTPCREL)<<16,
AMD64 | uint32(elf.R_X86_64_GOTPCRELX)<<16,
AMD64 | uint32(elf.R_X86_64_REX_GOTPCRELX)<<16,
I386 | uint32(elf.R_386_32)<<16,
I386 | uint32(elf.R_386_PC32)<<16,
I386 | uint32(elf.R_386_GOT32)<<16,
I386 | uint32(elf.R_386_PLT32)<<16,
I386 | uint32(elf.R_386_GOTOFF)<<16,
I386 | uint32(elf.R_386_GOTPC)<<16,
I386 | uint32(elf.R_386_GOT32X)<<16,
PPC64 | uint32(elf.R_PPC64_REL24)<<16,
PPC64 | uint32(elf.R_PPC_REL32)<<16,
S390X | uint32(elf.R_390_32)<<16,
S390X | uint32(elf.R_390_PC32)<<16,
S390X | uint32(elf.R_390_GOT32)<<16,
S390X | uint32(elf.R_390_PLT32)<<16,
S390X | uint32(elf.R_390_PC32DBL)<<16,
S390X | uint32(elf.R_390_PLT32DBL)<<16,
S390X | uint32(elf.R_390_GOTPCDBL)<<16,
S390X | uint32(elf.R_390_GOTENT)<<16:
return 4, nil
case AMD64 | uint32(elf.R_X86_64_64)<<24,
AMD64 | uint32(elf.R_X86_64_PC64)<<24,
PPC64 | uint32(elf.R_PPC64_ADDR64)<<24,
S390X | uint32(elf.R_390_GLOB_DAT)<<24,
S390X | uint32(elf.R_390_RELATIVE)<<24,
S390X | uint32(elf.R_390_GOTOFF)<<24,
S390X | uint32(elf.R_390_GOTPC)<<24,
S390X | uint32(elf.R_390_64)<<24,
S390X | uint32(elf.R_390_PC64)<<24,
S390X | uint32(elf.R_390_GOT64)<<24,
S390X | uint32(elf.R_390_PLT64)<<24:
case AMD64 | uint32(elf.R_X86_64_64)<<16,
AMD64 | uint32(elf.R_X86_64_PC64)<<16,
ARM64 | uint32(elf.R_AARCH64_ABS64)<<16,
ARM64 | uint32(elf.R_AARCH64_PREL64)<<16,
PPC64 | uint32(elf.R_PPC64_ADDR64)<<16,
S390X | uint32(elf.R_390_GLOB_DAT)<<16,
S390X | uint32(elf.R_390_RELATIVE)<<16,
S390X | uint32(elf.R_390_GOTOFF)<<16,
S390X | uint32(elf.R_390_GOTPC)<<16,
S390X | uint32(elf.R_390_64)<<16,
S390X | uint32(elf.R_390_PC64)<<16,
S390X | uint32(elf.R_390_GOT64)<<16,
S390X | uint32(elf.R_390_PLT64)<<16:
return 8, nil
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment