github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/assembler/assembler.go (about)

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package assembler
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/go-asm/go/cmd/asm/arch"
    11  	"github.com/go-asm/go/cmd/obj"
    12  	"github.com/go-asm/go/cmd/objabi"
    13  )
    14  
    15  // Builder allows you to assemble a series of instructions.
    16  type Builder struct {
    17  	ctxt *obj.Link
    18  	arch *arch.Arch
    19  
    20  	first *obj.Prog
    21  	last  *obj.Prog
    22  
    23  	// bulk allocator.
    24  	block *[]obj.Prog
    25  	used  int
    26  }
    27  
    28  // Root returns the first instruction.
    29  func (b *Builder) Root() *obj.Prog {
    30  	return b.first
    31  }
    32  
    33  // NewProg returns a new instruction structure.
    34  func (b *Builder) NewProg() *obj.Prog {
    35  	return b.progAlloc()
    36  }
    37  
    38  func (b *Builder) progAlloc() *obj.Prog {
    39  	var p *obj.Prog
    40  
    41  	if b.used >= len(*b.block) {
    42  		p = b.ctxt.NewProg()
    43  	} else {
    44  		p = &(*b.block)[b.used]
    45  		b.used++
    46  	}
    47  
    48  	p.Ctxt = b.ctxt
    49  	return p
    50  }
    51  
    52  // AddInstruction adds an instruction to the list of instructions
    53  // to be assembled.
    54  func (b *Builder) AddInstruction(p *obj.Prog) {
    55  	if b.first == nil {
    56  		b.first = p
    57  		b.last = p
    58  	} else {
    59  		b.last.Link = p
    60  		b.last = p
    61  	}
    62  }
    63  
    64  // Assemble generates the machine code from the given instructions.
    65  func (b *Builder) Assemble() []byte {
    66  	s := &obj.LSym{}
    67  	s.Extra = new(interface{})
    68  	*s.Extra = &obj.FuncInfo{
    69  		Text: b.first,
    70  	}
    71  	b.arch.Assemble(b.ctxt, s, b.progAlloc)
    72  
    73  	return s.P
    74  }
    75  
    76  // NewBuilder constructs an assembler for the given architecture.
    77  func NewBuilder(archStr string, cacheSize int) (*Builder, error) {
    78  	a := arch.Set(archStr, false)
    79  	ctxt := obj.Linknew(a.LinkArch)
    80  	ctxt.Headtype = objabi.Hlinux
    81  	ctxt.DiagFunc = func(in string, args ...interface{}) {
    82  		fmt.Printf(in+"\n", args...)
    83  	}
    84  	a.Init(ctxt)
    85  
    86  	block := make([]obj.Prog, cacheSize)
    87  
    88  	b := &Builder{
    89  		ctxt:  ctxt,
    90  		arch:  a,
    91  		block: &block,
    92  	}
    93  
    94  	return b, nil
    95  }