mirror of
https://github.com/golang/go
synced 2024-11-23 07:10:05 -07:00
cmd/link: fix malformed .shstrtab section
For ELF targets, the code in the go linker that generates the ".shstrtab" section was using a loader symbol to accumulate the contents of the section, then setting the section type to sym.SELFROSECT. This resulted in a section whose offset indicated that it fell into a loadable ELF segment, which is not how the .shstrtab is supposed to work (it should be outside of all loadable segments, similar to .strtab and .symtab). The peculiar .shstrtab caused confusion in third party tools that operate on ELF files, notably llvm-strip. This patch rewrites the .shstrtab generation code to avoid using a loader.Symbol and instead accumulate the contents of the section into a regular byte slice, then emit the section's data in the same way that .strtab is handled. Fixes #62600. Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest Change-Id: Ie54020d7b2d779d3ac9f5465fd505217d0681f79 Reviewed-on: https://go-review.googlesource.com/c/go/+/528036 Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
584aad5c57
commit
3251006291
@ -155,7 +155,7 @@ const (
|
||||
* marshal a 32-bit representation from the 64-bit structure.
|
||||
*/
|
||||
|
||||
var Elfstrdat []byte
|
||||
var elfstrdat, elfshstrdat []byte
|
||||
|
||||
/*
|
||||
* Total amount of space to reserve at the start of the file
|
||||
@ -1386,12 +1386,16 @@ func (ctxt *Link) doelf() {
|
||||
ldr := ctxt.loader
|
||||
|
||||
/* predefine strings we need for section headers */
|
||||
shstrtab := ldr.CreateSymForUpdate(".shstrtab", 0)
|
||||
|
||||
shstrtab.SetType(sym.SELFROSECT)
|
||||
addshstr := func(s string) int {
|
||||
off := len(elfshstrdat)
|
||||
elfshstrdat = append(elfshstrdat, s...)
|
||||
elfshstrdat = append(elfshstrdat, 0)
|
||||
return off
|
||||
}
|
||||
|
||||
shstrtabAddstring := func(s string) {
|
||||
off := shstrtab.Addstring(s)
|
||||
off := addshstr(s)
|
||||
elfsetstring(ctxt, 0, s, int(off))
|
||||
}
|
||||
|
||||
@ -1746,12 +1750,16 @@ func Asmbelfsetup() {
|
||||
|
||||
func asmbElf(ctxt *Link) {
|
||||
var symo int64
|
||||
if !*FlagS {
|
||||
symo = int64(Segdwarf.Fileoff + Segdwarf.Filelen)
|
||||
symo = Rnd(symo, int64(ctxt.Arch.PtrSize))
|
||||
ctxt.Out.SeekSet(symo)
|
||||
if *FlagS {
|
||||
ctxt.Out.Write(elfshstrdat)
|
||||
} else {
|
||||
ctxt.Out.SeekSet(symo)
|
||||
asmElfSym(ctxt)
|
||||
ctxt.Out.Write(Elfstrdat)
|
||||
ctxt.Out.Write(elfstrdat)
|
||||
ctxt.Out.Write(elfshstrdat)
|
||||
if ctxt.IsExternal() {
|
||||
elfEmitReloc(ctxt)
|
||||
}
|
||||
@ -2155,9 +2163,6 @@ func asmbElf(ctxt *Link) {
|
||||
|
||||
elfobj:
|
||||
sh := elfshname(".shstrtab")
|
||||
sh.Type = uint32(elf.SHT_STRTAB)
|
||||
sh.Addralign = 1
|
||||
shsym(sh, ldr, ldr.Lookup(".shstrtab", 0))
|
||||
eh.Shstrndx = uint16(sh.shnum)
|
||||
|
||||
if ctxt.IsMIPS() {
|
||||
@ -2184,6 +2189,7 @@ elfobj:
|
||||
elfshname(".symtab")
|
||||
elfshname(".strtab")
|
||||
}
|
||||
elfshname(".shstrtab")
|
||||
|
||||
for _, sect := range Segtext.Sections {
|
||||
elfshbits(ctxt.LinkMode, sect)
|
||||
@ -2226,6 +2232,7 @@ elfobj:
|
||||
sh.Flags = 0
|
||||
}
|
||||
|
||||
var shstroff uint64
|
||||
if !*FlagS {
|
||||
sh := elfshname(".symtab")
|
||||
sh.Type = uint32(elf.SHT_SYMTAB)
|
||||
@ -2239,10 +2246,19 @@ elfobj:
|
||||
sh = elfshname(".strtab")
|
||||
sh.Type = uint32(elf.SHT_STRTAB)
|
||||
sh.Off = uint64(symo) + uint64(symSize)
|
||||
sh.Size = uint64(len(Elfstrdat))
|
||||
sh.Size = uint64(len(elfstrdat))
|
||||
sh.Addralign = 1
|
||||
shstroff = sh.Off + sh.Size
|
||||
} else {
|
||||
shstroff = uint64(symo)
|
||||
}
|
||||
|
||||
sh = elfshname(".shstrtab")
|
||||
sh.Type = uint32(elf.SHT_STRTAB)
|
||||
sh.Off = shstroff
|
||||
sh.Size = uint64(len(elfshstrdat))
|
||||
sh.Addralign = 1
|
||||
|
||||
/* Main header */
|
||||
copy(eh.Ident[:], elf.ELFMAG)
|
||||
|
||||
|
@ -125,3 +125,61 @@ func TestNoDuplicateNeededEntries(t *testing.T) {
|
||||
t.Errorf("Got %d entries for `libc.so`, want %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShStrTabAttributesIssue62600(t *testing.T) {
|
||||
t.Parallel()
|
||||
testenv.MustHaveGoBuild(t)
|
||||
dir := t.TempDir()
|
||||
|
||||
const prog = `
|
||||
package main
|
||||
|
||||
func main() {
|
||||
println("whee")
|
||||
}
|
||||
`
|
||||
src := filepath.Join(dir, "issue62600.go")
|
||||
if err := os.WriteFile(src, []byte(prog), 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
binFile := filepath.Join(dir, "issue62600")
|
||||
cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", binFile, src)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
|
||||
}
|
||||
|
||||
fi, err := os.Open(binFile)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open built file: %v", err)
|
||||
}
|
||||
defer fi.Close()
|
||||
|
||||
elfFile, err := elf.NewFile(fi)
|
||||
if err != nil {
|
||||
t.Skip("The system may not support ELF, skipped.")
|
||||
}
|
||||
|
||||
section := elfFile.Section(".shstrtab")
|
||||
if section == nil {
|
||||
t.Fatal("no .shstrtab")
|
||||
}
|
||||
|
||||
// The .shstrtab section should have a zero address, non-zero
|
||||
// size, no ALLOC flag, and the offset should not fall into any of
|
||||
// the segments defined by the program headers.
|
||||
if section.Addr != 0 {
|
||||
t.Fatalf("expected Addr == 0 for .shstrtab got %x", section.Addr)
|
||||
}
|
||||
if section.Size == 0 {
|
||||
t.Fatal("expected nonzero Size for .shstrtab got 0")
|
||||
}
|
||||
if section.Flags&elf.SHF_ALLOC != 0 {
|
||||
t.Fatal("expected zero alloc flag got nonzero for .shstrtab")
|
||||
}
|
||||
for idx, p := range elfFile.Progs {
|
||||
if section.Offset >= p.Off && section.Offset < p.Off+p.Filesz {
|
||||
t.Fatalf("badly formed .shstrtab, is contained in segment %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,14 +45,14 @@ import (
|
||||
// Symbol table.
|
||||
|
||||
func putelfstr(s string) int {
|
||||
if len(Elfstrdat) == 0 && s != "" {
|
||||
if len(elfstrdat) == 0 && s != "" {
|
||||
// first entry must be empty string
|
||||
putelfstr("")
|
||||
}
|
||||
|
||||
off := len(Elfstrdat)
|
||||
Elfstrdat = append(Elfstrdat, s...)
|
||||
Elfstrdat = append(Elfstrdat, 0)
|
||||
off := len(elfstrdat)
|
||||
elfstrdat = append(elfstrdat, s...)
|
||||
elfstrdat = append(elfstrdat, 0)
|
||||
return off
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user