diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go index 1cd84d5727..ef4ae352fe 100644 --- a/src/debug/pe/file.go +++ b/src/debug/pe/file.go @@ -158,7 +158,11 @@ func NewFile(r io.ReaderAt) (*File, error) { NumberOfLineNumbers: sh.NumberOfLineNumbers, Characteristics: sh.Characteristics, } - s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size)) + r2 := r + if sh.PointerToRawData == 0 { // .bss must have all 0s + r2 = zeroReaderAt{} + } + s.sr = io.NewSectionReader(r2, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size)) s.ReaderAt = s.sr f.Sections[i] = s } @@ -173,6 +177,17 @@ func NewFile(r io.ReaderAt) (*File, error) { return f, nil } +// zeroReaderAt is ReaderAt that reads 0s. +type zeroReaderAt struct{} + +// ReadAt writes len(p) 0s into p. +func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) { + for i := range p { + p[i] = 0 + } + return len(p), nil +} + // getString extracts a string from symbol string table. func getString(section []byte, start int) (string, bool) { if start < 0 || start >= len(section) { diff --git a/src/debug/pe/file_test.go b/src/debug/pe/file_test.go index 7367b982e2..12059b5eff 100644 --- a/src/debug/pe/file_test.go +++ b/src/debug/pe/file_test.go @@ -6,6 +6,7 @@ package pe import ( "debug/dwarf" + "internal/testenv" "io/ioutil" "os" "os/exec" @@ -307,3 +308,75 @@ func main() { } t.Fatal("main.main not found") } + +func TestBSSHasZeros(t *testing.T) { + testenv.MustHaveExec(t) + + if runtime.GOOS != "windows" { + t.Skip("skipping windows only test") + } + gccpath, err := exec.LookPath("gcc") + if err != nil { + t.Skip("skipping test: gcc is missing") + } + + tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + + srcpath := filepath.Join(tmpdir, "a.c") + src := ` +#include + +int zero = 0; + +int +main(void) +{ + printf("%d\n", zero); + return 0; +} +` + err = ioutil.WriteFile(srcpath, []byte(src), 0644) + if err != nil { + t.Fatal(err) + } + + objpath := filepath.Join(tmpdir, "a.obj") + cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("failed to build object file: %v - %v", err, string(out)) + } + + f, err := Open(objpath) + if err != nil { + t.Fatal(err) + } + defer f.Close() + + var bss *Section + for _, sect := range f.Sections { + if sect.Name == ".bss" { + bss = sect + break + } + } + if bss == nil { + t.Fatal("could not find .bss section") + } + data, err := bss.Data() + if err != nil { + t.Fatal(err) + } + if len(data) == 0 { + t.Fatalf("%s file .bss section cannot be empty", objpath) + } + for _, b := range data { + if b != 0 { + t.Fatalf(".bss section has non zero bytes: %v", data) + } + } +}