cmd/link: default generic ABI compression for ELF

This CL change all debug dwarf headers to generic ABI
"Compression header" for ELF
(http://www.sco.com/developers/gabi/latest/ch4.sheader.html#compression_header)

Fixes #50796

Change-Id: I188625e596f11cd120dbd802ac2d79341d5eaf41
Reviewed-on: https://go-review.googlesource.com/c/go/+/380755
Trust: mzh <mzh@golangcn.org>
Run-TryBot: mzh <mzh@golangcn.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
diff --git a/src/cmd/link/elf_test.go b/src/cmd/link/elf_test.go
index 760d9ea..318bd76 100644
--- a/src/cmd/link/elf_test.go
+++ b/src/cmd/link/elf_test.go
@@ -455,6 +455,9 @@
 			extraexe := extrasize(elfexe)
 			extrapie := extrasize(elfpie)
 
+			if sizepie < sizeexe || sizepie-extrapie < sizeexe-extraexe {
+				return
+			}
 			diffReal := (sizepie - extrapie) - (sizeexe - extraexe)
 			diffExpected := (textpie + dynpie) - (textexe + dynexe)
 
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 95a8e0f..0ec1e52 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -2778,10 +2778,29 @@
 	}
 
 	var buf bytes.Buffer
-	buf.Write([]byte("ZLIB"))
-	var sizeBytes [8]byte
-	binary.BigEndian.PutUint64(sizeBytes[:], uint64(total))
-	buf.Write(sizeBytes[:])
+	if ctxt.IsELF {
+		switch ctxt.Arch.PtrSize {
+		case 8:
+			binary.Write(&buf, ctxt.Arch.ByteOrder, elf.Chdr64{
+				Type:      uint32(elf.COMPRESS_ZLIB),
+				Size:      uint64(total),
+				Addralign: uint64(ctxt.Arch.Alignment),
+			})
+		case 4:
+			binary.Write(&buf, ctxt.Arch.ByteOrder, elf.Chdr32{
+				Type:      uint32(elf.COMPRESS_ZLIB),
+				Size:      uint32(total),
+				Addralign: uint32(ctxt.Arch.Alignment),
+			})
+		default:
+			log.Fatalf("can't compress header size:%d", ctxt.Arch.PtrSize)
+		}
+	} else {
+		buf.Write([]byte("ZLIB"))
+		var sizeBytes [8]byte
+		binary.BigEndian.PutUint64(sizeBytes[:], uint64(total))
+		buf.Write(sizeBytes[:])
+	}
 
 	var relocbuf []byte // temporary buffer for applying relocations
 
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index 4aaed7b..289ebcb 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -2227,11 +2227,18 @@
 			newDwarfp = append(newDwarfp, ds)
 			Segdwarf.Sections = append(Segdwarf.Sections, ldr.SymSect(s))
 		} else {
-			compressedSegName := ".zdebug_" + ldr.SymSect(s).Name[len(".debug_"):]
+			var compressedSegName string
+			if ctxt.IsELF {
+				compressedSegName = ldr.SymSect(s).Name
+			} else {
+				compressedSegName = ".zdebug_" + ldr.SymSect(s).Name[len(".debug_"):]
+			}
 			sect := addsection(ctxt.loader, ctxt.Arch, &Segdwarf, compressedSegName, 04)
 			sect.Align = 1
 			sect.Length = uint64(len(z.compressed))
-			newSym := ldr.CreateSymForUpdate(compressedSegName, 0)
+			sect.Compressed = true
+			newSym := ldr.MakeSymbolBuilder(compressedSegName)
+			ldr.SetAttrReachable(s, true)
 			newSym.SetData(z.compressed)
 			newSym.SetSize(int64(len(z.compressed)))
 			ldr.SetSymSect(newSym.Sym(), sect)
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 1bdfb33..7f45a8f 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -1102,6 +1102,9 @@
 	}
 	if strings.HasPrefix(sect.Name, ".debug") || strings.HasPrefix(sect.Name, ".zdebug") {
 		sh.Flags = 0
+		if sect.Compressed {
+			sh.Flags |= uint64(elf.SHF_COMPRESSED)
+		}
 	}
 
 	if linkmode != LinkExternal {
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index f1a37e9..a81232b 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1477,7 +1477,7 @@
 		argv = append(argv, unusedArguments)
 	}
 
-	const compressDWARF = "-Wl,--compress-debug-sections=zlib-gnu"
+	const compressDWARF = "-Wl,--compress-debug-sections=zlib"
 	if ctxt.compressDWARF && linkerFlagSupported(ctxt.Arch, argv[0], altLinker, compressDWARF) {
 		argv = append(argv, compressDWARF)
 	}
diff --git a/src/cmd/link/internal/sym/segment.go b/src/cmd/link/internal/sym/segment.go
index 97853b9..c889e71 100644
--- a/src/cmd/link/internal/sym/segment.go
+++ b/src/cmd/link/internal/sym/segment.go
@@ -63,4 +63,6 @@
 	Relcount uint32
 	Sym      LoaderSym // symbol for the section, if any
 	Index    uint16    // each section has a unique index, used internally
+
+	Compressed bool
 }
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index 8c84661..e93200a 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -1150,11 +1150,37 @@
 		if err != nil && uint64(len(b)) < s.Size {
 			return nil, err
 		}
-
+		var (
+			dlen uint64
+			dbuf []byte
+		)
 		if len(b) >= 12 && string(b[:4]) == "ZLIB" {
-			dlen := binary.BigEndian.Uint64(b[4:12])
-			dbuf := make([]byte, dlen)
-			r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
+			dlen = binary.BigEndian.Uint64(b[4:12])
+			s.compressionOffset = 12
+		}
+		if dlen == 0 && len(b) >= 12 && s.Flags&SHF_COMPRESSED != 0 &&
+			s.Flags&SHF_ALLOC == 0 &&
+			f.FileHeader.ByteOrder.Uint32(b[:]) == uint32(COMPRESS_ZLIB) {
+			s.compressionType = COMPRESS_ZLIB
+			switch f.FileHeader.Class {
+			case ELFCLASS32:
+				// Chdr32.Size offset
+				dlen = uint64(f.FileHeader.ByteOrder.Uint32(b[4:]))
+				s.compressionOffset = 12
+			case ELFCLASS64:
+				if len(b) < 24 {
+					return nil, errors.New("invalid compress header 64")
+				}
+				// Chdr64.Size offset
+				dlen = f.FileHeader.ByteOrder.Uint64(b[8:])
+				s.compressionOffset = 24
+			default:
+				return nil, fmt.Errorf("unsupported compress header:%s", f.FileHeader.Class)
+			}
+		}
+		if dlen > 0 {
+			dbuf = make([]byte, dlen)
+			r, err := zlib.NewReader(bytes.NewBuffer(b[s.compressionOffset:]))
 			if err != nil {
 				return nil, err
 			}