pkg/tools/elf/abi.go (112 lines of code) (raw):
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package elf
import (
"fmt"
"strings"
)
type ArgLocation struct {
Type LocationType
Offset uint64
}
type ArgumentLocator interface {
// GetLocation of the argument
GetLocation(typeClass TypeClass, typeSize uint64, alignmentSize uint64, primitivesCount int, isRetArg bool) (*ArgLocation, error)
}
func NewArgumentLocator(r *DwarfReader) ArgumentLocator {
if r.language == ReaderLanguageGolang {
// is register-based ABI
// example: "Go cmd/comile go1.18; regabi"
if strings.Contains(r.producer, "regabi") {
return newGolangRegisterLocator()
}
return &GolangStackLocator{}
}
return &UnknownLocator{language: r.language}
}
type GolangRegisterLocator struct {
curStackOffset uint64
curIntArgOffset uint64
curFloatArgOffset uint64
curIntRetArgOffset uint64
curFloatRetArgOffset uint64
intArgRegisters []RegisterName
floatArgRegisters []RegisterName
intRetArgRegisters []RegisterName
floatRetArgRegisters []RegisterName
}
func newGolangRegisterLocator() *GolangRegisterLocator {
intRegisters := []RegisterName{
RegisterNameRAX, RegisterNameRBX, RegisterNameRCX,
RegisterNameRDI, RegisterNameRSI, RegisterNameR8,
RegisterNameR9, RegisterNameR10, RegisterNameR11,
}
floatRegisters := []RegisterName{
RegisterNameXMM0, RegisterNameXMM1, RegisterNameXMM2,
RegisterNameXMM3, RegisterNameXMM4, RegisterNameXMM5,
RegisterNameXMM6, RegisterNameXMM7, RegisterNameXMM8,
RegisterNameXMM9, RegisterNameXMM10, RegisterNameXMM11,
RegisterNameXMM12, RegisterNameXMM13, RegisterNameXMM14,
}
return &GolangRegisterLocator{
intArgRegisters: intRegisters,
floatArgRegisters: floatRegisters,
intRetArgRegisters: intRegisters,
floatRetArgRegisters: floatRegisters,
}
}
func (g *GolangRegisterLocator) GetLocation(typeClass TypeClass, typeSize, alignmentSize uint64, primitivesCount int,
isRetArg bool) (*ArgLocation, error) {
var registers []RegisterName
var offset *uint64
if typeClass == TypeClassInteger {
if isRetArg {
registers = g.intRetArgRegisters
offset = &g.curIntRetArgOffset
} else {
registers = g.intArgRegisters
offset = &g.curIntArgOffset
}
} else if typeClass == TypeClassFloat {
if isRetArg {
registers = g.floatRetArgRegisters
offset = &g.curFloatRetArgOffset
} else {
registers = g.floatArgRegisters
offset = &g.curFloatArgOffset
}
} else {
return nil, fmt.Errorf("unsupport type classs for getting location, type class: %d", typeClass)
}
result := &ArgLocation{}
if primitivesCount <= len(registers) {
if typeClass == TypeClassInteger {
result.Type = ArgLocationTypeRegister
} else {
result.Type = ArgLocationTypeRegisterFP
}
result.Offset = *offset
*offset += uint64(primitivesCount * 8)
} else {
g.curStackOffset = snapUpToMultiple(g.curStackOffset, alignmentSize)
result.Type = ArgLocationTypeStack
result.Offset = g.curStackOffset
g.curStackOffset += typeSize
}
return result, nil
}
type GolangStackLocator struct {
curStackOffset uint64
}
func (g *GolangStackLocator) GetLocation(_ TypeClass, typeSize, alignmentSize uint64, _ int, _ bool) (*ArgLocation, error) {
g.curStackOffset = snapUpToMultiple(g.curStackOffset, alignmentSize)
result := &ArgLocation{}
result.Type = ArgLocationTypeStack
result.Offset = g.curStackOffset
g.curStackOffset += typeSize
return result, nil
}
type UnknownLocator struct {
language int
}
func (u *UnknownLocator) GetLocation(typeClass TypeClass, typeSize, alignmentSize uint64, primitivesCount int, isRetArg bool) (*ArgLocation, error) {
return nil, fmt.Errorf("unknown locator for language: %d", u.language)
}
func snapUpToMultiple(curSize, alignmentSize uint64) uint64 {
return ((curSize + (alignmentSize - 1)) / alignmentSize) * alignmentSize
}