cmd/6l, cmd/internal/ld: handle R_PCREL to function in other shared library

An ELF linker handles a PC-relative reference to an STT_FUNC defined in a
shared library by building a PLT entry and referring to that, so do the
same in 6l.

Fixes #10690

Change-Id: I061a96fd4400d957e301d0ac86760ce256910e1d
Reviewed-on: https://go-review.googlesource.com/9711
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/src/cmd/6l/asm.go b/src/cmd/6l/asm.go
index deaeb82..4df8ac7 100644
--- a/src/cmd/6l/asm.go
+++ b/src/cmd/6l/asm.go
@@ -33,6 +33,7 @@
 import (
 	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"debug/elf"
 	"fmt"
 	"log"
 )
@@ -381,7 +382,11 @@
 
 	case obj.R_PCREL:
 		if r.Siz == 4 {
-			ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
+			if r.Xsym.Type == obj.SDYNIMPORT && r.Xsym.ElfType == elf.STT_FUNC {
+				ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32)
+			} else {
+				ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
+			}
 		} else {
 			return -1
 		}
diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go
index cdf2dca..184175e 100644
--- a/src/cmd/internal/ld/lib.go
+++ b/src/cmd/internal/ld/lib.go
@@ -1197,6 +1197,7 @@
 				s.Name, shlib, lsym.File)
 		}
 		lsym.Type = obj.SDYNIMPORT
+		lsym.ElfType = elf.ST_TYPE(s.Info)
 		lsym.File = libpath
 		if strings.HasPrefix(lsym.Name, "type.") {
 			data := make([]byte, s.Size)
diff --git a/src/cmd/internal/ld/link.go b/src/cmd/internal/ld/link.go
index 52390e7..03da52a 100644
--- a/src/cmd/internal/ld/link.go
+++ b/src/cmd/internal/ld/link.go
@@ -32,26 +32,31 @@
 
 import (
 	"cmd/internal/obj"
+	"debug/elf"
 	"encoding/binary"
 )
 
 type LSym struct {
-	Name        string
-	Extname     string
-	Type        int16
-	Version     int16
-	Dupok       uint8
-	Cfunc       uint8
-	External    uint8
-	Nosplit     uint8
-	Reachable   bool
-	Cgoexport   uint8
-	Special     uint8
-	Stkcheck    uint8
-	Hide        uint8
-	Leaf        uint8
-	Localentry  uint8
-	Onlist      uint8
+	Name       string
+	Extname    string
+	Type       int16
+	Version    int16
+	Dupok      uint8
+	Cfunc      uint8
+	External   uint8
+	Nosplit    uint8
+	Reachable  bool
+	Cgoexport  uint8
+	Special    uint8
+	Stkcheck   uint8
+	Hide       uint8
+	Leaf       uint8
+	Localentry uint8
+	Onlist     uint8
+	// ElfType is set for symbols read from shared libraries by ldshlibsyms. It
+	// is not set for symbols defined by the packages being linked or by symbols
+	// read by ldelf (and so is left as elf.STT_NOTYPE).
+	ElfType     elf.SymType
 	Dynid       int32
 	Plt         int32
 	Got         int32
diff --git a/src/cmd/internal/ld/symtab.go b/src/cmd/internal/ld/symtab.go
index 31baba0..d6e79dc 100644
--- a/src/cmd/internal/ld/symtab.go
+++ b/src/cmd/internal/ld/symtab.go
@@ -106,10 +106,9 @@
 		type_ = STT_OBJECT
 
 	case 'U':
-		type_ = STT_NOTYPE
-		if x == Ctxt.Tlsg {
-			type_ = STT_TLS
-		}
+		// ElfType is only set for symbols read from Go shared libraries, but
+		// for other symbols it is left as STT_NOTYPE which is fine.
+		type_ = int(x.ElfType)
 
 	case 't':
 		type_ = STT_TLS