diff options
Diffstat (limited to 'src/cmd')
| -rw-r--r-- | src/cmd/internal/obj/x86/seh.go | 36 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/seh.go | 13 |
2 files changed, 42 insertions, 7 deletions
diff --git a/src/cmd/internal/obj/x86/seh.go b/src/cmd/internal/obj/x86/seh.go index e7d3d571b7..71cdd36642 100644 --- a/src/cmd/internal/obj/x86/seh.go +++ b/src/cmd/internal/obj/x86/seh.go @@ -97,17 +97,32 @@ func populateSeh(ctxt *obj.Link, s *obj.LSym) (sehsym *obj.LSym) { // https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-unwind_info const ( - UWOP_PUSH_NONVOL = 0 - UWOP_SET_FPREG = 3 - SEH_REG_BP = 5 + UWOP_PUSH_NONVOL = 0 + UWOP_SET_FPREG = 3 + SEH_REG_BP = 5 + UNW_FLAG_EHANDLER = 1 << 3 ) + var exceptionHandler *obj.LSym + var flags uint8 + if s.Name == "runtime.asmcgocall_landingpad" { + // Most cgo calls go through runtime.asmcgocall_landingpad, + // we can use it to catch exceptions from C code. + // TODO: use a more generic approach to identify which calls need an exception handler. + exceptionHandler = ctxt.Lookup("runtime.sehtramp") + if exceptionHandler == nil { + ctxt.Diag("missing runtime.sehtramp\n") + return + } + flags = UNW_FLAG_EHANDLER + } + // Fow now we only support operations which are encoded // using a single 2-byte node, so the number of nodes // is the number of operations. nodes := uint8(2) buf := newsehbuf(ctxt, nodes) - buf.write8(1) // Flags + version + buf.write8(flags | 1) // Flags + version buf.write8(uint8(movbp.Link.Pc)) // Size of prolog buf.write8(nodes) // Count of nodes buf.write8(SEH_REG_BP) // FP register @@ -119,8 +134,10 @@ func populateSeh(ctxt *obj.Link, s *obj.LSym) (sehsym *obj.LSym) { buf.write8(uint8(pushbp.Link.Pc)) buf.writecode(UWOP_PUSH_NONVOL, SEH_REG_BP) - // The following 4 bytes reference the RVA of the exception handler, - // in case the function has one. We don't use it for now. + // The following 4 bytes reference the RVA of the exception handler. + // The value is set to 0 for now, if an exception handler is needed, + // it will be updated later with a R_PEIMAGEOFF relocation to the + // exception handler. buf.write32(0) // The list of unwind infos in a PE binary have very low cardinality @@ -134,6 +151,13 @@ func populateSeh(ctxt *obj.Link, s *obj.LSym) (sehsym *obj.LSym) { s.Type = objabi.SSEHUNWINDINFO s.Set(obj.AttrDuplicateOK, true) s.Set(obj.AttrLocal, true) + if exceptionHandler != nil { + r := obj.Addrel(s) + r.Off = int32(len(buf.data) - 4) + r.Siz = 4 + r.Sym = exceptionHandler + r.Type = objabi.R_PEIMAGEOFF + } // Note: AttrContentAddressable cannot be set here, // because the content-addressable-handling code // does not know about aux symbols. diff --git a/src/cmd/link/internal/ld/seh.go b/src/cmd/link/internal/ld/seh.go index 5379528c30..43b5176a53 100644 --- a/src/cmd/link/internal/ld/seh.go +++ b/src/cmd/link/internal/ld/seh.go @@ -40,7 +40,7 @@ func writeSEHAMD64(ctxt *Link) { // to deduplicate .xdata entries. uwcache := make(map[string]int64) // aux symbol name --> .xdata offset for _, s := range ctxt.Textp { - if fi := ldr.FuncInfo(s); !fi.Valid() || fi.TopFrame() { + if fi := ldr.FuncInfo(s); !fi.Valid() { continue } uw := ldr.SEHUnwindSym(s) @@ -53,6 +53,17 @@ func writeSEHAMD64(ctxt *Link) { off = xdata.Size() uwcache[name] = off xdata.AddBytes(ldr.Data(uw)) + // The SEH unwind data can contain relocations, + // make sure those are copied over. + rels := ldr.Relocs(uw) + for i := 0; i < rels.Count(); i++ { + r := rels.At(i) + rel, _ := xdata.AddRel(r.Type()) + rel.SetOff(int32(off) + r.Off()) + rel.SetSiz(r.Siz()) + rel.SetSym(r.Sym()) + rel.SetAdd(r.Add()) + } } // Reference: |
