diff options
| -rw-r--r-- | src/cmd/internal/obj/wasm/wasmobj.go | 3 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/data.go | 17 | ||||
| -rw-r--r-- | src/cmd/link/internal/ld/pcln.go | 43 | ||||
| -rw-r--r-- | src/runtime/symtab.go | 32 |
4 files changed, 77 insertions, 18 deletions
diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go index e8bf927a82..3f9243613e 100644 --- a/src/cmd/internal/obj/wasm/wasmobj.go +++ b/src/cmd/internal/obj/wasm/wasmobj.go @@ -372,6 +372,9 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { } tableIdxs = append(tableIdxs, uint64(numResumePoints)) s.Size = pc + 1 + if pc >= 1<<16 { + ctxt.Diag("function too big: %s exceeds 65536 blocks", s) + } if needMoreStack { p := pMorestack diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 42756e86bb..138547a3d3 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -496,6 +496,15 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { // to the start of the first text section, even if there are multiple. if sect.Name == ".text" { o = ldr.SymValue(rs) - int64(Segtext.Sections[0].Vaddr) + r.Add() + if target.IsWasm() { + // On Wasm, textoff (e.g. in the method table) is just the function index, + // whereas the "PC" (rs's Value) is function index << 16 + block index (see + // ../wasm/asm.go:assignAddress). + if o&(1<<16-1) != 0 { + st.err.Errorf(s, "textoff relocation %s does not target function entry: %s %#x", rt, ldr.SymName(rs), o) + } + o >>= 16 + } } else { o = ldr.SymValue(rs) - int64(ldr.SymSect(rs).Vaddr) + r.Add() } @@ -606,16 +615,16 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { P[off] = byte(int8(o)) case 2: if (rt == objabi.R_PCREL || rt == objabi.R_CALL) && o != int64(int16(o)) { - st.err.Errorf(s, "pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), o) + st.err.Errorf(s, "pc-relative relocation %s address for %s is too big: %#x", rt, ldr.SymName(rs), o) } else if o != int64(int16(o)) && o != int64(uint16(o)) { - st.err.Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), uint64(o)) + st.err.Errorf(s, "non-pc-relative relocation %s address for %s is too big: %#x", rt, ldr.SymName(rs), uint64(o)) } target.Arch.ByteOrder.PutUint16(P[off:], uint16(o)) case 4: if (rt == objabi.R_PCREL || rt == objabi.R_CALL) && o != int64(int32(o)) { - st.err.Errorf(s, "pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), o) + st.err.Errorf(s, "pc-relative relocation %s address for %s is too big: %#x", rt, ldr.SymName(rs), o) } else if o != int64(int32(o)) && o != int64(uint32(o)) { - st.err.Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), uint64(o)) + st.err.Errorf(s, "non-pc-relative relocation %s address for %s is too big: %#x", rt, ldr.SymName(rs), uint64(o)) } target.Arch.ByteOrder.PutUint32(P[off:], uint32(o)) case 8: diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index a09d3acd5e..9532b33a9b 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -614,16 +614,36 @@ func (state pclntab) calculateFunctabSize(ctxt *Link, funcs []loader.Sym) (int64 return size, startLocations } +// textOff computes the offset of a text symbol, relative to textStart, +// similar to an R_ADDROFF relocation, for various runtime metadata and +// tables (see runtime/symtab.go:(*moduledata).textAddr). +func textOff(ctxt *Link, s loader.Sym, textStart int64) uint32 { + ldr := ctxt.loader + off := ldr.SymValue(s) - textStart + if off < 0 { + panic(fmt.Sprintf("expected func %s(%x) to be placed at or after textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart)) + } + if ctxt.IsWasm() { + // On Wasm, the function table contains just the function index, whereas + // the "PC" (s's Value) is function index << 16 + block index (see + // ../wasm/asm.go:assignAddress). + if off&(1<<16-1) != 0 { + ctxt.Errorf(s, "nonzero PC_B at function entry: %#x", off) + } + off >>= 16 + } + if int64(uint32(off)) != off { + ctxt.Errorf(s, "textOff overflow: %#x", off) + } + return uint32(off) +} + // writePCToFunc writes the PC->func lookup table. func writePCToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, startLocations []uint32) { ldr := ctxt.loader textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0)) pcOff := func(s loader.Sym) uint32 { - off := ldr.SymValue(s) - textStart - if off < 0 { - panic(fmt.Sprintf("expected func %s(%x) to be placed at or after textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart)) - } - return uint32(off) + return textOff(ctxt, s, textStart) } for i, s := range funcs { sb.SetUint32(ctxt.Arch, int64(i*2*4), pcOff(s)) @@ -632,7 +652,11 @@ func writePCToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, sta // Final entry of table is just end pc offset. lastFunc := funcs[len(funcs)-1] - sb.SetUint32(ctxt.Arch, int64(len(funcs))*2*4, pcOff(lastFunc)+uint32(ldr.SymSize(lastFunc))) + lastPC := pcOff(lastFunc) + uint32(ldr.SymSize(lastFunc)) + if ctxt.IsWasm() { + lastPC = pcOff(lastFunc) + 1 // On Wasm it is function index (see above) + } + sb.SetUint32(ctxt.Arch, int64(len(funcs))*2*4, lastPC) } // writeFuncs writes the func structures and pcdata to runtime.functab. @@ -646,7 +670,7 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym var pcsp, pcfile, pcline, pcinline loader.Sym var pcdata []loader.Sym - // Write the individual func objects. + // Write the individual func objects (runtime._func struct). for i, s := range funcs { startLine := int32(0) fi := ldr.FuncInfo(s) @@ -658,10 +682,7 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym off := int64(startLocations[i]) // entryOff uint32 (offset of func entry PC from textStart) - entryOff := ldr.SymValue(s) - textStart - if entryOff < 0 { - panic(fmt.Sprintf("expected func %s(%x) to be placed before or at textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart)) - } + entryOff := textOff(ctxt, s, textStart) off = sb.SetUint32(ctxt.Arch, off, uint32(entryOff)) // nameOff int32 diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 866c46a83d..56f2a00d76 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -647,8 +647,15 @@ func moduledataverify1(datap *moduledata) { min := datap.textAddr(datap.ftab[0].entryoff) max := datap.textAddr(datap.ftab[nftab].entryoff) - if datap.minpc != min || datap.maxpc != max { - println("minpc=", hex(datap.minpc), "min=", hex(min), "maxpc=", hex(datap.maxpc), "max=", hex(max)) + minpc := datap.minpc + maxpc := datap.maxpc + if GOARCH == "wasm" { + // On Wasm, the func table contains the function index, whereas + // the "PC" is function index << 16 + block index. + maxpc = alignUp(maxpc, 1<<16) // round up for end PC + } + if minpc != min || maxpc != max { + println("minpc=", hex(minpc), "min=", hex(min), "maxpc=", hex(maxpc), "max=", hex(max)) throw("minpc or maxpc invalid") } @@ -694,6 +701,11 @@ func (md *moduledata) textAddr(off32 uint32) uintptr { throw("runtime: text offset out of range") } } + if GOARCH == "wasm" { + // On Wasm, a text offset (e.g. in the method table) is function index, whereas + // the "PC" is function index << 16 + block index. + res <<= 16 + } return res } @@ -704,8 +716,17 @@ func (md *moduledata) textAddr(off32 uint32) uintptr { // //go:nosplit func (md *moduledata) textOff(pc uintptr) (uint32, bool) { - res := uint32(pc - md.text) + off := pc - md.text + if GOARCH == "wasm" { + // On Wasm, the func table contains the function index, whereas + // the "PC" is function index << 16 + block index. + off >>= 16 + } + res := uint32(off) if len(md.textsectmap) > 1 { + if GOARCH == "wasm" { + fatal("unexpected multiple text sections on Wasm") + } for i, sect := range md.textsectmap { if sect.baseaddr > pc { // pc is not in any section. @@ -904,6 +925,11 @@ func findfunc(pc uintptr) funcInfo { } x := uintptr(pcOff) + datap.text - datap.minpc // TODO: are datap.text and datap.minpc always equal? + if GOARCH == "wasm" { + // On Wasm, pcOff is the function index, whereas + // the "PC" is function index << 16 + block index. + x = uintptr(pcOff)<<16 + datap.text - datap.minpc + } b := x / abi.FuncTabBucketSize i := x % abi.FuncTabBucketSize / (abi.FuncTabBucketSize / nsub) |
