Source file src/cmd/link/internal/ld/elf_test.go

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

View as plain text