github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/link/ld/elf_test.go (about)

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build cgo
     6  
     7  package ld
     8  
     9  import (
    10  	"debug/elf"
    11  	"os"
    12  	"path/filepath"
    13  	"runtime"
    14  	"strings"
    15  	"testing"
    16  
    17  	"github.com/go-asm/go/testenv"
    18  )
    19  
    20  func TestDynSymShInfo(t *testing.T) {
    21  	t.Parallel()
    22  	testenv.MustHaveGoBuild(t)
    23  	dir := t.TempDir()
    24  
    25  	const prog = `
    26  package main
    27  
    28  import "net"
    29  
    30  func main() {
    31  	net.Dial("", "")
    32  }
    33  `
    34  	src := filepath.Join(dir, "issue33358.go")
    35  	if err := os.WriteFile(src, []byte(prog), 0666); err != nil {
    36  		t.Fatal(err)
    37  	}
    38  
    39  	binFile := filepath.Join(dir, "issue33358")
    40  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", binFile, src)
    41  	if out, err := cmd.CombinedOutput(); err != nil {
    42  		t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
    43  	}
    44  
    45  	fi, err := os.Open(binFile)
    46  	if err != nil {
    47  		t.Fatalf("failed to open built file: %v", err)
    48  	}
    49  	defer fi.Close()
    50  
    51  	elfFile, err := elf.NewFile(fi)
    52  	if err != nil {
    53  		t.Skip("The system may not support ELF, skipped.")
    54  	}
    55  
    56  	section := elfFile.Section(".dynsym")
    57  	if section == nil {
    58  		t.Fatal("no dynsym")
    59  	}
    60  
    61  	symbols, err := elfFile.DynamicSymbols()
    62  	if err != nil {
    63  		t.Fatalf("failed to get dynamic symbols: %v", err)
    64  	}
    65  
    66  	var numLocalSymbols uint32
    67  	for i, s := range symbols {
    68  		if elf.ST_BIND(s.Info) != elf.STB_LOCAL {
    69  			numLocalSymbols = uint32(i + 1)
    70  			break
    71  		}
    72  	}
    73  
    74  	if section.Info != numLocalSymbols {
    75  		t.Fatalf("Unexpected sh info, want greater than 0, got: %d", section.Info)
    76  	}
    77  }
    78  
    79  func TestNoDuplicateNeededEntries(t *testing.T) {
    80  	testenv.MustHaveGoBuild(t)
    81  	testenv.MustHaveCGO(t)
    82  
    83  	// run this test on just a small set of platforms (no need to test it
    84  	// across the board given the nature of the test).
    85  	pair := runtime.GOOS + "-" + runtime.GOARCH
    86  	switch pair {
    87  	case "linux-amd64", "linux-arm64", "freebsd-amd64", "openbsd-amd64":
    88  	default:
    89  		t.Skip("no need for test on " + pair)
    90  	}
    91  
    92  	t.Parallel()
    93  
    94  	dir := t.TempDir()
    95  
    96  	wd, err := os.Getwd()
    97  	if err != nil {
    98  		t.Fatalf("Failed to get working directory: %v", err)
    99  	}
   100  
   101  	path := filepath.Join(dir, "x")
   102  	argv := []string{"build", "-o", path, filepath.Join(wd, "testdata", "issue39256")}
   103  	out, err := testenv.Command(t, testenv.GoToolPath(t), argv...).CombinedOutput()
   104  	if err != nil {
   105  		t.Fatalf("Build failure: %s\n%s\n", err, string(out))
   106  	}
   107  
   108  	f, err := elf.Open(path)
   109  	if err != nil {
   110  		t.Fatalf("Failed to open ELF file: %v", err)
   111  	}
   112  	libs, err := f.ImportedLibraries()
   113  	if err != nil {
   114  		t.Fatalf("Failed to read imported libraries: %v", err)
   115  	}
   116  
   117  	var count int
   118  	for _, lib := range libs {
   119  		if lib == "libc.so" || strings.HasPrefix(lib, "libc.so.") {
   120  			count++
   121  		}
   122  	}
   123  
   124  	if got, want := count, 1; got != want {
   125  		t.Errorf("Got %d entries for `libc.so`, want %d", got, want)
   126  	}
   127  }
   128  
   129  func TestShStrTabAttributesIssue62600(t *testing.T) {
   130  	t.Parallel()
   131  	testenv.MustHaveGoBuild(t)
   132  	dir := t.TempDir()
   133  
   134  	const prog = `
   135  package main
   136  
   137  func main() {
   138  	println("whee")
   139  }
   140  `
   141  	src := filepath.Join(dir, "issue62600.go")
   142  	if err := os.WriteFile(src, []byte(prog), 0666); err != nil {
   143  		t.Fatal(err)
   144  	}
   145  
   146  	binFile := filepath.Join(dir, "issue62600")
   147  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", binFile, src)
   148  	if out, err := cmd.CombinedOutput(); err != nil {
   149  		t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
   150  	}
   151  
   152  	fi, err := os.Open(binFile)
   153  	if err != nil {
   154  		t.Fatalf("failed to open built file: %v", err)
   155  	}
   156  	defer fi.Close()
   157  
   158  	elfFile, err := elf.NewFile(fi)
   159  	if err != nil {
   160  		t.Skip("The system may not support ELF, skipped.")
   161  	}
   162  
   163  	section := elfFile.Section(".shstrtab")
   164  	if section == nil {
   165  		t.Fatal("no .shstrtab")
   166  	}
   167  
   168  	// The .shstrtab section should have a zero address, non-zero
   169  	// size, no ALLOC flag, and the offset should not fall into any of
   170  	// the segments defined by the program headers.
   171  	if section.Addr != 0 {
   172  		t.Fatalf("expected Addr == 0 for .shstrtab got %x", section.Addr)
   173  	}
   174  	if section.Size == 0 {
   175  		t.Fatal("expected nonzero Size for .shstrtab got 0")
   176  	}
   177  	if section.Flags&elf.SHF_ALLOC != 0 {
   178  		t.Fatal("expected zero alloc flag got nonzero for .shstrtab")
   179  	}
   180  	for idx, p := range elfFile.Progs {
   181  		if section.Offset >= p.Off && section.Offset < p.Off+p.Filesz {
   182  			t.Fatalf("badly formed .shstrtab, is contained in segment %d", idx)
   183  		}
   184  	}
   185  }