}
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
// 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()
}
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:
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))
// 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.
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)
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
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")
}
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
}
//
//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.
}
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)