// asmb writes the final WebAssembly module binary.
// Spec: https://webassembly.github.io/spec/core/binary/modules.html
-func asmb2(ctxt *ld.Link) {
+func asmb2(ctxt *ld.Link, ldr *loader.Loader) {
types := []*wasmFuncType{
// For normal Go functions, the single parameter is PC_B,
// the return value is
Type: lookupType(&wasmFuncType{Params: []byte{I32}}, &types),
},
}
- hostImportMap := make(map[*sym.Symbol]int64)
- for _, fn := range ctxt.Textp {
- for _, r := range fn.R {
- if r.Type == objabi.R_WASMIMPORT {
- hostImportMap[r.Sym] = int64(len(hostImports))
+ hostImportMap := make(map[loader.Sym]int64)
+ for _, fn := range ctxt.Textp2 {
+ relocs := ldr.Relocs(fn)
+ for ri := 0; ri < relocs.Count(); ri++ {
+ r := relocs.At2(ri)
+ if r.Type() == objabi.R_WASMIMPORT {
+ hostImportMap[r.Sym()] = int64(len(hostImports))
hostImports = append(hostImports, &wasmFunc{
- Name: r.Sym.Name,
+ Name: ldr.SymName(r.Sym()),
Type: lookupType(&wasmFuncType{Params: []byte{I32}}, &types),
})
}
// collect functions with WebAssembly body
var buildid []byte
- fns := make([]*wasmFunc, len(ctxt.Textp))
- for i, fn := range ctxt.Textp {
+ fns := make([]*wasmFunc, len(ctxt.Textp2))
+ for i, fn := range ctxt.Textp2 {
wfn := new(bytes.Buffer)
- if fn.Name == "go.buildid" {
+ if ldr.SymName(fn) == "go.buildid" {
writeUleb128(wfn, 0) // number of sets of locals
writeI32Const(wfn, 0)
wfn.WriteByte(0x0b) // end
- buildid = fn.P
+ buildid = ldr.Data(fn)
} else {
// Relocations have variable length, handle them here.
+ relocs := ldr.Relocs(fn)
+ P := ldr.Data(fn)
off := int32(0)
- for _, r := range fn.R {
- wfn.Write(fn.P[off:r.Off])
- off = r.Off
- switch r.Type {
+ for ri := 0; ri < relocs.Count(); ri++ {
+ r := relocs.At2(ri)
+ wfn.Write(P[off:r.Off()])
+ off = r.Off()
+ rs := ldr.ResolveABIAlias(r.Sym())
+ switch r.Type() {
case objabi.R_ADDR:
- writeSleb128(wfn, r.Sym.Value+r.Add)
+ writeSleb128(wfn, ldr.SymValue(rs)+r.Add())
case objabi.R_CALL:
- writeSleb128(wfn, int64(len(hostImports))+r.Sym.Value>>16-funcValueOffset)
+ writeSleb128(wfn, int64(len(hostImports))+ldr.SymValue(rs)>>16-funcValueOffset)
case objabi.R_WASMIMPORT:
- writeSleb128(wfn, hostImportMap[r.Sym])
+ writeSleb128(wfn, hostImportMap[rs])
default:
- ld.Errorf(fn, "bad reloc type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
+ ldr.Errorf(fn, "bad reloc type %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()))
continue
}
}
- wfn.Write(fn.P[off:])
+ wfn.Write(P[off:])
}
typ := uint32(0)
- if sig, ok := wasmFuncTypes[fn.Name]; ok {
+ if sig, ok := wasmFuncTypes[ldr.SymName(fn)]; ok {
typ = lookupType(sig, &types)
}
- name := nameRegexp.ReplaceAllString(fn.Name, "_")
+ name := nameRegexp.ReplaceAllString(ldr.SymName(fn), "_")
fns[i] = &wasmFunc{Name: name, Type: typ, Code: wfn.Bytes()}
}
writeImportSec(ctxt, hostImports)
writeFunctionSec(ctxt, fns)
writeTableSec(ctxt, fns)
- writeMemorySec(ctxt)
+ writeMemorySec(ctxt, ldr)
writeGlobalSec(ctxt)
- writeExportSec(ctxt, len(hostImports))
+ writeExportSec(ctxt, ldr, len(hostImports))
writeElementSec(ctxt, uint64(len(hostImports)), uint64(len(fns)))
writeCodeSec(ctxt, fns)
writeDataSec(ctxt)
// writeMemorySec writes the section that declares linear memories. Currently one linear memory is being used.
// Linear memory always starts at address zero. More memory can be requested with the GrowMemory instruction.
-func writeMemorySec(ctxt *ld.Link) {
+func writeMemorySec(ctxt *ld.Link, ldr *loader.Loader) {
sizeOffset := writeSecHeader(ctxt, sectionMemory)
- dataSection := ctxt.Syms.Lookup("runtime.data", 0).Sect
+ dataSection := ldr.SymSect(ldr.Lookup("runtime.data", 0))
dataEnd := dataSection.Vaddr + dataSection.Length
var initialSize = dataEnd + 16<<20 // 16MB, enough for runtime init without growing
// writeExportSec writes the section that declares exports.
// Exports can be accessed by the WebAssembly host, usually JavaScript.
// The wasm_export_* functions and the linear memory get exported.
-func writeExportSec(ctxt *ld.Link, lenHostImports int) {
+func writeExportSec(ctxt *ld.Link, ldr *loader.Loader, lenHostImports int) {
sizeOffset := writeSecHeader(ctxt, sectionExport)
writeUleb128(ctxt.Out, 4) // number of exports
for _, name := range []string{"run", "resume", "getsp"} {
- idx := uint32(lenHostImports) + uint32(ctxt.Syms.ROLookup("wasm_export_"+name, 0).Value>>16) - funcValueOffset
+ s := ldr.Lookup("wasm_export_"+name, 0)
+ idx := uint32(lenHostImports) + uint32(ldr.SymValue(s)>>16) - funcValueOffset
writeName(ctxt.Out, name) // inst.exports.run/resume/getsp in wasm_exec.js
ctxt.Out.WriteByte(0x00) // func export
writeUleb128(ctxt.Out, uint64(idx)) // funcidx