1
0
mirror of https://github.com/golang/go synced 2024-11-26 04:07:59 -07:00

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 <cherryyz@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Meng Zhuo <mzh@golangcn.org>
This commit is contained in:
YunQiang Su 2020-06-20 14:04:54 +00:00 committed by Cherry Zhang
parent 700b73975e
commit ff5cf4ced3
2 changed files with 147 additions and 0 deletions

View File

@ -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))

View File

@ -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"},