{"record":{"id":"9a61946f5ad2cb94","repo":"golang/go","slug":"s-and-s-symbols-must-be-in-the-same-section","errorCode":null,"errorMessage":"%s and %s symbols must be in the same section","messagePattern":"(.+?) and (.+?) symbols must be in the same section","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/internal/objfile/pe.go","lineNumber":179,"sourceCode":"\t\tif len(f.Sections) < int(s.SectionNumber) {\n\t\t\treturn nil, fmt.Errorf(\"symbol %s: section number %d is larger than max %d\", name, s.SectionNumber, len(f.Sections))\n\t\t}\n\t\treturn s, nil\n\t}\n\treturn nil, fmt.Errorf(\"no %s symbol found\", name)\n}\n\nfunc loadPETable(f *pe.File, sname, ename string) ([]byte, error) {\n\tssym, err := findPESymbol(f, sname)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tesym, err := findPESymbol(f, ename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif ssym.SectionNumber != esym.SectionNumber {\n\t\treturn nil, fmt.Errorf(\"%s and %s symbols must be in the same section\", sname, ename)\n\t}\n\tsect := f.Sections[ssym.SectionNumber-1]\n\tdata, err := sect.Data()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn data[ssym.Value:esym.Value], nil\n}\n\nfunc (f *peFile) goarch() string {\n\tswitch f.pe.Machine {\n\tcase pe.IMAGE_FILE_MACHINE_I386:\n\t\treturn \"386\"\n\tcase pe.IMAGE_FILE_MACHINE_AMD64:\n\t\treturn \"amd64\"\n\tcase pe.IMAGE_FILE_MACHINE_ARM64:\n\t\treturn \"arm64\"\n\tdefault:","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/internal/objfile/pe.go#L161-L197","documentation":"loadPETable extracts a byte table from a PE (Windows) binary by slicing the section data between a start symbol's Value and an end symbol's Value. Because the slice is computed against a single section's Data(), both symbols must live in the same PE section; if they do not, the offsets are meaningless and could even panic on a bad slice. The library therefore refuses the operation rather than return garbage. This fires during pclntab/funcdata extraction from a Go PE binary (used by go tool nm, objdump, pprof).","triggerScenarios":"Calling loadPETable (directly or via pclntab loading) where findPESymbol(sname).SectionNumber != findPESymbol(ename).SectionNumber — e.g. 'runtime.pclntab' and 'runtime.epclntab' resolved to different PE sections.","commonSituations":"Inspecting a Windows .exe that was post-processed by objcopy/stripping tools that re-laid-out sections, a corrupted PE binary, or a hand-crafted/merged object file. Also possible if the wrong start/end symbol pair is requested for the binary's Go version.","solutions":["Rebuild the Windows binary with a stock 'go build' and avoid objcopy/manual section manipulation.","Confirm the binary was produced by the Go toolchain for GOOS=windows and has not been stripped of pclntab.","If you only need symbols, try 'go tool nm' on the original object file before linking instead of the final .exe."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// data, err := loadPETable(pe, \"runtime.pclntab\", \"runtime.epclntab\")\n// if err != nil {\n//     if strings.Contains(err.Error(), \"must be in the same section\") {\n//         // binary is unsuitable for table extraction; fall back to symbol-only tooling\n//     }\n//     return err\n// }","preventionTips":["Only feed stock 'go build' Windows binaries to objfile-based tools.","Avoid objcopy/manual section manipulation on Go .exe files.","Keep pclntab/epclntab symbols intact (do not strip aggressively)."],"tags":["pe","windows","binary","objfile","go-toolchain","pclntab"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}