cmd/link: use sym.Symbol in addpersrc

addpersrc is called very late, after we have converted to
sym.Symbols and various fields in loader representation have been
dropped. Use the Symbol representation there.

Fixes #39658.

Change-Id: I616e838655b6f01554644171317e2cc5cefabf39
Reviewed-on: https://go-review.googlesource.com/c/go/+/238779
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index 362d2fd..c9cb25d 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -1470,6 +1470,7 @@
 	}
 
 	rsrcsym = sym
+	ctxt.loader.SetAttrReachable(rsrcsym, true)
 }
 
 func addpersrc(ctxt *Link) {
@@ -1477,18 +1478,18 @@
 		return
 	}
 
-	data := ctxt.loader.Data(rsrcsym)
+	rsrc := ctxt.loader.Syms[rsrcsym]
+	data := rsrc.P
 	size := len(data)
 	h := pefile.addSection(".rsrc", size, size)
 	h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
 	h.checkOffset(ctxt.Out.Offset())
 
 	// relocation
-	relocs := ctxt.loader.Relocs(rsrcsym)
-	for i := 0; i < relocs.Count(); i++ {
-		r := relocs.At2(i)
-		p := data[r.Off():]
-		val := uint32(int64(h.virtualAddress) + r.Add())
+	for ri := range rsrc.R {
+		r := &rsrc.R[ri]
+		p := data[r.Off:]
+		val := uint32(int64(h.virtualAddress) + r.Add)
 
 		// 32-bit little-endian
 		p[0] = byte(val)
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index 5ff9912..dc7adcb 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -746,3 +746,37 @@
 		t.Errorf("did not see expected error message. out:\n%s", out)
 	}
 }
+
+func TestPErsrc(t *testing.T) {
+	// Test that PE rsrc section is handled correctly (issue 39658).
+	testenv.MustHaveGoBuild(t)
+
+	if runtime.GOARCH != "amd64" || runtime.GOOS != "windows" {
+		t.Skipf("this is a windows/amd64-only test")
+	}
+
+	tmpdir, err := ioutil.TempDir("", "TestPErsrc")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+
+	pkgdir := filepath.Join("testdata", "testPErsrc")
+	exe := filepath.Join(tmpdir, "a.exe")
+	cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
+	cmd.Dir = pkgdir
+	// cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("building failed: %v, output:\n%s", err, out)
+	}
+
+	// Check that the binary contains the rsrc data
+	b, err := ioutil.ReadFile(exe)
+	if err != nil {
+		t.Fatalf("reading output failed: %v", err)
+	}
+	if !bytes.Contains(b, []byte("Hello Gophers!")) {
+		t.Fatalf("binary does not contain expected content")
+	}
+}
diff --git a/src/cmd/link/testdata/testPErsrc/main.go b/src/cmd/link/testdata/testPErsrc/main.go
new file mode 100644
index 0000000..5eb66fb
--- /dev/null
+++ b/src/cmd/link/testdata/testPErsrc/main.go
@@ -0,0 +1,19 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that a PE rsrc section is handled correctly (issue 39658).
+//
+// rsrc.syso is created with:
+//	windres -i a.rc -o rsrc.syso -O coff
+// on windows-amd64-2016 builder, where a.rc is a text file with
+// the following content:
+//
+// resname RCDATA {
+//   "Hello Gophers!\0",
+//   "This is a test.\0",
+// }
+
+package main
+
+func main() {}
diff --git a/src/cmd/link/testdata/testPErsrc/rsrc.syso b/src/cmd/link/testdata/testPErsrc/rsrc.syso
new file mode 100644
index 0000000..0d9699d
--- /dev/null
+++ b/src/cmd/link/testdata/testPErsrc/rsrc.syso
Binary files differ