shared_test.go 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093
  1. // Copyright 2015 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. package shared_test
  5. import (
  6. "bufio"
  7. "bytes"
  8. "debug/elf"
  9. "encoding/binary"
  10. "flag"
  11. "fmt"
  12. "go/build"
  13. "io"
  14. "log"
  15. "os"
  16. "os/exec"
  17. "path/filepath"
  18. "regexp"
  19. "runtime"
  20. "sort"
  21. "strconv"
  22. "strings"
  23. "testing"
  24. "time"
  25. )
  26. var gopathInstallDir, gorootInstallDir string
  27. // This is the smallest set of packages we can link into a shared
  28. // library (runtime/cgo is built implicitly).
  29. var minpkgs = []string{"runtime", "sync/atomic"}
  30. var soname = "libruntime,sync-atomic.so"
  31. var testX = flag.Bool("testx", false, "if true, pass -x to 'go' subcommands invoked by the test")
  32. var testWork = flag.Bool("testwork", false, "if true, log and do not delete the temporary working directory")
  33. // run runs a command and calls t.Errorf if it fails.
  34. func run(t *testing.T, msg string, args ...string) {
  35. runWithEnv(t, msg, nil, args...)
  36. }
  37. // runWithEnv runs a command under the given environment and calls t.Errorf if it fails.
  38. func runWithEnv(t *testing.T, msg string, env []string, args ...string) {
  39. c := exec.Command(args[0], args[1:]...)
  40. if len(env) != 0 {
  41. c.Env = append(os.Environ(), env...)
  42. }
  43. if output, err := c.CombinedOutput(); err != nil {
  44. t.Errorf("executing %s (%s) failed %s:\n%s", strings.Join(args, " "), msg, err, output)
  45. }
  46. }
  47. // goCmd invokes the go tool with the installsuffix set up by TestMain. It calls
  48. // t.Fatalf if the command fails.
  49. func goCmd(t *testing.T, args ...string) string {
  50. newargs := []string{args[0]}
  51. if *testX && args[0] != "env" {
  52. newargs = append(newargs, "-x")
  53. }
  54. newargs = append(newargs, args[1:]...)
  55. c := exec.Command("go", newargs...)
  56. stderr := new(strings.Builder)
  57. c.Stderr = stderr
  58. if testing.Verbose() && t == nil {
  59. fmt.Fprintf(os.Stderr, "+ go %s\n", strings.Join(args, " "))
  60. c.Stderr = os.Stderr
  61. }
  62. output, err := c.Output()
  63. if err != nil {
  64. if t != nil {
  65. t.Helper()
  66. t.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, stderr)
  67. } else {
  68. // Panic instead of using log.Fatalf so that deferred cleanup may run in testMain.
  69. log.Panicf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, stderr)
  70. }
  71. }
  72. if testing.Verbose() && t != nil {
  73. t.Logf("go %s", strings.Join(args, " "))
  74. if stderr.Len() > 0 {
  75. t.Logf("%s", stderr)
  76. }
  77. }
  78. return string(bytes.TrimSpace(output))
  79. }
  80. // TestMain calls testMain so that the latter can use defer (TestMain exits with os.Exit).
  81. func testMain(m *testing.M) (int, error) {
  82. workDir, err := os.MkdirTemp("", "shared_test")
  83. if err != nil {
  84. return 0, err
  85. }
  86. if *testWork || testing.Verbose() {
  87. fmt.Printf("+ mkdir -p %s\n", workDir)
  88. }
  89. if !*testWork {
  90. defer os.RemoveAll(workDir)
  91. }
  92. // Some tests need to edit the source in GOPATH, so copy this directory to a
  93. // temporary directory and chdir to that.
  94. gopath := filepath.Join(workDir, "gopath")
  95. modRoot, err := cloneTestdataModule(gopath)
  96. if err != nil {
  97. return 0, err
  98. }
  99. if testing.Verbose() {
  100. fmt.Printf("+ export GOPATH=%s\n", gopath)
  101. fmt.Printf("+ cd %s\n", modRoot)
  102. }
  103. os.Setenv("GOPATH", gopath)
  104. // Explicitly override GOBIN as well, in case it was set through a GOENV file.
  105. os.Setenv("GOBIN", filepath.Join(gopath, "bin"))
  106. os.Chdir(modRoot)
  107. os.Setenv("PWD", modRoot)
  108. // The test also needs to install libraries into GOROOT/pkg, so copy the
  109. // subset of GOROOT that we need.
  110. //
  111. // TODO(golang.org/issue/28553): Rework -buildmode=shared so that it does not
  112. // need to write to GOROOT.
  113. goroot := filepath.Join(workDir, "goroot")
  114. if err := cloneGOROOTDeps(goroot); err != nil {
  115. return 0, err
  116. }
  117. if testing.Verbose() {
  118. fmt.Fprintf(os.Stderr, "+ export GOROOT=%s\n", goroot)
  119. }
  120. os.Setenv("GOROOT", goroot)
  121. myContext := build.Default
  122. myContext.GOROOT = goroot
  123. myContext.GOPATH = gopath
  124. runtimeP, err := myContext.Import("runtime", ".", build.ImportComment)
  125. if err != nil {
  126. return 0, fmt.Errorf("import failed: %v", err)
  127. }
  128. gorootInstallDir = runtimeP.PkgTargetRoot + "_dynlink"
  129. // All tests depend on runtime being built into a shared library. Because
  130. // that takes a few seconds, do it here and have all tests use the version
  131. // built here.
  132. goCmd(nil, append([]string{"install", "-buildmode=shared"}, minpkgs...)...)
  133. myContext.InstallSuffix = "_dynlink"
  134. depP, err := myContext.Import("./depBase", ".", build.ImportComment)
  135. if err != nil {
  136. return 0, fmt.Errorf("import failed: %v", err)
  137. }
  138. if depP.PkgTargetRoot == "" {
  139. gopathInstallDir = filepath.Dir(goCmd(nil, "list", "-buildmode=shared", "-f", "{{.Target}}", "./depBase"))
  140. } else {
  141. gopathInstallDir = filepath.Join(depP.PkgTargetRoot, "testshared")
  142. }
  143. return m.Run(), nil
  144. }
  145. func TestMain(m *testing.M) {
  146. log.SetFlags(log.Lshortfile)
  147. flag.Parse()
  148. exitCode, err := testMain(m)
  149. if err != nil {
  150. log.Fatal(err)
  151. }
  152. os.Exit(exitCode)
  153. }
  154. // cloneTestdataModule clones the packages from src/testshared into gopath.
  155. // It returns the directory within gopath at which the module root is located.
  156. func cloneTestdataModule(gopath string) (string, error) {
  157. modRoot := filepath.Join(gopath, "src", "testshared")
  158. if err := overlayDir(modRoot, "testdata"); err != nil {
  159. return "", err
  160. }
  161. if err := os.WriteFile(filepath.Join(modRoot, "go.mod"), []byte("module testshared\n"), 0644); err != nil {
  162. return "", err
  163. }
  164. return modRoot, nil
  165. }
  166. // cloneGOROOTDeps copies (or symlinks) the portions of GOROOT/src and
  167. // GOROOT/pkg relevant to this test into the given directory.
  168. // It must be run from within the testdata module.
  169. func cloneGOROOTDeps(goroot string) error {
  170. oldGOROOT := strings.TrimSpace(goCmd(nil, "env", "GOROOT"))
  171. if oldGOROOT == "" {
  172. return fmt.Errorf("go env GOROOT returned an empty string")
  173. }
  174. // Before we clone GOROOT, figure out which packages we need to copy over.
  175. listArgs := []string{
  176. "list",
  177. "-deps",
  178. "-f", "{{if and .Standard (not .ForTest)}}{{.ImportPath}}{{end}}",
  179. }
  180. stdDeps := goCmd(nil, append(listArgs, minpkgs...)...)
  181. testdataDeps := goCmd(nil, append(listArgs, "-test", "./...")...)
  182. pkgs := append(strings.Split(strings.TrimSpace(stdDeps), "\n"),
  183. strings.Split(strings.TrimSpace(testdataDeps), "\n")...)
  184. sort.Strings(pkgs)
  185. var pkgRoots []string
  186. for _, pkg := range pkgs {
  187. parentFound := false
  188. for _, prev := range pkgRoots {
  189. if strings.HasPrefix(pkg, prev) {
  190. // We will copy in the source for pkg when we copy in prev.
  191. parentFound = true
  192. break
  193. }
  194. }
  195. if !parentFound {
  196. pkgRoots = append(pkgRoots, pkg)
  197. }
  198. }
  199. gorootDirs := []string{
  200. "pkg/tool",
  201. "pkg/include",
  202. }
  203. for _, pkg := range pkgRoots {
  204. gorootDirs = append(gorootDirs, filepath.Join("src", pkg))
  205. }
  206. for _, dir := range gorootDirs {
  207. if testing.Verbose() {
  208. fmt.Fprintf(os.Stderr, "+ cp -r %s %s\n", filepath.Join(oldGOROOT, dir), filepath.Join(goroot, dir))
  209. }
  210. if err := overlayDir(filepath.Join(goroot, dir), filepath.Join(oldGOROOT, dir)); err != nil {
  211. return err
  212. }
  213. }
  214. return nil
  215. }
  216. // The shared library was built at the expected location.
  217. func TestSOBuilt(t *testing.T) {
  218. _, err := os.Stat(filepath.Join(gorootInstallDir, soname))
  219. if err != nil {
  220. t.Error(err)
  221. }
  222. }
  223. func hasDynTag(f *elf.File, tag elf.DynTag) bool {
  224. ds := f.SectionByType(elf.SHT_DYNAMIC)
  225. if ds == nil {
  226. return false
  227. }
  228. d, err := ds.Data()
  229. if err != nil {
  230. return false
  231. }
  232. for len(d) > 0 {
  233. var t elf.DynTag
  234. switch f.Class {
  235. case elf.ELFCLASS32:
  236. t = elf.DynTag(f.ByteOrder.Uint32(d[0:4]))
  237. d = d[8:]
  238. case elf.ELFCLASS64:
  239. t = elf.DynTag(f.ByteOrder.Uint64(d[0:8]))
  240. d = d[16:]
  241. }
  242. if t == tag {
  243. return true
  244. }
  245. }
  246. return false
  247. }
  248. // The shared library does not have relocations against the text segment.
  249. func TestNoTextrel(t *testing.T) {
  250. sopath := filepath.Join(gorootInstallDir, soname)
  251. f, err := elf.Open(sopath)
  252. if err != nil {
  253. t.Fatal("elf.Open failed: ", err)
  254. }
  255. defer f.Close()
  256. if hasDynTag(f, elf.DT_TEXTREL) {
  257. t.Errorf("%s has DT_TEXTREL set", soname)
  258. }
  259. }
  260. // The shared library does not contain symbols called ".dup"
  261. // (See golang.org/issue/14841.)
  262. func TestNoDupSymbols(t *testing.T) {
  263. sopath := filepath.Join(gorootInstallDir, soname)
  264. f, err := elf.Open(sopath)
  265. if err != nil {
  266. t.Fatal("elf.Open failed: ", err)
  267. }
  268. defer f.Close()
  269. syms, err := f.Symbols()
  270. if err != nil {
  271. t.Errorf("error reading symbols %v", err)
  272. return
  273. }
  274. for _, s := range syms {
  275. if s.Name == ".dup" {
  276. t.Fatalf("%s contains symbol called .dup", sopath)
  277. }
  278. }
  279. }
  280. // The install command should have created a "shlibname" file for the
  281. // listed packages (and runtime/cgo, and math on arm) indicating the
  282. // name of the shared library containing it.
  283. func TestShlibnameFiles(t *testing.T) {
  284. pkgs := append([]string{}, minpkgs...)
  285. pkgs = append(pkgs, "runtime/cgo")
  286. if runtime.GOARCH == "arm" {
  287. pkgs = append(pkgs, "math")
  288. }
  289. for _, pkg := range pkgs {
  290. shlibnamefile := filepath.Join(gorootInstallDir, pkg+".shlibname")
  291. contentsb, err := os.ReadFile(shlibnamefile)
  292. if err != nil {
  293. t.Errorf("error reading shlibnamefile for %s: %v", pkg, err)
  294. continue
  295. }
  296. contents := strings.TrimSpace(string(contentsb))
  297. if contents != soname {
  298. t.Errorf("shlibnamefile for %s has wrong contents: %q", pkg, contents)
  299. }
  300. }
  301. }
  302. // Is a given offset into the file contained in a loaded segment?
  303. func isOffsetLoaded(f *elf.File, offset uint64) bool {
  304. for _, prog := range f.Progs {
  305. if prog.Type == elf.PT_LOAD {
  306. if prog.Off <= offset && offset < prog.Off+prog.Filesz {
  307. return true
  308. }
  309. }
  310. }
  311. return false
  312. }
  313. func rnd(v int32, r int32) int32 {
  314. if r <= 0 {
  315. return v
  316. }
  317. v += r - 1
  318. c := v % r
  319. if c < 0 {
  320. c += r
  321. }
  322. v -= c
  323. return v
  324. }
  325. func readwithpad(r io.Reader, sz int32) ([]byte, error) {
  326. data := make([]byte, rnd(sz, 4))
  327. _, err := io.ReadFull(r, data)
  328. if err != nil {
  329. return nil, err
  330. }
  331. data = data[:sz]
  332. return data, nil
  333. }
  334. type note struct {
  335. name string
  336. tag int32
  337. desc string
  338. section *elf.Section
  339. }
  340. // Read all notes from f. As ELF section names are not supposed to be special, one
  341. // looks for a particular note by scanning all SHT_NOTE sections looking for a note
  342. // with a particular "name" and "tag".
  343. func readNotes(f *elf.File) ([]*note, error) {
  344. var notes []*note
  345. for _, sect := range f.Sections {
  346. if sect.Type != elf.SHT_NOTE {
  347. continue
  348. }
  349. r := sect.Open()
  350. for {
  351. var namesize, descsize, tag int32
  352. err := binary.Read(r, f.ByteOrder, &namesize)
  353. if err != nil {
  354. if err == io.EOF {
  355. break
  356. }
  357. return nil, fmt.Errorf("read namesize failed: %v", err)
  358. }
  359. err = binary.Read(r, f.ByteOrder, &descsize)
  360. if err != nil {
  361. return nil, fmt.Errorf("read descsize failed: %v", err)
  362. }
  363. err = binary.Read(r, f.ByteOrder, &tag)
  364. if err != nil {
  365. return nil, fmt.Errorf("read type failed: %v", err)
  366. }
  367. name, err := readwithpad(r, namesize)
  368. if err != nil {
  369. return nil, fmt.Errorf("read name failed: %v", err)
  370. }
  371. desc, err := readwithpad(r, descsize)
  372. if err != nil {
  373. return nil, fmt.Errorf("read desc failed: %v", err)
  374. }
  375. notes = append(notes, &note{name: string(name), tag: tag, desc: string(desc), section: sect})
  376. }
  377. }
  378. return notes, nil
  379. }
  380. func dynStrings(t *testing.T, path string, flag elf.DynTag) []string {
  381. t.Helper()
  382. f, err := elf.Open(path)
  383. if err != nil {
  384. t.Fatalf("elf.Open(%q) failed: %v", path, err)
  385. }
  386. defer f.Close()
  387. dynstrings, err := f.DynString(flag)
  388. if err != nil {
  389. t.Fatalf("DynString(%s) failed on %s: %v", flag, path, err)
  390. }
  391. return dynstrings
  392. }
  393. func AssertIsLinkedToRegexp(t *testing.T, path string, re *regexp.Regexp) {
  394. t.Helper()
  395. for _, dynstring := range dynStrings(t, path, elf.DT_NEEDED) {
  396. if re.MatchString(dynstring) {
  397. return
  398. }
  399. }
  400. t.Errorf("%s is not linked to anything matching %v", path, re)
  401. }
  402. func AssertIsLinkedTo(t *testing.T, path, lib string) {
  403. t.Helper()
  404. AssertIsLinkedToRegexp(t, path, regexp.MustCompile(regexp.QuoteMeta(lib)))
  405. }
  406. func AssertHasRPath(t *testing.T, path, dir string) {
  407. t.Helper()
  408. for _, tag := range []elf.DynTag{elf.DT_RPATH, elf.DT_RUNPATH} {
  409. for _, dynstring := range dynStrings(t, path, tag) {
  410. for _, rpath := range strings.Split(dynstring, ":") {
  411. if filepath.Clean(rpath) == filepath.Clean(dir) {
  412. return
  413. }
  414. }
  415. }
  416. }
  417. t.Errorf("%s does not have rpath %s", path, dir)
  418. }
  419. // Build a trivial program that links against the shared runtime and check it runs.
  420. func TestTrivialExecutable(t *testing.T) {
  421. goCmd(t, "install", "-linkshared", "./trivial")
  422. run(t, "trivial executable", "../../bin/trivial")
  423. AssertIsLinkedTo(t, "../../bin/trivial", soname)
  424. AssertHasRPath(t, "../../bin/trivial", gorootInstallDir)
  425. // It is 19K on linux/amd64, with separate-code in binutils ld and 64k being most common alignment
  426. // 4*64k should be enough, but this might need revision eventually.
  427. checkSize(t, "../../bin/trivial", 256000)
  428. }
  429. // Build a trivial program in PIE mode that links against the shared runtime and check it runs.
  430. func TestTrivialExecutablePIE(t *testing.T) {
  431. goCmd(t, "build", "-buildmode=pie", "-o", "trivial.pie", "-linkshared", "./trivial")
  432. run(t, "trivial executable", "./trivial.pie")
  433. AssertIsLinkedTo(t, "./trivial.pie", soname)
  434. AssertHasRPath(t, "./trivial.pie", gorootInstallDir)
  435. // It is 19K on linux/amd64, with separate-code in binutils ld and 64k being most common alignment
  436. // 4*64k should be enough, but this might need revision eventually.
  437. checkSize(t, "./trivial.pie", 256000)
  438. }
  439. // Check that the file size does not exceed a limit.
  440. func checkSize(t *testing.T, f string, limit int64) {
  441. fi, err := os.Stat(f)
  442. if err != nil {
  443. t.Fatalf("stat failed: %v", err)
  444. }
  445. if sz := fi.Size(); sz > limit {
  446. t.Errorf("file too large: got %d, want <= %d", sz, limit)
  447. }
  448. }
  449. // Build a division test program and check it runs.
  450. func TestDivisionExecutable(t *testing.T) {
  451. goCmd(t, "install", "-linkshared", "./division")
  452. run(t, "division executable", "../../bin/division")
  453. }
  454. // Build an executable that uses cgo linked against the shared runtime and check it
  455. // runs.
  456. func TestCgoExecutable(t *testing.T) {
  457. goCmd(t, "install", "-linkshared", "./execgo")
  458. run(t, "cgo executable", "../../bin/execgo")
  459. }
  460. func checkPIE(t *testing.T, name string) {
  461. f, err := elf.Open(name)
  462. if err != nil {
  463. t.Fatal("elf.Open failed: ", err)
  464. }
  465. defer f.Close()
  466. if f.Type != elf.ET_DYN {
  467. t.Errorf("%s has type %v, want ET_DYN", name, f.Type)
  468. }
  469. if hasDynTag(f, elf.DT_TEXTREL) {
  470. t.Errorf("%s has DT_TEXTREL set", name)
  471. }
  472. }
  473. func TestTrivialPIE(t *testing.T) {
  474. name := "trivial_pie"
  475. goCmd(t, "build", "-buildmode=pie", "-o="+name, "./trivial")
  476. defer os.Remove(name)
  477. run(t, name, "./"+name)
  478. checkPIE(t, name)
  479. }
  480. func TestCgoPIE(t *testing.T) {
  481. name := "cgo_pie"
  482. goCmd(t, "build", "-buildmode=pie", "-o="+name, "./execgo")
  483. defer os.Remove(name)
  484. run(t, name, "./"+name)
  485. checkPIE(t, name)
  486. }
  487. // Build a GOPATH package into a shared library that links against the goroot runtime
  488. // and an executable that links against both.
  489. func TestGopathShlib(t *testing.T) {
  490. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./depBase")
  491. shlib := goCmd(t, "list", "-f", "{{.Shlib}}", "-buildmode=shared", "-linkshared", "./depBase")
  492. AssertIsLinkedTo(t, shlib, soname)
  493. goCmd(t, "install", "-linkshared", "./exe")
  494. AssertIsLinkedTo(t, "../../bin/exe", soname)
  495. AssertIsLinkedTo(t, "../../bin/exe", filepath.Base(shlib))
  496. AssertHasRPath(t, "../../bin/exe", gorootInstallDir)
  497. AssertHasRPath(t, "../../bin/exe", filepath.Dir(gopathInstallDir))
  498. // And check it runs.
  499. run(t, "executable linked to GOPATH library", "../../bin/exe")
  500. }
  501. // The shared library contains a note listing the packages it contains in a section
  502. // that is not mapped into memory.
  503. func testPkgListNote(t *testing.T, f *elf.File, note *note) {
  504. if note.section.Flags != 0 {
  505. t.Errorf("package list section has flags %v, want 0", note.section.Flags)
  506. }
  507. if isOffsetLoaded(f, note.section.Offset) {
  508. t.Errorf("package list section contained in PT_LOAD segment")
  509. }
  510. if note.desc != "testshared/depBase\n" {
  511. t.Errorf("incorrect package list %q, want %q", note.desc, "testshared/depBase\n")
  512. }
  513. }
  514. // The shared library contains a note containing the ABI hash that is mapped into
  515. // memory and there is a local symbol called go.link.abihashbytes that points 16
  516. // bytes into it.
  517. func testABIHashNote(t *testing.T, f *elf.File, note *note) {
  518. if note.section.Flags != elf.SHF_ALLOC {
  519. t.Errorf("abi hash section has flags %v, want SHF_ALLOC", note.section.Flags)
  520. }
  521. if !isOffsetLoaded(f, note.section.Offset) {
  522. t.Errorf("abihash section not contained in PT_LOAD segment")
  523. }
  524. var hashbytes elf.Symbol
  525. symbols, err := f.Symbols()
  526. if err != nil {
  527. t.Errorf("error reading symbols %v", err)
  528. return
  529. }
  530. for _, sym := range symbols {
  531. if sym.Name == "go.link.abihashbytes" {
  532. hashbytes = sym
  533. }
  534. }
  535. if hashbytes.Name == "" {
  536. t.Errorf("no symbol called go.link.abihashbytes")
  537. return
  538. }
  539. if elf.ST_BIND(hashbytes.Info) != elf.STB_LOCAL {
  540. t.Errorf("%s has incorrect binding %v, want STB_LOCAL", hashbytes.Name, elf.ST_BIND(hashbytes.Info))
  541. }
  542. if f.Sections[hashbytes.Section] != note.section {
  543. t.Errorf("%s has incorrect section %v, want %s", hashbytes.Name, f.Sections[hashbytes.Section].Name, note.section.Name)
  544. }
  545. if hashbytes.Value-note.section.Addr != 16 {
  546. t.Errorf("%s has incorrect offset into section %d, want 16", hashbytes.Name, hashbytes.Value-note.section.Addr)
  547. }
  548. }
  549. // A Go shared library contains a note indicating which other Go shared libraries it
  550. // was linked against in an unmapped section.
  551. func testDepsNote(t *testing.T, f *elf.File, note *note) {
  552. if note.section.Flags != 0 {
  553. t.Errorf("package list section has flags %v, want 0", note.section.Flags)
  554. }
  555. if isOffsetLoaded(f, note.section.Offset) {
  556. t.Errorf("package list section contained in PT_LOAD segment")
  557. }
  558. // libdepBase.so just links against the lib containing the runtime.
  559. if note.desc != soname {
  560. t.Errorf("incorrect dependency list %q, want %q", note.desc, soname)
  561. }
  562. }
  563. // The shared library contains notes with defined contents; see above.
  564. func TestNotes(t *testing.T) {
  565. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./depBase")
  566. shlib := goCmd(t, "list", "-f", "{{.Shlib}}", "-buildmode=shared", "-linkshared", "./depBase")
  567. f, err := elf.Open(shlib)
  568. if err != nil {
  569. t.Fatal(err)
  570. }
  571. defer f.Close()
  572. notes, err := readNotes(f)
  573. if err != nil {
  574. t.Fatal(err)
  575. }
  576. pkgListNoteFound := false
  577. abiHashNoteFound := false
  578. depsNoteFound := false
  579. for _, note := range notes {
  580. if note.name != "Go\x00\x00" {
  581. continue
  582. }
  583. switch note.tag {
  584. case 1: // ELF_NOTE_GOPKGLIST_TAG
  585. if pkgListNoteFound {
  586. t.Error("multiple package list notes")
  587. }
  588. testPkgListNote(t, f, note)
  589. pkgListNoteFound = true
  590. case 2: // ELF_NOTE_GOABIHASH_TAG
  591. if abiHashNoteFound {
  592. t.Error("multiple abi hash notes")
  593. }
  594. testABIHashNote(t, f, note)
  595. abiHashNoteFound = true
  596. case 3: // ELF_NOTE_GODEPS_TAG
  597. if depsNoteFound {
  598. t.Error("multiple dependency list notes")
  599. }
  600. testDepsNote(t, f, note)
  601. depsNoteFound = true
  602. }
  603. }
  604. if !pkgListNoteFound {
  605. t.Error("package list note not found")
  606. }
  607. if !abiHashNoteFound {
  608. t.Error("abi hash note not found")
  609. }
  610. if !depsNoteFound {
  611. t.Error("deps note not found")
  612. }
  613. }
  614. // Build a GOPATH package (depBase) into a shared library that links against the goroot
  615. // runtime, another package (dep2) that links against the first, and an
  616. // executable that links against dep2.
  617. func TestTwoGopathShlibs(t *testing.T) {
  618. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./depBase")
  619. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./dep2")
  620. goCmd(t, "install", "-linkshared", "./exe2")
  621. run(t, "executable linked to GOPATH library", "../../bin/exe2")
  622. }
  623. func TestThreeGopathShlibs(t *testing.T) {
  624. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./depBase")
  625. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./dep2")
  626. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./dep3")
  627. goCmd(t, "install", "-linkshared", "./exe3")
  628. run(t, "executable linked to GOPATH library", "../../bin/exe3")
  629. }
  630. // If gccgo is not available or not new enough, call t.Skip.
  631. func requireGccgo(t *testing.T) {
  632. t.Helper()
  633. gccgoName := os.Getenv("GCCGO")
  634. if gccgoName == "" {
  635. gccgoName = "gccgo"
  636. }
  637. gccgoPath, err := exec.LookPath(gccgoName)
  638. if err != nil {
  639. t.Skip("gccgo not found")
  640. }
  641. cmd := exec.Command(gccgoPath, "-dumpversion")
  642. output, err := cmd.CombinedOutput()
  643. if err != nil {
  644. t.Fatalf("%s -dumpversion failed: %v\n%s", gccgoPath, err, output)
  645. }
  646. dot := bytes.Index(output, []byte{'.'})
  647. if dot > 0 {
  648. output = output[:dot]
  649. }
  650. major, err := strconv.Atoi(string(output))
  651. if err != nil {
  652. t.Skipf("can't parse gccgo version number %s", output)
  653. }
  654. if major < 5 {
  655. t.Skipf("gccgo too old (%s)", strings.TrimSpace(string(output)))
  656. }
  657. gomod, err := exec.Command("go", "env", "GOMOD").Output()
  658. if err != nil {
  659. t.Fatalf("go env GOMOD: %v", err)
  660. }
  661. if len(bytes.TrimSpace(gomod)) > 0 {
  662. t.Skipf("gccgo not supported in module mode; see golang.org/issue/30344")
  663. }
  664. }
  665. // Build a GOPATH package into a shared library with gccgo and an executable that
  666. // links against it.
  667. func TestGoPathShlibGccgo(t *testing.T) {
  668. requireGccgo(t)
  669. libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
  670. goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "./depBase")
  671. // Run 'go list' after 'go install': with gccgo, we apparently don't know the
  672. // shlib location until after we've installed it.
  673. shlib := goCmd(t, "list", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "-f", "{{.Shlib}}", "./depBase")
  674. AssertIsLinkedToRegexp(t, shlib, libgoRE)
  675. goCmd(t, "install", "-compiler=gccgo", "-linkshared", "./exe")
  676. AssertIsLinkedToRegexp(t, "../../bin/exe", libgoRE)
  677. AssertIsLinkedTo(t, "../../bin/exe", filepath.Base(shlib))
  678. AssertHasRPath(t, "../../bin/exe", filepath.Dir(shlib))
  679. // And check it runs.
  680. run(t, "gccgo-built", "../../bin/exe")
  681. }
  682. // The gccgo version of TestTwoGopathShlibs: build a GOPATH package into a shared
  683. // library with gccgo, another GOPATH package that depends on the first and an
  684. // executable that links the second library.
  685. func TestTwoGopathShlibsGccgo(t *testing.T) {
  686. requireGccgo(t)
  687. libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
  688. goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "./depBase")
  689. goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "./dep2")
  690. goCmd(t, "install", "-compiler=gccgo", "-linkshared", "./exe2")
  691. // Run 'go list' after 'go install': with gccgo, we apparently don't know the
  692. // shlib location until after we've installed it.
  693. dep2 := goCmd(t, "list", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "-f", "{{.Shlib}}", "./dep2")
  694. depBase := goCmd(t, "list", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "-f", "{{.Shlib}}", "./depBase")
  695. AssertIsLinkedToRegexp(t, depBase, libgoRE)
  696. AssertIsLinkedToRegexp(t, dep2, libgoRE)
  697. AssertIsLinkedTo(t, dep2, filepath.Base(depBase))
  698. AssertIsLinkedToRegexp(t, "../../bin/exe2", libgoRE)
  699. AssertIsLinkedTo(t, "../../bin/exe2", filepath.Base(dep2))
  700. AssertIsLinkedTo(t, "../../bin/exe2", filepath.Base(depBase))
  701. // And check it runs.
  702. run(t, "gccgo-built", "../../bin/exe2")
  703. }
  704. // Testing rebuilding of shared libraries when they are stale is a bit more
  705. // complicated that it seems like it should be. First, we make everything "old": but
  706. // only a few seconds old, or it might be older than gc (or the runtime source) and
  707. // everything will get rebuilt. Then define a timestamp slightly newer than this
  708. // time, which is what we set the mtime to of a file to cause it to be seen as new,
  709. // and finally another slightly even newer one that we can compare files against to
  710. // see if they have been rebuilt.
  711. var oldTime = time.Now().Add(-9 * time.Second)
  712. var nearlyNew = time.Now().Add(-6 * time.Second)
  713. var stampTime = time.Now().Add(-3 * time.Second)
  714. // resetFileStamps makes "everything" (bin, src, pkg from GOPATH and the
  715. // test-specific parts of GOROOT) appear old.
  716. func resetFileStamps() {
  717. chtime := func(path string, info os.FileInfo, err error) error {
  718. return os.Chtimes(path, oldTime, oldTime)
  719. }
  720. reset := func(path string) {
  721. if err := filepath.Walk(path, chtime); err != nil {
  722. log.Panicf("resetFileStamps failed: %v", err)
  723. }
  724. }
  725. reset("../../bin")
  726. reset("../../pkg")
  727. reset("../../src")
  728. reset(gorootInstallDir)
  729. }
  730. // touch changes path and returns a function that changes it back.
  731. // It also sets the time of the file, so that we can see if it is rewritten.
  732. func touch(t *testing.T, path string) (cleanup func()) {
  733. t.Helper()
  734. data, err := os.ReadFile(path)
  735. if err != nil {
  736. t.Fatal(err)
  737. }
  738. old := make([]byte, len(data))
  739. copy(old, data)
  740. if bytes.HasPrefix(data, []byte("!<arch>\n")) {
  741. // Change last digit of build ID.
  742. // (Content ID in the new content-based build IDs.)
  743. const marker = `build id "`
  744. i := bytes.Index(data, []byte(marker))
  745. if i < 0 {
  746. t.Fatal("cannot find build id in archive")
  747. }
  748. j := bytes.IndexByte(data[i+len(marker):], '"')
  749. if j < 0 {
  750. t.Fatal("cannot find build id in archive")
  751. }
  752. i += len(marker) + j - 1
  753. if data[i] == 'a' {
  754. data[i] = 'b'
  755. } else {
  756. data[i] = 'a'
  757. }
  758. } else {
  759. // assume it's a text file
  760. data = append(data, '\n')
  761. }
  762. // If the file is still a symlink from an overlay, delete it so that we will
  763. // replace it with a regular file instead of overwriting the symlinked one.
  764. fi, err := os.Lstat(path)
  765. if err == nil && !fi.Mode().IsRegular() {
  766. fi, err = os.Stat(path)
  767. if err := os.Remove(path); err != nil {
  768. t.Fatal(err)
  769. }
  770. }
  771. if err != nil {
  772. t.Fatal(err)
  773. }
  774. // If we're replacing a symlink to a read-only file, make the new file
  775. // user-writable.
  776. perm := fi.Mode().Perm() | 0200
  777. if err := os.WriteFile(path, data, perm); err != nil {
  778. t.Fatal(err)
  779. }
  780. if err := os.Chtimes(path, nearlyNew, nearlyNew); err != nil {
  781. t.Fatal(err)
  782. }
  783. return func() {
  784. if err := os.WriteFile(path, old, perm); err != nil {
  785. t.Fatal(err)
  786. }
  787. }
  788. }
  789. // isNew returns if the path is newer than the time stamp used by touch.
  790. func isNew(t *testing.T, path string) bool {
  791. t.Helper()
  792. fi, err := os.Stat(path)
  793. if err != nil {
  794. t.Fatal(err)
  795. }
  796. return fi.ModTime().After(stampTime)
  797. }
  798. // Fail unless path has been rebuilt (i.e. is newer than the time stamp used by
  799. // isNew)
  800. func AssertRebuilt(t *testing.T, msg, path string) {
  801. t.Helper()
  802. if !isNew(t, path) {
  803. t.Errorf("%s was not rebuilt (%s)", msg, path)
  804. }
  805. }
  806. // Fail if path has been rebuilt (i.e. is newer than the time stamp used by isNew)
  807. func AssertNotRebuilt(t *testing.T, msg, path string) {
  808. t.Helper()
  809. if isNew(t, path) {
  810. t.Errorf("%s was rebuilt (%s)", msg, path)
  811. }
  812. }
  813. func TestRebuilding(t *testing.T) {
  814. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./depBase")
  815. goCmd(t, "install", "-linkshared", "./exe")
  816. info := strings.Fields(goCmd(t, "list", "-buildmode=shared", "-linkshared", "-f", "{{.Target}} {{.Shlib}}", "./depBase"))
  817. if len(info) != 2 {
  818. t.Fatalf("go list failed to report Target and/or Shlib")
  819. }
  820. target := info[0]
  821. shlib := info[1]
  822. // If the source is newer than both the .a file and the .so, both are rebuilt.
  823. t.Run("newsource", func(t *testing.T) {
  824. resetFileStamps()
  825. cleanup := touch(t, "./depBase/dep.go")
  826. defer func() {
  827. cleanup()
  828. goCmd(t, "install", "-linkshared", "./exe")
  829. }()
  830. goCmd(t, "install", "-linkshared", "./exe")
  831. AssertRebuilt(t, "new source", target)
  832. AssertRebuilt(t, "new source", shlib)
  833. })
  834. // If the .a file is newer than the .so, the .so is rebuilt (but not the .a)
  835. t.Run("newarchive", func(t *testing.T) {
  836. resetFileStamps()
  837. AssertNotRebuilt(t, "new .a file before build", target)
  838. goCmd(t, "list", "-linkshared", "-f={{.ImportPath}} {{.Stale}} {{.StaleReason}} {{.Target}}", "./depBase")
  839. AssertNotRebuilt(t, "new .a file before build", target)
  840. cleanup := touch(t, target)
  841. defer func() {
  842. cleanup()
  843. goCmd(t, "install", "-v", "-linkshared", "./exe")
  844. }()
  845. goCmd(t, "install", "-v", "-linkshared", "./exe")
  846. AssertNotRebuilt(t, "new .a file", target)
  847. AssertRebuilt(t, "new .a file", shlib)
  848. })
  849. }
  850. func appendFile(t *testing.T, path, content string) {
  851. t.Helper()
  852. f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0660)
  853. if err != nil {
  854. t.Fatalf("os.OpenFile failed: %v", err)
  855. }
  856. defer func() {
  857. err := f.Close()
  858. if err != nil {
  859. t.Fatalf("f.Close failed: %v", err)
  860. }
  861. }()
  862. _, err = f.WriteString(content)
  863. if err != nil {
  864. t.Fatalf("f.WriteString failed: %v", err)
  865. }
  866. }
  867. func createFile(t *testing.T, path, content string) {
  868. t.Helper()
  869. f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
  870. if err != nil {
  871. t.Fatalf("os.OpenFile failed: %v", err)
  872. }
  873. _, err = f.WriteString(content)
  874. if closeErr := f.Close(); err == nil {
  875. err = closeErr
  876. }
  877. if err != nil {
  878. t.Fatalf("WriteString failed: %v", err)
  879. }
  880. }
  881. func TestABIChecking(t *testing.T) {
  882. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./depBase")
  883. goCmd(t, "install", "-linkshared", "./exe")
  884. // If we make an ABI-breaking change to depBase and rebuild libp.so but not exe,
  885. // exe will abort with a complaint on startup.
  886. // This assumes adding an exported function breaks ABI, which is not true in
  887. // some senses but suffices for the narrow definition of ABI compatibility the
  888. // toolchain uses today.
  889. resetFileStamps()
  890. createFile(t, "./depBase/break.go", "package depBase\nfunc ABIBreak() {}\n")
  891. defer os.Remove("./depBase/break.go")
  892. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./depBase")
  893. c := exec.Command("../../bin/exe")
  894. output, err := c.CombinedOutput()
  895. if err == nil {
  896. t.Fatal("executing exe did not fail after ABI break")
  897. }
  898. scanner := bufio.NewScanner(bytes.NewReader(output))
  899. foundMsg := false
  900. const wantPrefix = "abi mismatch detected between the executable and lib"
  901. for scanner.Scan() {
  902. if strings.HasPrefix(scanner.Text(), wantPrefix) {
  903. foundMsg = true
  904. break
  905. }
  906. }
  907. if err = scanner.Err(); err != nil {
  908. t.Errorf("scanner encountered error: %v", err)
  909. }
  910. if !foundMsg {
  911. t.Fatalf("exe failed, but without line %q; got output:\n%s", wantPrefix, output)
  912. }
  913. // Rebuilding exe makes it work again.
  914. goCmd(t, "install", "-linkshared", "./exe")
  915. run(t, "rebuilt exe", "../../bin/exe")
  916. // If we make a change which does not break ABI (such as adding an unexported
  917. // function) and rebuild libdepBase.so, exe still works, even if new function
  918. // is in a file by itself.
  919. resetFileStamps()
  920. createFile(t, "./depBase/dep2.go", "package depBase\nfunc noABIBreak() {}\n")
  921. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./depBase")
  922. run(t, "after non-ABI breaking change", "../../bin/exe")
  923. }
  924. // If a package 'explicit' imports a package 'implicit', building
  925. // 'explicit' into a shared library implicitly includes implicit in
  926. // the shared library. Building an executable that imports both
  927. // explicit and implicit builds the code from implicit into the
  928. // executable rather than fetching it from the shared library. The
  929. // link still succeeds and the executable still runs though.
  930. func TestImplicitInclusion(t *testing.T) {
  931. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./explicit")
  932. goCmd(t, "install", "-linkshared", "./implicitcmd")
  933. run(t, "running executable linked against library that contains same package as it", "../../bin/implicitcmd")
  934. }
  935. // Tests to make sure that the type fields of empty interfaces and itab
  936. // fields of nonempty interfaces are unique even across modules,
  937. // so that interface equality works correctly.
  938. func TestInterface(t *testing.T) {
  939. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./iface_a")
  940. // Note: iface_i gets installed implicitly as a dependency of iface_a.
  941. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./iface_b")
  942. goCmd(t, "install", "-linkshared", "./iface")
  943. run(t, "running type/itab uniqueness tester", "../../bin/iface")
  944. }
  945. // Access a global variable from a library.
  946. func TestGlobal(t *testing.T) {
  947. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./globallib")
  948. goCmd(t, "install", "-linkshared", "./global")
  949. run(t, "global executable", "../../bin/global")
  950. AssertIsLinkedTo(t, "../../bin/global", soname)
  951. AssertHasRPath(t, "../../bin/global", gorootInstallDir)
  952. }
  953. // Run a test using -linkshared of an installed shared package.
  954. // Issue 26400.
  955. func TestTestInstalledShared(t *testing.T) {
  956. goCmd(t, "test", "-linkshared", "-test.short", "sync/atomic")
  957. }
  958. // Test generated pointer method with -linkshared.
  959. // Issue 25065.
  960. func TestGeneratedMethod(t *testing.T) {
  961. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue25065")
  962. }
  963. // Test use of shared library struct with generated hash function.
  964. // Issue 30768.
  965. func TestGeneratedHash(t *testing.T) {
  966. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue30768/issue30768lib")
  967. goCmd(t, "test", "-linkshared", "./issue30768")
  968. }
  969. // Test that packages can be added not in dependency order (here a depends on b, and a adds
  970. // before b). This could happen with e.g. go build -buildmode=shared std. See issue 39777.
  971. func TestPackageOrder(t *testing.T) {
  972. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue39777/a", "./issue39777/b")
  973. }
  974. // Test that GC data are generated correctly by the linker when it needs a type defined in
  975. // a shared library. See issue 39927.
  976. func TestGCData(t *testing.T) {
  977. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./gcdata/p")
  978. goCmd(t, "build", "-linkshared", "./gcdata/main")
  979. runWithEnv(t, "running gcdata/main", []string{"GODEBUG=clobberfree=1"}, "./main")
  980. }
  981. // Test that we don't decode type symbols from shared libraries (which has no data,
  982. // causing panic). See issue 44031.
  983. func TestIssue44031(t *testing.T) {
  984. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue44031/a")
  985. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue44031/b")
  986. goCmd(t, "run", "-linkshared", "./issue44031/main")
  987. }
  988. // Test that we use a variable from shared libraries (which implement an
  989. // interface in shared libraries.). A weak reference is used in the itab
  990. // in main process. It can cause unreacheble panic. See issue 47873.
  991. func TestIssue47873(t *testing.T) {
  992. goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue47837/a")
  993. goCmd(t, "run", "-linkshared", "./issue47837/main")
  994. }