]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: fix loadelf failed on MIPS family
authorMeng Zhuo <mengzhuo1203@gmail.com>
Fri, 6 Dec 2019 08:13:44 +0000 (16:13 +0800)
committerCherry Zhang <cherryyz@google.com>
Mon, 9 Dec 2019 18:22:59 +0000 (18:22 +0000)
The relocation of MIPS64 family ELF is different with other architecure according
to the document from Linux-MIPS

https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf

In "2.9 Relocation" it shows relocation section contains five parts:

1. r_sym Elf64_Word Symbol index
2. r_ssym Elf64_Byte Special symbol
3. r_type3 Elf64_Byte Relocation type
4. r_type2 Elf64_Byte Relocation type
5. r_type Elf64_Byte Relocation type

This CL makes loadelf aware the difference.

Update #35779

Change-Id: Ib221665641972b1c2bfea5a496e3118e5dc0bc45
Reviewed-on: https://go-review.googlesource.com/c/go/+/209317
Run-TryBot: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/link/elf_test.go
src/cmd/link/internal/loadelf/ldelf.go

index 11a7730796bd33ea3d4b875232d26224cf80702a..39fb9df0be660b20ea040fd4a6bc3c9cb3f3a098 100644 (file)
@@ -15,7 +15,6 @@ import (
        "os"
        "os/exec"
        "path/filepath"
-       "runtime"
        "strings"
        "sync"
        "testing"
@@ -143,12 +142,6 @@ func TestMinusRSymsWithSameName(t *testing.T) {
        testenv.MustHaveCGO(t)
        t.Parallel()
 
-       // Skip this test on MIPS for the time being since it seems to trigger
-       // problems with unknown relocations.
-       if strings.Contains(runtime.GOARCH, "mips") {
-               testenv.SkipFlaky(t, 35779)
-       }
-
        dir, err := ioutil.TempDir("", "go-link-TestMinusRSymsWithSameName")
        if err != nil {
                t.Fatal(err)
index 60bebab8180b49a99d4660725b5a2a1773ef4454..1962d76338f8c08321b785f342e9993c7d6e24a7 100644 (file)
@@ -904,14 +904,26 @@ func load(arch *sys.Arch, localSymVersion int, newSym, lookup lookupFunc, f *bio
                p := rsect.base
                for j := 0; j < n; j++ {
                        var add uint64
+                       var symIdx int
+                       var relocType uint64
+
                        rp := &r[j]
-                       var info uint64
                        if is64 != 0 {
                                // 64-bit rel/rela
                                rp.Off = int32(e.Uint64(p))
 
                                p = p[8:]
-                               info = e.Uint64(p)
+                               switch arch.Family {
+                               case sys.MIPS64:
+                                       // https://www.linux-mips.org/pub/linux/mips/doc/ABI/elf64-2.4.pdf
+                                       // The doc shows it's different with general Linux ELF
+                                       symIdx = int(e.Uint32(p))
+                                       relocType = uint64(p[7])
+                               default:
+                                       info := e.Uint64(p)
+                                       relocType = info & 0xffffffff
+                                       symIdx = int(info >> 32)
+                               }
                                p = p[8:]
                                if rela != 0 {
                                        add = e.Uint64(p)
@@ -922,8 +934,9 @@ func load(arch *sys.Arch, localSymVersion int, newSym, lookup lookupFunc, f *bio
                                rp.Off = int32(e.Uint32(p))
 
                                p = p[4:]
-                               info = uint64(e.Uint32(p))
-                               info = info>>8<<32 | info&0xff // convert to 64-bit info
+                               info := e.Uint32(p)
+                               relocType = uint64(info & 0xff)
+                               symIdx = int(info >> 8)
                                p = p[4:]
                                if rela != 0 {
                                        add = uint64(e.Uint32(p))
@@ -931,29 +944,29 @@ func load(arch *sys.Arch, localSymVersion int, newSym, lookup lookupFunc, f *bio
                                }
                        }
 
-                       if info&0xffffffff == 0 { // skip R_*_NONE relocation
+                       if relocType == 0 { // skip R_*_NONE relocation
                                j--
                                n--
                                continue
                        }
 
-                       if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol
+                       if symIdx == 0 { // absolute relocation, don't bother reading the null symbol
                                rp.Sym = nil
                        } else {
                                var elfsym ElfSym
-                               if err := readelfsym(newSym, lookup, arch, elfobj, int(info>>32), &elfsym, 0, 0); err != nil {
+                               if err := readelfsym(newSym, lookup, arch, elfobj, symIdx, &elfsym, 0, 0); err != nil {
                                        return errorf("malformed elf file: %v", err)
                                }
-                               elfsym.sym = symbols[info>>32]
+                               elfsym.sym = symbols[symIdx]
                                if elfsym.sym == nil {
-                                       return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, int(info>>32), elfsym.name, elfsym.shndx, elfsym.type_)
+                                       return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, symIdx, elfsym.name, elfsym.shndx, elfsym.type_)
                                }
 
                                rp.Sym = elfsym.sym
                        }
 
-                       rp.Type = objabi.ElfRelocOffset + objabi.RelocType(info)
-                       rp.Siz, err = relSize(arch, pn, uint32(info))
+                       rp.Type = objabi.ElfRelocOffset + objabi.RelocType(relocType)
+                       rp.Siz, err = relSize(arch, pn, uint32(relocType))
                        if err != nil {
                                return nil, 0, err
                        }
@@ -1147,18 +1160,36 @@ func relSize(arch *sys.Arch, pn string, elftype uint32) (uint8, error) {
        // performance.
 
        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)
+               AMD64  = uint32(sys.AMD64)
+               ARM    = uint32(sys.ARM)
+               ARM64  = uint32(sys.ARM64)
+               I386   = uint32(sys.I386)
+               PPC64  = uint32(sys.PPC64)
+               S390X  = uint32(sys.S390X)
+               MIPS   = uint32(sys.MIPS)
+               MIPS64 = uint32(sys.MIPS64)
        )
 
        switch uint32(arch.Family) | elftype<<16 {
        default:
                return 0, fmt.Errorf("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype)
 
+       case MIPS | uint32(elf.R_MIPS_HI16)<<16,
+               MIPS | uint32(elf.R_MIPS_LO16)<<16,
+               MIPS | uint32(elf.R_MIPS_GOT16)<<16,
+               MIPS | uint32(elf.R_MIPS_GPREL16)<<16,
+               MIPS | uint32(elf.R_MIPS_GOT_PAGE)<<16,
+               MIPS | uint32(elf.R_MIPS_JALR)<<16,
+               MIPS | uint32(elf.R_MIPS_GOT_OFST)<<16,
+               MIPS64 | uint32(elf.R_MIPS_HI16)<<16,
+               MIPS64 | uint32(elf.R_MIPS_LO16)<<16,
+               MIPS64 | uint32(elf.R_MIPS_GOT16)<<16,
+               MIPS64 | uint32(elf.R_MIPS_GPREL16)<<16,
+               MIPS64 | uint32(elf.R_MIPS_GOT_PAGE)<<16,
+               MIPS64 | uint32(elf.R_MIPS_JALR)<<16,
+               MIPS64 | uint32(elf.R_MIPS_GOT_OFST)<<16:
+               return 4, nil
+
        case S390X | uint32(elf.R_390_8)<<16:
                return 1, nil