diff options
author | Meng Zhuo <mengzhuo1203@gmail.com> | 2019-12-06 16:13:44 +0800 |
---|---|---|
committer | Cherry Zhang <cherryyz@google.com> | 2019-12-09 18:22:59 +0000 |
commit | ffa5c85c9227a212fe1a91a6d54da56a9e754f1f (patch) | |
tree | ed4a0e3b03f8e5cc749c324ef50f7c7cdda24513 | |
parent | a3a630b0d2829ab74ac623fc2ae92864bd61d391 (diff) | |
download | go-ffa5c85c9227a212fe1a91a6d54da56a9e754f1f.tar.gz go-ffa5c85c9227a212fe1a91a6d54da56a9e754f1f.zip |
cmd/link: fix loadelf failed on MIPS family
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>
-rw-r--r-- | src/cmd/link/elf_test.go | 7 | ||||
-rw-r--r-- | src/cmd/link/internal/loadelf/ldelf.go | 65 |
2 files changed, 48 insertions, 24 deletions
diff --git a/src/cmd/link/elf_test.go b/src/cmd/link/elf_test.go index 11a7730796..39fb9df0be 100644 --- a/src/cmd/link/elf_test.go +++ b/src/cmd/link/elf_test.go @@ -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) diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go index 60bebab818..1962d76338 100644 --- a/src/cmd/link/internal/loadelf/ldelf.go +++ b/src/cmd/link/internal/loadelf/ldelf.go @@ -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 |