From ff5cf4ced3f1681ec972cd954d4b476f87616fe3 Mon Sep 17 00:00:00 2001 From: YunQiang Su Date: Sat, 20 Jun 2020 14:04:54 +0000 Subject: [PATCH] cmd/link,debug/elf: mips32, add .gnu.attributes and .MIPS.abiflags sections MIPS32 uses .gnu.attributes and .MIPS.abiflags sections to mark FP ABI the object is using, and the kernel will set the correct FP mode for it. Currrently Go doesn't generate these 2 sections. If we link object without these 2 sections togather FPXX objects, the result will be FPXX, which is wrong: FP32 + FPXX -> FP32 FPXX + FP64 -> FP64 FP32 + FP64 -> reject These 2 sections is also needed to support FPXX and FP64 in future. More details about FP32/FPXX/FP64 are explained in: https://web.archive.org/web/20180828210612/https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking Fixes #39677 Change-Id: Ia34e7461dee38a4f575dd8ace609988744512ac1 Reviewed-on: https://go-review.googlesource.com/c/go/+/239217 Run-TryBot: Cherry Zhang Reviewed-by: Cherry Zhang TryBot-Result: Go Bot Trust: Meng Zhuo --- src/cmd/link/internal/ld/elf.go | 145 ++++++++++++++++++++++++++++++++ src/debug/elf/elf.go | 2 + 2 files changed, 147 insertions(+) diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 37b2dc640d..d3e598b312 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -519,6 +519,90 @@ func elfwriteinterp(out *OutBuf) int { return int(sh.Size) } +// member of .gnu.attributes of MIPS for fpAbi +const ( + // No floating point is present in the module (default) + MIPS_FPABI_NONE = 0 + // FP code in the module uses the FP32 ABI for a 32-bit ABI + MIPS_FPABI_ANY = 1 + // FP code in the module only uses single precision ABI + MIPS_FPABI_SINGLE = 2 + // FP code in the module uses soft-float ABI + MIPS_FPABI_SOFT = 3 + // FP code in the module assumes an FPU with FR=1 and has 12 + // callee-saved doubles. Historic, no longer supported. + MIPS_FPABI_HIST = 4 + // FP code in the module uses the FPXX ABI + MIPS_FPABI_FPXX = 5 + // FP code in the module uses the FP64 ABI + MIPS_FPABI_FP64 = 6 + // FP code in the module uses the FP64A ABI + MIPS_FPABI_FP64A = 7 +) + +func elfMipsAbiFlags(sh *ElfShdr, startva uint64, resoff uint64) int { + n := 24 + sh.Addr = startva + resoff - uint64(n) + sh.Off = resoff - uint64(n) + sh.Size = uint64(n) + sh.Type = uint32(elf.SHT_MIPS_ABIFLAGS) + sh.Flags = uint64(elf.SHF_ALLOC) + + return n +} + +//typedef struct +//{ +// /* Version of flags structure. */ +// uint16_t version; +// /* The level of the ISA: 1-5, 32, 64. */ +// uint8_t isa_level; +// /* The revision of ISA: 0 for MIPS V and below, 1-n otherwise. */ +// uint8_t isa_rev; +// /* The size of general purpose registers. */ +// uint8_t gpr_size; +// /* The size of co-processor 1 registers. */ +// uint8_t cpr1_size; +// /* The size of co-processor 2 registers. */ +// uint8_t cpr2_size; +// /* The floating-point ABI. */ +// uint8_t fp_abi; +// /* Processor-specific extension. */ +// uint32_t isa_ext; +// /* Mask of ASEs used. */ +// uint32_t ases; +// /* Mask of general flags. */ +// uint32_t flags1; +// uint32_t flags2; +//} Elf_Internal_ABIFlags_v0; +func elfWriteMipsAbiFlags(ctxt *Link) int { + sh := elfshname(".MIPS.abiflags") + ctxt.Out.SeekSet(int64(sh.Off)) + ctxt.Out.Write16(0) // version + ctxt.Out.Write8(32) // isaLevel + ctxt.Out.Write8(1) // isaRev + ctxt.Out.Write8(1) // gprSize + ctxt.Out.Write8(1) // cpr1Size + ctxt.Out.Write8(0) // cpr2Size + if objabi.GOMIPS == "softfloat" { + ctxt.Out.Write8(MIPS_FPABI_SOFT) // fpAbi + } else { + // Go cannot make sure non odd-number-fpr is used (ie, in load a double from memory). + // So, we mark the object is MIPS I style paired float/double register scheme, + // aka MIPS_FPABI_ANY. If we mark the object as FPXX, the kernel may use FR=1 mode, + // then we meet some problem. + // Note: MIPS_FPABI_ANY is bad naming: in fact it is MIPS I style FPR usage. + // It is not for 'ANY'. + // TODO: switch to FPXX after be sure that no odd-number-fpr is used. + ctxt.Out.Write8(MIPS_FPABI_ANY) // fpAbi + } + ctxt.Out.Write32(0) // isaExt + ctxt.Out.Write32(0) // ases + ctxt.Out.Write32(0) // flags1 + ctxt.Out.Write32(0) // flags2 + return int(sh.Size) +} + func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int { n := 3*4 + uint64(sz) + resoff%4 @@ -1204,6 +1288,10 @@ func (ctxt *Link) doelf() { shstrtab.Addstring(".noptrbss") shstrtab.Addstring("__libfuzzer_extra_counters") shstrtab.Addstring(".go.buildinfo") + if ctxt.IsMIPS() { + shstrtab.Addstring(".MIPS.abiflags") + shstrtab.Addstring(".gnu.attributes") + } // generate .tbss section for dynamic internal linker or external // linking, so that various binutils could correctly calculate @@ -1254,6 +1342,10 @@ func (ctxt *Link) doelf() { shstrtab.Addstring(elfRelType + ".data.rel.ro") } shstrtab.Addstring(elfRelType + ".go.buildinfo") + if ctxt.IsMIPS() { + shstrtab.Addstring(elfRelType + ".MIPS.abiflags") + shstrtab.Addstring(elfRelType + ".gnu.attributes") + } // add a .note.GNU-stack section to mark the stack as non-executable shstrtab.Addstring(".note.GNU-stack") @@ -1445,6 +1537,36 @@ func (ctxt *Link) doelf() { if ctxt.LinkMode == LinkExternal && *flagBuildid != "" { addgonote(ctxt, ".note.go.buildid", ELF_NOTE_GOBUILDID_TAG, []byte(*flagBuildid)) } + + + //type mipsGnuAttributes struct { + // version uint8 // 'A' + // length uint32 // 15 including itself + // gnu [4]byte // "gnu\0" + // tag uint8 // 1:file, 2: section, 3: symbol, 1 here + // taglen uint32 // tag length, including tag, 7 here + // tagfp uint8 // 4 + // fpAbi uint8 // see .MIPS.abiflags + //} + if ctxt.IsMIPS() { + gnuattributes := ldr.CreateSymForUpdate(".gnu.attributes", 0) + gnuattributes.SetType(sym.SELFROSECT) + gnuattributes.SetReachable(true) + gnuattributes.AddUint8('A') // version 'A' + gnuattributes.AddUint32(ctxt.Arch, 15) // length 15 including itself + gnuattributes.AddBytes([]byte("gnu\x00")) // "gnu\0" + gnuattributes.AddUint8(1) // 1:file, 2: section, 3: symbol, 1 here + gnuattributes.AddUint32(ctxt.Arch, 7) // tag length, including tag, 7 here + gnuattributes.AddUint8(4) // 4 for FP, 8 for MSA + if objabi.GOMIPS == "softfloat" { + gnuattributes.AddUint8(MIPS_FPABI_SOFT) + } else { + // Note: MIPS_FPABI_ANY is bad naming: in fact it is MIPS I style FPR usage. + // It is not for 'ANY'. + // TODO: switch to FPXX after be sure that no odd-number-fpr is used. + gnuattributes.AddUint8(MIPS_FPABI_ANY) + } + } } // Do not write DT_NULL. elfdynhash will finish it. @@ -1910,6 +2032,25 @@ elfobj: shsym(sh, ldr, ldr.Lookup(".shstrtab", 0)) eh.Shstrndx = uint16(sh.shnum) + if ctxt.IsMIPS() { + sh = elfshname(".MIPS.abiflags") + sh.Type = uint32(elf.SHT_MIPS_ABIFLAGS) + sh.Flags = uint64(elf.SHF_ALLOC) + sh.Addralign = 8 + resoff -= int64(elfMipsAbiFlags(sh, uint64(startva), uint64(resoff))) + + ph := newElfPhdr() + ph.Type = elf.PT_MIPS_ABIFLAGS + ph.Flags = elf.PF_R + phsh(ph, sh) + + sh = elfshname(".gnu.attributes") + sh.Type = uint32(elf.SHT_GNU_ATTRIBUTES) + sh.Addralign = 1 + ldr := ctxt.loader + shsym(sh, ldr, ldr.Lookup(".gnu.attributes", 0)) + } + // put these sections early in the list if !*FlagS { elfshname(".symtab") @@ -2029,6 +2170,10 @@ elfobj: if !*FlagD { a += int64(elfwriteinterp(ctxt.Out)) } + if ctxt.IsMIPS() { + a += int64(elfWriteMipsAbiFlags(ctxt)) + } + if ctxt.LinkMode != LinkExternal { if ctxt.HeadType == objabi.Hnetbsd { a += int64(elfwritenetbsdsig(ctxt.Out)) diff --git a/src/debug/elf/elf.go b/src/debug/elf/elf.go index 2b777eabac..b04d874019 100644 --- a/src/debug/elf/elf.go +++ b/src/debug/elf/elf.go @@ -644,6 +644,7 @@ const ( SHT_GNU_VERSYM SectionType = 0x6fffffff /* GNU version symbol table */ SHT_HIOS SectionType = 0x6fffffff /* Last of OS specific semantics */ SHT_LOPROC SectionType = 0x70000000 /* reserved range for processor */ + SHT_MIPS_ABIFLAGS SectionType = 0x7000002a /* .MIPS.abiflags */ SHT_HIPROC SectionType = 0x7fffffff /* specific section header types */ SHT_LOUSER SectionType = 0x80000000 /* reserved range for application */ SHT_HIUSER SectionType = 0xffffffff /* specific indexes */ @@ -675,6 +676,7 @@ var shtStrings = []intName{ {0x6ffffffe, "SHT_GNU_VERNEED"}, {0x6fffffff, "SHT_GNU_VERSYM"}, {0x70000000, "SHT_LOPROC"}, + {0x7000002a, "SHT_MIPS_ABIFLAGS"}, {0x7fffffff, "SHT_HIPROC"}, {0x80000000, "SHT_LOUSER"}, {0xffffffff, "SHT_HIUSER"},