[chore] Update gin to v1.9.0 (#1553)

This commit is contained in:
Daenney
2023-02-25 13:12:40 +01:00
committed by GitHub
parent 689a10fe17
commit ecdc8379fa
347 changed files with 166814 additions and 3671 deletions

27
vendor/github.com/twitchyliquid64/golang-asm/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,716 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package arch defines architecture-specific information and support functions.
package arch
import (
"github.com/twitchyliquid64/golang-asm/obj"
"github.com/twitchyliquid64/golang-asm/obj/arm"
"github.com/twitchyliquid64/golang-asm/obj/arm64"
"github.com/twitchyliquid64/golang-asm/obj/mips"
"github.com/twitchyliquid64/golang-asm/obj/ppc64"
"github.com/twitchyliquid64/golang-asm/obj/riscv"
"github.com/twitchyliquid64/golang-asm/obj/s390x"
"github.com/twitchyliquid64/golang-asm/obj/wasm"
"github.com/twitchyliquid64/golang-asm/obj/x86"
"fmt"
"strings"
)
// Pseudo-registers whose names are the constant name without the leading R.
const (
RFP = -(iota + 1)
RSB
RSP
RPC
)
// Arch wraps the link architecture object with more architecture-specific information.
type Arch struct {
*obj.LinkArch
// Map of instruction names to enumeration.
Instructions map[string]obj.As
// Map of register names to enumeration.
Register map[string]int16
// Table of register prefix names. These are things like R for R(0) and SPR for SPR(268).
RegisterPrefix map[string]bool
// RegisterNumber converts R(10) into arm.REG_R10.
RegisterNumber func(string, int16) (int16, bool)
// Instruction is a jump.
IsJump func(word string) bool
}
// nilRegisterNumber is the register number function for architectures
// that do not accept the R(N) notation. It always returns failure.
func nilRegisterNumber(name string, n int16) (int16, bool) {
return 0, false
}
// Set configures the architecture specified by GOARCH and returns its representation.
// It returns nil if GOARCH is not recognized.
func Set(GOARCH string) *Arch {
switch GOARCH {
case "386":
return archX86(&x86.Link386)
case "amd64":
return archX86(&x86.Linkamd64)
case "arm":
return archArm()
case "arm64":
return archArm64()
case "mips":
return archMips(&mips.Linkmips)
case "mipsle":
return archMips(&mips.Linkmipsle)
case "mips64":
return archMips64(&mips.Linkmips64)
case "mips64le":
return archMips64(&mips.Linkmips64le)
case "ppc64":
return archPPC64(&ppc64.Linkppc64)
case "ppc64le":
return archPPC64(&ppc64.Linkppc64le)
case "riscv64":
return archRISCV64()
case "s390x":
return archS390x()
case "wasm":
return archWasm()
}
return nil
}
func jumpX86(word string) bool {
return word[0] == 'J' || word == "CALL" || strings.HasPrefix(word, "LOOP") || word == "XBEGIN"
}
func jumpRISCV(word string) bool {
switch word {
case "BEQ", "BEQZ", "BGE", "BGEU", "BGEZ", "BGT", "BGTU", "BGTZ", "BLE", "BLEU", "BLEZ",
"BLT", "BLTU", "BLTZ", "BNE", "BNEZ", "CALL", "JAL", "JALR", "JMP":
return true
}
return false
}
func jumpWasm(word string) bool {
return word == "JMP" || word == "CALL" || word == "Call" || word == "Br" || word == "BrIf"
}
func archX86(linkArch *obj.LinkArch) *Arch {
register := make(map[string]int16)
// Create maps for easy lookup of instruction names etc.
for i, s := range x86.Register {
register[s] = int16(i + x86.REG_AL)
}
// Pseudo-registers.
register["SB"] = RSB
register["FP"] = RFP
register["PC"] = RPC
// Register prefix not used on this architecture.
instructions := make(map[string]obj.As)
for i, s := range obj.Anames {
instructions[s] = obj.As(i)
}
for i, s := range x86.Anames {
if obj.As(i) >= obj.A_ARCHSPECIFIC {
instructions[s] = obj.As(i) + obj.ABaseAMD64
}
}
// Annoying aliases.
instructions["JA"] = x86.AJHI /* alternate */
instructions["JAE"] = x86.AJCC /* alternate */
instructions["JB"] = x86.AJCS /* alternate */
instructions["JBE"] = x86.AJLS /* alternate */
instructions["JC"] = x86.AJCS /* alternate */
instructions["JCC"] = x86.AJCC /* carry clear (CF = 0) */
instructions["JCS"] = x86.AJCS /* carry set (CF = 1) */
instructions["JE"] = x86.AJEQ /* alternate */
instructions["JEQ"] = x86.AJEQ /* equal (ZF = 1) */
instructions["JG"] = x86.AJGT /* alternate */
instructions["JGE"] = x86.AJGE /* greater than or equal (signed) (SF = OF) */
instructions["JGT"] = x86.AJGT /* greater than (signed) (ZF = 0 && SF = OF) */
instructions["JHI"] = x86.AJHI /* higher (unsigned) (CF = 0 && ZF = 0) */
instructions["JHS"] = x86.AJCC /* alternate */
instructions["JL"] = x86.AJLT /* alternate */
instructions["JLE"] = x86.AJLE /* less than or equal (signed) (ZF = 1 || SF != OF) */
instructions["JLO"] = x86.AJCS /* alternate */
instructions["JLS"] = x86.AJLS /* lower or same (unsigned) (CF = 1 || ZF = 1) */
instructions["JLT"] = x86.AJLT /* less than (signed) (SF != OF) */
instructions["JMI"] = x86.AJMI /* negative (minus) (SF = 1) */
instructions["JNA"] = x86.AJLS /* alternate */
instructions["JNAE"] = x86.AJCS /* alternate */
instructions["JNB"] = x86.AJCC /* alternate */
instructions["JNBE"] = x86.AJHI /* alternate */
instructions["JNC"] = x86.AJCC /* alternate */
instructions["JNE"] = x86.AJNE /* not equal (ZF = 0) */
instructions["JNG"] = x86.AJLE /* alternate */
instructions["JNGE"] = x86.AJLT /* alternate */
instructions["JNL"] = x86.AJGE /* alternate */
instructions["JNLE"] = x86.AJGT /* alternate */
instructions["JNO"] = x86.AJOC /* alternate */
instructions["JNP"] = x86.AJPC /* alternate */
instructions["JNS"] = x86.AJPL /* alternate */
instructions["JNZ"] = x86.AJNE /* alternate */
instructions["JO"] = x86.AJOS /* alternate */
instructions["JOC"] = x86.AJOC /* overflow clear (OF = 0) */
instructions["JOS"] = x86.AJOS /* overflow set (OF = 1) */
instructions["JP"] = x86.AJPS /* alternate */
instructions["JPC"] = x86.AJPC /* parity clear (PF = 0) */
instructions["JPE"] = x86.AJPS /* alternate */
instructions["JPL"] = x86.AJPL /* non-negative (plus) (SF = 0) */
instructions["JPO"] = x86.AJPC /* alternate */
instructions["JPS"] = x86.AJPS /* parity set (PF = 1) */
instructions["JS"] = x86.AJMI /* alternate */
instructions["JZ"] = x86.AJEQ /* alternate */
instructions["MASKMOVDQU"] = x86.AMASKMOVOU
instructions["MOVD"] = x86.AMOVQ
instructions["MOVDQ2Q"] = x86.AMOVQ
instructions["MOVNTDQ"] = x86.AMOVNTO
instructions["MOVOA"] = x86.AMOVO
instructions["PSLLDQ"] = x86.APSLLO
instructions["PSRLDQ"] = x86.APSRLO
instructions["PADDD"] = x86.APADDL
return &Arch{
LinkArch: linkArch,
Instructions: instructions,
Register: register,
RegisterPrefix: nil,
RegisterNumber: nilRegisterNumber,
IsJump: jumpX86,
}
}
func archArm() *Arch {
register := make(map[string]int16)
// Create maps for easy lookup of instruction names etc.
// Note that there is no list of names as there is for x86.
for i := arm.REG_R0; i < arm.REG_SPSR; i++ {
register[obj.Rconv(i)] = int16(i)
}
// Avoid unintentionally clobbering g using R10.
delete(register, "R10")
register["g"] = arm.REG_R10
for i := 0; i < 16; i++ {
register[fmt.Sprintf("C%d", i)] = int16(i)
}
// Pseudo-registers.
register["SB"] = RSB
register["FP"] = RFP
register["PC"] = RPC
register["SP"] = RSP
registerPrefix := map[string]bool{
"F": true,
"R": true,
}
// special operands for DMB/DSB instructions
register["MB_SY"] = arm.REG_MB_SY
register["MB_ST"] = arm.REG_MB_ST
register["MB_ISH"] = arm.REG_MB_ISH
register["MB_ISHST"] = arm.REG_MB_ISHST
register["MB_NSH"] = arm.REG_MB_NSH
register["MB_NSHST"] = arm.REG_MB_NSHST
register["MB_OSH"] = arm.REG_MB_OSH
register["MB_OSHST"] = arm.REG_MB_OSHST
instructions := make(map[string]obj.As)
for i, s := range obj.Anames {
instructions[s] = obj.As(i)
}
for i, s := range arm.Anames {
if obj.As(i) >= obj.A_ARCHSPECIFIC {
instructions[s] = obj.As(i) + obj.ABaseARM
}
}
// Annoying aliases.
instructions["B"] = obj.AJMP
instructions["BL"] = obj.ACALL
// MCR differs from MRC by the way fields of the word are encoded.
// (Details in arm.go). Here we add the instruction so parse will find
// it, but give it an opcode number known only to us.
instructions["MCR"] = aMCR
return &Arch{
LinkArch: &arm.Linkarm,
Instructions: instructions,
Register: register,
RegisterPrefix: registerPrefix,
RegisterNumber: armRegisterNumber,
IsJump: jumpArm,
}
}
func archArm64() *Arch {
register := make(map[string]int16)
// Create maps for easy lookup of instruction names etc.
// Note that there is no list of names as there is for 386 and amd64.
register[obj.Rconv(arm64.REGSP)] = int16(arm64.REGSP)
for i := arm64.REG_R0; i <= arm64.REG_R31; i++ {
register[obj.Rconv(i)] = int16(i)
}
// Rename R18 to R18_PLATFORM to avoid accidental use.
register["R18_PLATFORM"] = register["R18"]
delete(register, "R18")
for i := arm64.REG_F0; i <= arm64.REG_F31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := arm64.REG_V0; i <= arm64.REG_V31; i++ {
register[obj.Rconv(i)] = int16(i)
}
// System registers.
for i := 0; i < len(arm64.SystemReg); i++ {
register[arm64.SystemReg[i].Name] = arm64.SystemReg[i].Reg
}
register["LR"] = arm64.REGLINK
register["DAIFSet"] = arm64.REG_DAIFSet
register["DAIFClr"] = arm64.REG_DAIFClr
register["PLDL1KEEP"] = arm64.REG_PLDL1KEEP
register["PLDL1STRM"] = arm64.REG_PLDL1STRM
register["PLDL2KEEP"] = arm64.REG_PLDL2KEEP
register["PLDL2STRM"] = arm64.REG_PLDL2STRM
register["PLDL3KEEP"] = arm64.REG_PLDL3KEEP
register["PLDL3STRM"] = arm64.REG_PLDL3STRM
register["PLIL1KEEP"] = arm64.REG_PLIL1KEEP
register["PLIL1STRM"] = arm64.REG_PLIL1STRM
register["PLIL2KEEP"] = arm64.REG_PLIL2KEEP
register["PLIL2STRM"] = arm64.REG_PLIL2STRM
register["PLIL3KEEP"] = arm64.REG_PLIL3KEEP
register["PLIL3STRM"] = arm64.REG_PLIL3STRM
register["PSTL1KEEP"] = arm64.REG_PSTL1KEEP
register["PSTL1STRM"] = arm64.REG_PSTL1STRM
register["PSTL2KEEP"] = arm64.REG_PSTL2KEEP
register["PSTL2STRM"] = arm64.REG_PSTL2STRM
register["PSTL3KEEP"] = arm64.REG_PSTL3KEEP
register["PSTL3STRM"] = arm64.REG_PSTL3STRM
// Conditional operators, like EQ, NE, etc.
register["EQ"] = arm64.COND_EQ
register["NE"] = arm64.COND_NE
register["HS"] = arm64.COND_HS
register["CS"] = arm64.COND_HS
register["LO"] = arm64.COND_LO
register["CC"] = arm64.COND_LO
register["MI"] = arm64.COND_MI
register["PL"] = arm64.COND_PL
register["VS"] = arm64.COND_VS
register["VC"] = arm64.COND_VC
register["HI"] = arm64.COND_HI
register["LS"] = arm64.COND_LS
register["GE"] = arm64.COND_GE
register["LT"] = arm64.COND_LT
register["GT"] = arm64.COND_GT
register["LE"] = arm64.COND_LE
register["AL"] = arm64.COND_AL
register["NV"] = arm64.COND_NV
// Pseudo-registers.
register["SB"] = RSB
register["FP"] = RFP
register["PC"] = RPC
register["SP"] = RSP
// Avoid unintentionally clobbering g using R28.
delete(register, "R28")
register["g"] = arm64.REG_R28
registerPrefix := map[string]bool{
"F": true,
"R": true,
"V": true,
}
instructions := make(map[string]obj.As)
for i, s := range obj.Anames {
instructions[s] = obj.As(i)
}
for i, s := range arm64.Anames {
if obj.As(i) >= obj.A_ARCHSPECIFIC {
instructions[s] = obj.As(i) + obj.ABaseARM64
}
}
// Annoying aliases.
instructions["B"] = arm64.AB
instructions["BL"] = arm64.ABL
return &Arch{
LinkArch: &arm64.Linkarm64,
Instructions: instructions,
Register: register,
RegisterPrefix: registerPrefix,
RegisterNumber: arm64RegisterNumber,
IsJump: jumpArm64,
}
}
func archPPC64(linkArch *obj.LinkArch) *Arch {
register := make(map[string]int16)
// Create maps for easy lookup of instruction names etc.
// Note that there is no list of names as there is for x86.
for i := ppc64.REG_R0; i <= ppc64.REG_R31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := ppc64.REG_F0; i <= ppc64.REG_F31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := ppc64.REG_V0; i <= ppc64.REG_V31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := ppc64.REG_VS0; i <= ppc64.REG_VS63; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := ppc64.REG_CR0; i <= ppc64.REG_CR7; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := ppc64.REG_MSR; i <= ppc64.REG_CR; i++ {
register[obj.Rconv(i)] = int16(i)
}
register["CR"] = ppc64.REG_CR
register["XER"] = ppc64.REG_XER
register["LR"] = ppc64.REG_LR
register["CTR"] = ppc64.REG_CTR
register["FPSCR"] = ppc64.REG_FPSCR
register["MSR"] = ppc64.REG_MSR
// Pseudo-registers.
register["SB"] = RSB
register["FP"] = RFP
register["PC"] = RPC
// Avoid unintentionally clobbering g using R30.
delete(register, "R30")
register["g"] = ppc64.REG_R30
registerPrefix := map[string]bool{
"CR": true,
"F": true,
"R": true,
"SPR": true,
}
instructions := make(map[string]obj.As)
for i, s := range obj.Anames {
instructions[s] = obj.As(i)
}
for i, s := range ppc64.Anames {
if obj.As(i) >= obj.A_ARCHSPECIFIC {
instructions[s] = obj.As(i) + obj.ABasePPC64
}
}
// Annoying aliases.
instructions["BR"] = ppc64.ABR
instructions["BL"] = ppc64.ABL
return &Arch{
LinkArch: linkArch,
Instructions: instructions,
Register: register,
RegisterPrefix: registerPrefix,
RegisterNumber: ppc64RegisterNumber,
IsJump: jumpPPC64,
}
}
func archMips(linkArch *obj.LinkArch) *Arch {
register := make(map[string]int16)
// Create maps for easy lookup of instruction names etc.
// Note that there is no list of names as there is for x86.
for i := mips.REG_R0; i <= mips.REG_R31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := mips.REG_F0; i <= mips.REG_F31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := mips.REG_M0; i <= mips.REG_M31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := mips.REG_FCR0; i <= mips.REG_FCR31; i++ {
register[obj.Rconv(i)] = int16(i)
}
register["HI"] = mips.REG_HI
register["LO"] = mips.REG_LO
// Pseudo-registers.
register["SB"] = RSB
register["FP"] = RFP
register["PC"] = RPC
// Avoid unintentionally clobbering g using R30.
delete(register, "R30")
register["g"] = mips.REG_R30
registerPrefix := map[string]bool{
"F": true,
"FCR": true,
"M": true,
"R": true,
}
instructions := make(map[string]obj.As)
for i, s := range obj.Anames {
instructions[s] = obj.As(i)
}
for i, s := range mips.Anames {
if obj.As(i) >= obj.A_ARCHSPECIFIC {
instructions[s] = obj.As(i) + obj.ABaseMIPS
}
}
// Annoying alias.
instructions["JAL"] = mips.AJAL
return &Arch{
LinkArch: linkArch,
Instructions: instructions,
Register: register,
RegisterPrefix: registerPrefix,
RegisterNumber: mipsRegisterNumber,
IsJump: jumpMIPS,
}
}
func archMips64(linkArch *obj.LinkArch) *Arch {
register := make(map[string]int16)
// Create maps for easy lookup of instruction names etc.
// Note that there is no list of names as there is for x86.
for i := mips.REG_R0; i <= mips.REG_R31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := mips.REG_F0; i <= mips.REG_F31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := mips.REG_M0; i <= mips.REG_M31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := mips.REG_FCR0; i <= mips.REG_FCR31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := mips.REG_W0; i <= mips.REG_W31; i++ {
register[obj.Rconv(i)] = int16(i)
}
register["HI"] = mips.REG_HI
register["LO"] = mips.REG_LO
// Pseudo-registers.
register["SB"] = RSB
register["FP"] = RFP
register["PC"] = RPC
// Avoid unintentionally clobbering g using R30.
delete(register, "R30")
register["g"] = mips.REG_R30
// Avoid unintentionally clobbering RSB using R28.
delete(register, "R28")
register["RSB"] = mips.REG_R28
registerPrefix := map[string]bool{
"F": true,
"FCR": true,
"M": true,
"R": true,
"W": true,
}
instructions := make(map[string]obj.As)
for i, s := range obj.Anames {
instructions[s] = obj.As(i)
}
for i, s := range mips.Anames {
if obj.As(i) >= obj.A_ARCHSPECIFIC {
instructions[s] = obj.As(i) + obj.ABaseMIPS
}
}
// Annoying alias.
instructions["JAL"] = mips.AJAL
return &Arch{
LinkArch: linkArch,
Instructions: instructions,
Register: register,
RegisterPrefix: registerPrefix,
RegisterNumber: mipsRegisterNumber,
IsJump: jumpMIPS,
}
}
func archRISCV64() *Arch {
register := make(map[string]int16)
// Standard register names.
for i := riscv.REG_X0; i <= riscv.REG_X31; i++ {
name := fmt.Sprintf("X%d", i-riscv.REG_X0)
register[name] = int16(i)
}
for i := riscv.REG_F0; i <= riscv.REG_F31; i++ {
name := fmt.Sprintf("F%d", i-riscv.REG_F0)
register[name] = int16(i)
}
// General registers with ABI names.
register["ZERO"] = riscv.REG_ZERO
register["RA"] = riscv.REG_RA
register["SP"] = riscv.REG_SP
register["GP"] = riscv.REG_GP
register["TP"] = riscv.REG_TP
register["T0"] = riscv.REG_T0
register["T1"] = riscv.REG_T1
register["T2"] = riscv.REG_T2
register["S0"] = riscv.REG_S0
register["S1"] = riscv.REG_S1
register["A0"] = riscv.REG_A0
register["A1"] = riscv.REG_A1
register["A2"] = riscv.REG_A2
register["A3"] = riscv.REG_A3
register["A4"] = riscv.REG_A4
register["A5"] = riscv.REG_A5
register["A6"] = riscv.REG_A6
register["A7"] = riscv.REG_A7
register["S2"] = riscv.REG_S2
register["S3"] = riscv.REG_S3
register["S4"] = riscv.REG_S4
register["S5"] = riscv.REG_S5
register["S6"] = riscv.REG_S6
register["S7"] = riscv.REG_S7
register["S8"] = riscv.REG_S8
register["S9"] = riscv.REG_S9
register["S10"] = riscv.REG_S10
register["S11"] = riscv.REG_S11
register["T3"] = riscv.REG_T3
register["T4"] = riscv.REG_T4
register["T5"] = riscv.REG_T5
register["T6"] = riscv.REG_T6
// Go runtime register names.
register["g"] = riscv.REG_G
register["CTXT"] = riscv.REG_CTXT
register["TMP"] = riscv.REG_TMP
// ABI names for floating point register.
register["FT0"] = riscv.REG_FT0
register["FT1"] = riscv.REG_FT1
register["FT2"] = riscv.REG_FT2
register["FT3"] = riscv.REG_FT3
register["FT4"] = riscv.REG_FT4
register["FT5"] = riscv.REG_FT5
register["FT6"] = riscv.REG_FT6
register["FT7"] = riscv.REG_FT7
register["FS0"] = riscv.REG_FS0
register["FS1"] = riscv.REG_FS1
register["FA0"] = riscv.REG_FA0
register["FA1"] = riscv.REG_FA1
register["FA2"] = riscv.REG_FA2
register["FA3"] = riscv.REG_FA3
register["FA4"] = riscv.REG_FA4
register["FA5"] = riscv.REG_FA5
register["FA6"] = riscv.REG_FA6
register["FA7"] = riscv.REG_FA7
register["FS2"] = riscv.REG_FS2
register["FS3"] = riscv.REG_FS3
register["FS4"] = riscv.REG_FS4
register["FS5"] = riscv.REG_FS5
register["FS6"] = riscv.REG_FS6
register["FS7"] = riscv.REG_FS7
register["FS8"] = riscv.REG_FS8
register["FS9"] = riscv.REG_FS9
register["FS10"] = riscv.REG_FS10
register["FS11"] = riscv.REG_FS11
register["FT8"] = riscv.REG_FT8
register["FT9"] = riscv.REG_FT9
register["FT10"] = riscv.REG_FT10
register["FT11"] = riscv.REG_FT11
// Pseudo-registers.
register["SB"] = RSB
register["FP"] = RFP
register["PC"] = RPC
instructions := make(map[string]obj.As)
for i, s := range obj.Anames {
instructions[s] = obj.As(i)
}
for i, s := range riscv.Anames {
if obj.As(i) >= obj.A_ARCHSPECIFIC {
instructions[s] = obj.As(i) + obj.ABaseRISCV
}
}
return &Arch{
LinkArch: &riscv.LinkRISCV64,
Instructions: instructions,
Register: register,
RegisterPrefix: nil,
RegisterNumber: nilRegisterNumber,
IsJump: jumpRISCV,
}
}
func archS390x() *Arch {
register := make(map[string]int16)
// Create maps for easy lookup of instruction names etc.
// Note that there is no list of names as there is for x86.
for i := s390x.REG_R0; i <= s390x.REG_R15; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := s390x.REG_F0; i <= s390x.REG_F15; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := s390x.REG_V0; i <= s390x.REG_V31; i++ {
register[obj.Rconv(i)] = int16(i)
}
for i := s390x.REG_AR0; i <= s390x.REG_AR15; i++ {
register[obj.Rconv(i)] = int16(i)
}
register["LR"] = s390x.REG_LR
// Pseudo-registers.
register["SB"] = RSB
register["FP"] = RFP
register["PC"] = RPC
// Avoid unintentionally clobbering g using R13.
delete(register, "R13")
register["g"] = s390x.REG_R13
registerPrefix := map[string]bool{
"AR": true,
"F": true,
"R": true,
}
instructions := make(map[string]obj.As)
for i, s := range obj.Anames {
instructions[s] = obj.As(i)
}
for i, s := range s390x.Anames {
if obj.As(i) >= obj.A_ARCHSPECIFIC {
instructions[s] = obj.As(i) + obj.ABaseS390X
}
}
// Annoying aliases.
instructions["BR"] = s390x.ABR
instructions["BL"] = s390x.ABL
return &Arch{
LinkArch: &s390x.Links390x,
Instructions: instructions,
Register: register,
RegisterPrefix: registerPrefix,
RegisterNumber: s390xRegisterNumber,
IsJump: jumpS390x,
}
}
func archWasm() *Arch {
instructions := make(map[string]obj.As)
for i, s := range obj.Anames {
instructions[s] = obj.As(i)
}
for i, s := range wasm.Anames {
if obj.As(i) >= obj.A_ARCHSPECIFIC {
instructions[s] = obj.As(i) + obj.ABaseWasm
}
}
return &Arch{
LinkArch: &wasm.Linkwasm,
Instructions: instructions,
Register: wasm.Register,
RegisterPrefix: nil,
RegisterNumber: nilRegisterNumber,
IsJump: jumpWasm,
}
}

View File

@ -0,0 +1,257 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file encapsulates some of the odd characteristics of the ARM
// instruction set, to minimize its interaction with the core of the
// assembler.
package arch
import (
"strings"
"github.com/twitchyliquid64/golang-asm/obj"
"github.com/twitchyliquid64/golang-asm/obj/arm"
)
var armLS = map[string]uint8{
"U": arm.C_UBIT,
"S": arm.C_SBIT,
"W": arm.C_WBIT,
"P": arm.C_PBIT,
"PW": arm.C_WBIT | arm.C_PBIT,
"WP": arm.C_WBIT | arm.C_PBIT,
}
var armSCOND = map[string]uint8{
"EQ": arm.C_SCOND_EQ,
"NE": arm.C_SCOND_NE,
"CS": arm.C_SCOND_HS,
"HS": arm.C_SCOND_HS,
"CC": arm.C_SCOND_LO,
"LO": arm.C_SCOND_LO,
"MI": arm.C_SCOND_MI,
"PL": arm.C_SCOND_PL,
"VS": arm.C_SCOND_VS,
"VC": arm.C_SCOND_VC,
"HI": arm.C_SCOND_HI,
"LS": arm.C_SCOND_LS,
"GE": arm.C_SCOND_GE,
"LT": arm.C_SCOND_LT,
"GT": arm.C_SCOND_GT,
"LE": arm.C_SCOND_LE,
"AL": arm.C_SCOND_NONE,
"U": arm.C_UBIT,
"S": arm.C_SBIT,
"W": arm.C_WBIT,
"P": arm.C_PBIT,
"PW": arm.C_WBIT | arm.C_PBIT,
"WP": arm.C_WBIT | arm.C_PBIT,
"F": arm.C_FBIT,
"IBW": arm.C_WBIT | arm.C_PBIT | arm.C_UBIT,
"IAW": arm.C_WBIT | arm.C_UBIT,
"DBW": arm.C_WBIT | arm.C_PBIT,
"DAW": arm.C_WBIT,
"IB": arm.C_PBIT | arm.C_UBIT,
"IA": arm.C_UBIT,
"DB": arm.C_PBIT,
"DA": 0,
}
var armJump = map[string]bool{
"B": true,
"BL": true,
"BX": true,
"BEQ": true,
"BNE": true,
"BCS": true,
"BHS": true,
"BCC": true,
"BLO": true,
"BMI": true,
"BPL": true,
"BVS": true,
"BVC": true,
"BHI": true,
"BLS": true,
"BGE": true,
"BLT": true,
"BGT": true,
"BLE": true,
"CALL": true,
"JMP": true,
}
func jumpArm(word string) bool {
return armJump[word]
}
// IsARMCMP reports whether the op (as defined by an arm.A* constant) is
// one of the comparison instructions that require special handling.
func IsARMCMP(op obj.As) bool {
switch op {
case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST:
return true
}
return false
}
// IsARMSTREX reports whether the op (as defined by an arm.A* constant) is
// one of the STREX-like instructions that require special handling.
func IsARMSTREX(op obj.As) bool {
switch op {
case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU:
return true
}
return false
}
// MCR is not defined by the obj/arm; instead we define it privately here.
// It is encoded as an MRC with a bit inside the instruction word,
// passed to arch.ARMMRCOffset.
const aMCR = arm.ALAST + 1
// IsARMMRC reports whether the op (as defined by an arm.A* constant) is
// MRC or MCR
func IsARMMRC(op obj.As) bool {
switch op {
case arm.AMRC, aMCR: // Note: aMCR is defined in this package.
return true
}
return false
}
// IsARMBFX reports whether the op (as defined by an arm.A* constant) is one the
// BFX-like instructions which are in the form of "op $width, $LSB, (Reg,) Reg".
func IsARMBFX(op obj.As) bool {
switch op {
case arm.ABFX, arm.ABFXU, arm.ABFC, arm.ABFI:
return true
}
return false
}
// IsARMFloatCmp reports whether the op is a floating comparison instruction.
func IsARMFloatCmp(op obj.As) bool {
switch op {
case arm.ACMPF, arm.ACMPD:
return true
}
return false
}
// ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions.
// The difference between MRC and MCR is represented by a bit high in the word, not
// in the usual way by the opcode itself. Asm must use AMRC for both instructions, so
// we return the opcode for MRC so that asm doesn't need to import obj/arm.
func ARMMRCOffset(op obj.As, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 obj.As, ok bool) {
op1 := int64(0)
if op == arm.AMRC {
op1 = 1
}
bits, ok := ParseARMCondition(cond)
if !ok {
return
}
offset = (0xe << 24) | // opcode
(op1 << 20) | // MCR/MRC
((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
((x0 & 15) << 8) | //coprocessor number
((x1 & 7) << 21) | // coprocessor operation
((x2 & 15) << 12) | // ARM register
((x3 & 15) << 16) | // Crn
((x4 & 15) << 0) | // Crm
((x5 & 7) << 5) | // coprocessor information
(1 << 4) /* must be set */
return offset, arm.AMRC, true
}
// IsARMMULA reports whether the op (as defined by an arm.A* constant) is
// MULA, MULS, MMULA, MMULS, MULABB, MULAWB or MULAWT, the 4-operand instructions.
func IsARMMULA(op obj.As) bool {
switch op {
case arm.AMULA, arm.AMULS, arm.AMMULA, arm.AMMULS, arm.AMULABB, arm.AMULAWB, arm.AMULAWT:
return true
}
return false
}
var bcode = []obj.As{
arm.ABEQ,
arm.ABNE,
arm.ABCS,
arm.ABCC,
arm.ABMI,
arm.ABPL,
arm.ABVS,
arm.ABVC,
arm.ABHI,
arm.ABLS,
arm.ABGE,
arm.ABLT,
arm.ABGT,
arm.ABLE,
arm.AB,
obj.ANOP,
}
// ARMConditionCodes handles the special condition code situation for the ARM.
// It returns a boolean to indicate success; failure means cond was unrecognized.
func ARMConditionCodes(prog *obj.Prog, cond string) bool {
if cond == "" {
return true
}
bits, ok := ParseARMCondition(cond)
if !ok {
return false
}
/* hack to make B.NE etc. work: turn it into the corresponding conditional */
if prog.As == arm.AB {
prog.As = bcode[(bits^arm.C_SCOND_XOR)&0xf]
bits = (bits &^ 0xf) | arm.C_SCOND_NONE
}
prog.Scond = bits
return true
}
// ParseARMCondition parses the conditions attached to an ARM instruction.
// The input is a single string consisting of period-separated condition
// codes, such as ".P.W". An initial period is ignored.
func ParseARMCondition(cond string) (uint8, bool) {
return parseARMCondition(cond, armLS, armSCOND)
}
func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) {
cond = strings.TrimPrefix(cond, ".")
if cond == "" {
return arm.C_SCOND_NONE, true
}
names := strings.Split(cond, ".")
bits := uint8(0)
for _, name := range names {
if b, present := ls[name]; present {
bits |= b
continue
}
if b, present := scond[name]; present {
bits = (bits &^ arm.C_SCOND) | b
continue
}
return 0, false
}
return bits, true
}
func armRegisterNumber(name string, n int16) (int16, bool) {
if n < 0 || 15 < n {
return 0, false
}
switch name {
case "R":
return arm.REG_R0 + n, true
case "F":
return arm.REG_F0 + n, true
}
return 0, false
}

View File

@ -0,0 +1,350 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file encapsulates some of the odd characteristics of the ARM64
// instruction set, to minimize its interaction with the core of the
// assembler.
package arch
import (
"github.com/twitchyliquid64/golang-asm/obj"
"github.com/twitchyliquid64/golang-asm/obj/arm64"
"errors"
)
var arm64LS = map[string]uint8{
"P": arm64.C_XPOST,
"W": arm64.C_XPRE,
}
var arm64Jump = map[string]bool{
"B": true,
"BL": true,
"BEQ": true,
"BNE": true,
"BCS": true,
"BHS": true,
"BCC": true,
"BLO": true,
"BMI": true,
"BPL": true,
"BVS": true,
"BVC": true,
"BHI": true,
"BLS": true,
"BGE": true,
"BLT": true,
"BGT": true,
"BLE": true,
"CALL": true,
"CBZ": true,
"CBZW": true,
"CBNZ": true,
"CBNZW": true,
"JMP": true,
"TBNZ": true,
"TBZ": true,
}
func jumpArm64(word string) bool {
return arm64Jump[word]
}
// IsARM64CMP reports whether the op (as defined by an arm.A* constant) is
// one of the comparison instructions that require special handling.
func IsARM64CMP(op obj.As) bool {
switch op {
case arm64.ACMN, arm64.ACMP, arm64.ATST,
arm64.ACMNW, arm64.ACMPW, arm64.ATSTW,
arm64.AFCMPS, arm64.AFCMPD,
arm64.AFCMPES, arm64.AFCMPED:
return true
}
return false
}
// IsARM64STLXR reports whether the op (as defined by an arm64.A*
// constant) is one of the STLXR-like instructions that require special
// handling.
func IsARM64STLXR(op obj.As) bool {
switch op {
case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR,
arm64.ASTXRB, arm64.ASTXRH, arm64.ASTXRW, arm64.ASTXR,
arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW:
return true
}
// atomic instructions
if arm64.IsAtomicInstruction(op) {
return true
}
return false
}
// ARM64Suffix handles the special suffix for the ARM64.
// It returns a boolean to indicate success; failure means
// cond was unrecognized.
func ARM64Suffix(prog *obj.Prog, cond string) bool {
if cond == "" {
return true
}
bits, ok := parseARM64Suffix(cond)
if !ok {
return false
}
prog.Scond = bits
return true
}
// parseARM64Suffix parses the suffix attached to an ARM64 instruction.
// The input is a single string consisting of period-separated condition
// codes, such as ".P.W". An initial period is ignored.
func parseARM64Suffix(cond string) (uint8, bool) {
if cond == "" {
return 0, true
}
return parseARMCondition(cond, arm64LS, nil)
}
func arm64RegisterNumber(name string, n int16) (int16, bool) {
switch name {
case "F":
if 0 <= n && n <= 31 {
return arm64.REG_F0 + n, true
}
case "R":
if 0 <= n && n <= 30 { // not 31
return arm64.REG_R0 + n, true
}
case "V":
if 0 <= n && n <= 31 {
return arm64.REG_V0 + n, true
}
}
return 0, false
}
// IsARM64TBL reports whether the op (as defined by an arm64.A*
// constant) is one of the table lookup instructions that require special
// handling.
func IsARM64TBL(op obj.As) bool {
return op == arm64.AVTBL
}
// ARM64RegisterExtension parses an ARM64 register with extension or arrangement.
func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
Rnum := (reg & 31) + int16(num<<5)
if isAmount {
if num < 0 || num > 7 {
return errors.New("index shift amount is out of range")
}
}
switch ext {
case "UXTB":
if !isAmount {
return errors.New("invalid register extension")
}
if a.Type == obj.TYPE_MEM {
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_UXTB + Rnum
case "UXTH":
if !isAmount {
return errors.New("invalid register extension")
}
if a.Type == obj.TYPE_MEM {
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_UXTH + Rnum
case "UXTW":
if !isAmount {
return errors.New("invalid register extension")
}
// effective address of memory is a base register value and an offset register value.
if a.Type == obj.TYPE_MEM {
a.Index = arm64.REG_UXTW + Rnum
} else {
a.Reg = arm64.REG_UXTW + Rnum
}
case "UXTX":
if !isAmount {
return errors.New("invalid register extension")
}
if a.Type == obj.TYPE_MEM {
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_UXTX + Rnum
case "SXTB":
if !isAmount {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_SXTB + Rnum
case "SXTH":
if !isAmount {
return errors.New("invalid register extension")
}
if a.Type == obj.TYPE_MEM {
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_SXTH + Rnum
case "SXTW":
if !isAmount {
return errors.New("invalid register extension")
}
if a.Type == obj.TYPE_MEM {
a.Index = arm64.REG_SXTW + Rnum
} else {
a.Reg = arm64.REG_SXTW + Rnum
}
case "SXTX":
if !isAmount {
return errors.New("invalid register extension")
}
if a.Type == obj.TYPE_MEM {
a.Index = arm64.REG_SXTX + Rnum
} else {
a.Reg = arm64.REG_SXTX + Rnum
}
case "LSL":
if !isAmount {
return errors.New("invalid register extension")
}
a.Index = arm64.REG_LSL + Rnum
case "B8":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5)
case "B16":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5)
case "H4":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5)
case "H8":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5)
case "S2":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5)
case "S4":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5)
case "D1":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1D & 15) << 5)
case "D2":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5)
case "Q1":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1Q & 15) << 5)
case "B":
if !isIndex {
return nil
}
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5)
a.Index = num
case "H":
if !isIndex {
return nil
}
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5)
a.Index = num
case "S":
if !isIndex {
return nil
}
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5)
a.Index = num
case "D":
if !isIndex {
return nil
}
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5)
a.Index = num
default:
return errors.New("unsupported register extension type: " + ext)
}
return nil
}
// ARM64RegisterArrangement parses an ARM64 vector register arrangement.
func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) {
var curQ, curSize uint16
if name[0] != 'V' {
return 0, errors.New("expect V0 through V31; found: " + name)
}
if reg < 0 {
return 0, errors.New("invalid register number: " + name)
}
switch arng {
case "B8":
curSize = 0
curQ = 0
case "B16":
curSize = 0
curQ = 1
case "H4":
curSize = 1
curQ = 0
case "H8":
curSize = 1
curQ = 1
case "S2":
curSize = 2
curQ = 0
case "S4":
curSize = 2
curQ = 1
case "D1":
curSize = 3
curQ = 0
case "D2":
curSize = 3
curQ = 1
default:
return 0, errors.New("invalid arrangement in ARM64 register list")
}
return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil
}
// ARM64RegisterListOffset generates offset encoding according to AArch64 specification.
func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) {
offset := int64(firstReg)
switch regCnt {
case 1:
offset |= 0x7 << 12
case 2:
offset |= 0xa << 12
case 3:
offset |= 0x6 << 12
case 4:
offset |= 0x2 << 12
default:
return 0, errors.New("invalid register numbers in ARM64 register list")
}
offset |= arrangement
// arm64 uses the 60th bit to differentiate from other archs
// For more details, refer to: obj/arm64/list7.go
offset |= 1 << 60
return offset, nil
}

View File

@ -0,0 +1,72 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file encapsulates some of the odd characteristics of the
// MIPS (MIPS64) instruction set, to minimize its interaction
// with the core of the assembler.
package arch
import (
"github.com/twitchyliquid64/golang-asm/obj"
"github.com/twitchyliquid64/golang-asm/obj/mips"
)
func jumpMIPS(word string) bool {
switch word {
case "BEQ", "BFPF", "BFPT", "BGEZ", "BGEZAL", "BGTZ", "BLEZ", "BLTZ", "BLTZAL", "BNE", "JMP", "JAL", "CALL":
return true
}
return false
}
// IsMIPSCMP reports whether the op (as defined by an mips.A* constant) is
// one of the CMP instructions that require special handling.
func IsMIPSCMP(op obj.As) bool {
switch op {
case mips.ACMPEQF, mips.ACMPEQD, mips.ACMPGEF, mips.ACMPGED,
mips.ACMPGTF, mips.ACMPGTD:
return true
}
return false
}
// IsMIPSMUL reports whether the op (as defined by an mips.A* constant) is
// one of the MUL/DIV/REM/MADD/MSUB instructions that require special handling.
func IsMIPSMUL(op obj.As) bool {
switch op {
case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU,
mips.ADIV, mips.ADIVU, mips.ADIVV, mips.ADIVVU,
mips.AREM, mips.AREMU, mips.AREMV, mips.AREMVU,
mips.AMADD, mips.AMSUB:
return true
}
return false
}
func mipsRegisterNumber(name string, n int16) (int16, bool) {
switch name {
case "F":
if 0 <= n && n <= 31 {
return mips.REG_F0 + n, true
}
case "FCR":
if 0 <= n && n <= 31 {
return mips.REG_FCR0 + n, true
}
case "M":
if 0 <= n && n <= 31 {
return mips.REG_M0 + n, true
}
case "R":
if 0 <= n && n <= 31 {
return mips.REG_R0 + n, true
}
case "W":
if 0 <= n && n <= 31 {
return mips.REG_W0 + n, true
}
}
return 0, false
}

View File

@ -0,0 +1,102 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file encapsulates some of the odd characteristics of the
// 64-bit PowerPC (PPC64) instruction set, to minimize its interaction
// with the core of the assembler.
package arch
import (
"github.com/twitchyliquid64/golang-asm/obj"
"github.com/twitchyliquid64/golang-asm/obj/ppc64"
)
func jumpPPC64(word string) bool {
switch word {
case "BC", "BCL", "BEQ", "BGE", "BGT", "BL", "BLE", "BLT", "BNE", "BR", "BVC", "BVS", "CALL", "JMP":
return true
}
return false
}
// IsPPC64RLD reports whether the op (as defined by an ppc64.A* constant) is
// one of the RLD-like instructions that require special handling.
// The FMADD-like instructions behave similarly.
func IsPPC64RLD(op obj.As) bool {
switch op {
case ppc64.ARLDC, ppc64.ARLDCCC, ppc64.ARLDCL, ppc64.ARLDCLCC,
ppc64.ARLDCR, ppc64.ARLDCRCC, ppc64.ARLDMI, ppc64.ARLDMICC,
ppc64.ARLWMI, ppc64.ARLWMICC, ppc64.ARLWNM, ppc64.ARLWNMCC:
return true
case ppc64.AFMADD, ppc64.AFMADDCC, ppc64.AFMADDS, ppc64.AFMADDSCC,
ppc64.AFMSUB, ppc64.AFMSUBCC, ppc64.AFMSUBS, ppc64.AFMSUBSCC,
ppc64.AFNMADD, ppc64.AFNMADDCC, ppc64.AFNMADDS, ppc64.AFNMADDSCC,
ppc64.AFNMSUB, ppc64.AFNMSUBCC, ppc64.AFNMSUBS, ppc64.AFNMSUBSCC:
return true
}
return false
}
func IsPPC64ISEL(op obj.As) bool {
return op == ppc64.AISEL
}
// IsPPC64CMP reports whether the op (as defined by an ppc64.A* constant) is
// one of the CMP instructions that require special handling.
func IsPPC64CMP(op obj.As) bool {
switch op {
case ppc64.ACMP, ppc64.ACMPU, ppc64.ACMPW, ppc64.ACMPWU, ppc64.AFCMPU:
return true
}
return false
}
// IsPPC64NEG reports whether the op (as defined by an ppc64.A* constant) is
// one of the NEG-like instructions that require special handling.
func IsPPC64NEG(op obj.As) bool {
switch op {
case ppc64.AADDMECC, ppc64.AADDMEVCC, ppc64.AADDMEV, ppc64.AADDME,
ppc64.AADDZECC, ppc64.AADDZEVCC, ppc64.AADDZEV, ppc64.AADDZE,
ppc64.ACNTLZDCC, ppc64.ACNTLZD, ppc64.ACNTLZWCC, ppc64.ACNTLZW,
ppc64.AEXTSBCC, ppc64.AEXTSB, ppc64.AEXTSHCC, ppc64.AEXTSH,
ppc64.AEXTSWCC, ppc64.AEXTSW, ppc64.ANEGCC, ppc64.ANEGVCC,
ppc64.ANEGV, ppc64.ANEG, ppc64.ASLBMFEE, ppc64.ASLBMFEV,
ppc64.ASLBMTE, ppc64.ASUBMECC, ppc64.ASUBMEVCC, ppc64.ASUBMEV,
ppc64.ASUBME, ppc64.ASUBZECC, ppc64.ASUBZEVCC, ppc64.ASUBZEV,
ppc64.ASUBZE:
return true
}
return false
}
func ppc64RegisterNumber(name string, n int16) (int16, bool) {
switch name {
case "CR":
if 0 <= n && n <= 7 {
return ppc64.REG_CR0 + n, true
}
case "VS":
if 0 <= n && n <= 63 {
return ppc64.REG_VS0 + n, true
}
case "V":
if 0 <= n && n <= 31 {
return ppc64.REG_V0 + n, true
}
case "F":
if 0 <= n && n <= 31 {
return ppc64.REG_F0 + n, true
}
case "R":
if 0 <= n && n <= 31 {
return ppc64.REG_R0 + n, true
}
case "SPR":
if 0 <= n && n <= 1024 {
return ppc64.REG_SPR0 + n, true
}
}
return 0, false
}

View File

@ -0,0 +1,28 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file encapsulates some of the odd characteristics of the RISCV64
// instruction set, to minimize its interaction with the core of the
// assembler.
package arch
import (
"github.com/twitchyliquid64/golang-asm/obj"
"github.com/twitchyliquid64/golang-asm/obj/riscv"
)
// IsRISCV64AMO reports whether the op (as defined by a riscv.A*
// constant) is one of the AMO instructions that requires special
// handling.
func IsRISCV64AMO(op obj.As) bool {
switch op {
case riscv.ASCW, riscv.ASCD, riscv.AAMOSWAPW, riscv.AAMOSWAPD, riscv.AAMOADDW, riscv.AAMOADDD,
riscv.AAMOANDW, riscv.AAMOANDD, riscv.AAMOORW, riscv.AAMOORD, riscv.AAMOXORW, riscv.AAMOXORD,
riscv.AAMOMINW, riscv.AAMOMIND, riscv.AAMOMINUW, riscv.AAMOMINUD,
riscv.AAMOMAXW, riscv.AAMOMAXD, riscv.AAMOMAXUW, riscv.AAMOMAXUD:
return true
}
return false
}

View File

@ -0,0 +1,81 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file encapsulates some of the odd characteristics of the
// s390x instruction set, to minimize its interaction
// with the core of the assembler.
package arch
import (
"github.com/twitchyliquid64/golang-asm/obj/s390x"
)
func jumpS390x(word string) bool {
switch word {
case "BRC",
"BC",
"BCL",
"BEQ",
"BGE",
"BGT",
"BL",
"BLE",
"BLEU",
"BLT",
"BLTU",
"BNE",
"BR",
"BVC",
"BVS",
"BRCT",
"BRCTG",
"CMPBEQ",
"CMPBGE",
"CMPBGT",
"CMPBLE",
"CMPBLT",
"CMPBNE",
"CMPUBEQ",
"CMPUBGE",
"CMPUBGT",
"CMPUBLE",
"CMPUBLT",
"CMPUBNE",
"CRJ",
"CGRJ",
"CLRJ",
"CLGRJ",
"CIJ",
"CGIJ",
"CLIJ",
"CLGIJ",
"CALL",
"JMP":
return true
}
return false
}
func s390xRegisterNumber(name string, n int16) (int16, bool) {
switch name {
case "AR":
if 0 <= n && n <= 15 {
return s390x.REG_AR0 + n, true
}
case "F":
if 0 <= n && n <= 15 {
return s390x.REG_F0 + n, true
}
case "R":
if 0 <= n && n <= 15 {
return s390x.REG_R0 + n, true
}
case "V":
if 0 <= n && n <= 31 {
return s390x.REG_V0 + n, true
}
}
return 0, false
}

148
vendor/github.com/twitchyliquid64/golang-asm/bio/buf.go generated vendored Normal file
View File

@ -0,0 +1,148 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package bio implements common I/O abstractions used within the Go toolchain.
package bio
import (
"bufio"
"io"
"log"
"os"
)
// Reader implements a seekable buffered io.Reader.
type Reader struct {
f *os.File
*bufio.Reader
}
// Writer implements a seekable buffered io.Writer.
type Writer struct {
f *os.File
*bufio.Writer
}
// Create creates the file named name and returns a Writer
// for that file.
func Create(name string) (*Writer, error) {
f, err := os.Create(name)
if err != nil {
return nil, err
}
return &Writer{f: f, Writer: bufio.NewWriter(f)}, nil
}
// Open returns a Reader for the file named name.
func Open(name string) (*Reader, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
return NewReader(f), nil
}
// NewReader returns a Reader from an open file.
func NewReader(f *os.File) *Reader {
return &Reader{f: f, Reader: bufio.NewReader(f)}
}
func (r *Reader) MustSeek(offset int64, whence int) int64 {
if whence == 1 {
offset -= int64(r.Buffered())
}
off, err := r.f.Seek(offset, whence)
if err != nil {
log.Fatalf("seeking in output: %v", err)
}
r.Reset(r.f)
return off
}
func (w *Writer) MustSeek(offset int64, whence int) int64 {
if err := w.Flush(); err != nil {
log.Fatalf("writing output: %v", err)
}
off, err := w.f.Seek(offset, whence)
if err != nil {
log.Fatalf("seeking in output: %v", err)
}
return off
}
func (r *Reader) Offset() int64 {
off, err := r.f.Seek(0, 1)
if err != nil {
log.Fatalf("seeking in output [0, 1]: %v", err)
}
off -= int64(r.Buffered())
return off
}
func (w *Writer) Offset() int64 {
if err := w.Flush(); err != nil {
log.Fatalf("writing output: %v", err)
}
off, err := w.f.Seek(0, 1)
if err != nil {
log.Fatalf("seeking in output [0, 1]: %v", err)
}
return off
}
func (r *Reader) Close() error {
return r.f.Close()
}
func (w *Writer) Close() error {
err := w.Flush()
err1 := w.f.Close()
if err == nil {
err = err1
}
return err
}
func (r *Reader) File() *os.File {
return r.f
}
func (w *Writer) File() *os.File {
return w.f
}
// Slice reads the next length bytes of r into a slice.
//
// This slice may be backed by mmap'ed memory. Currently, this memory
// will never be unmapped. The second result reports whether the
// backing memory is read-only.
func (r *Reader) Slice(length uint64) ([]byte, bool, error) {
if length == 0 {
return []byte{}, false, nil
}
data, ok := r.sliceOS(length)
if ok {
return data, true, nil
}
data = make([]byte, length)
_, err := io.ReadFull(r, data)
if err != nil {
return nil, false, err
}
return data, false, nil
}
// SliceRO returns a slice containing the next length bytes of r
// backed by a read-only mmap'd data. If the mmap cannot be
// established (limit exceeded, region too small, etc) a nil slice
// will be returned. If mmap succeeds, it will never be unmapped.
func (r *Reader) SliceRO(length uint64) []byte {
data, ok := r.sliceOS(length)
if ok {
return data
}
return nil
}

View File

@ -0,0 +1,62 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd
package bio
import (
"runtime"
"sync/atomic"
"syscall"
)
// mmapLimit is the maximum number of mmaped regions to create before
// falling back to reading into a heap-allocated slice. This exists
// because some operating systems place a limit on the number of
// distinct mapped regions per process. As of this writing:
//
// Darwin unlimited
// DragonFly 1000000 (vm.max_proc_mmap)
// FreeBSD unlimited
// Linux 65530 (vm.max_map_count) // TODO: query /proc/sys/vm/max_map_count?
// NetBSD unlimited
// OpenBSD unlimited
var mmapLimit int32 = 1<<31 - 1
func init() {
// Linux is the only practically concerning OS.
if runtime.GOOS == "linux" {
mmapLimit = 30000
}
}
func (r *Reader) sliceOS(length uint64) ([]byte, bool) {
// For small slices, don't bother with the overhead of a
// mapping, especially since we have no way to unmap it.
const threshold = 16 << 10
if length < threshold {
return nil, false
}
// Have we reached the mmap limit?
if atomic.AddInt32(&mmapLimit, -1) < 0 {
atomic.AddInt32(&mmapLimit, 1)
return nil, false
}
// Page-align the offset.
off := r.Offset()
align := syscall.Getpagesize()
aoff := off &^ int64(align-1)
data, err := syscall.Mmap(int(r.f.Fd()), aoff, int(length+uint64(off-aoff)), syscall.PROT_READ, syscall.MAP_SHARED|syscall.MAP_FILE)
if err != nil {
return nil, false
}
data = data[off-aoff:]
r.MustSeek(int64(length), 1)
return data, true
}

View File

@ -0,0 +1,11 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
package bio
func (r *Reader) sliceOS(length uint64) ([]byte, bool) {
return nil, false
}

View File

@ -0,0 +1,43 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bio
import (
"io"
"log"
)
// MustClose closes Closer c and calls log.Fatal if it returns a non-nil error.
func MustClose(c io.Closer) {
if err := c.Close(); err != nil {
log.Fatal(err)
}
}
// MustWriter returns a Writer that wraps the provided Writer,
// except that it calls log.Fatal instead of returning a non-nil error.
func MustWriter(w io.Writer) io.Writer {
return mustWriter{w}
}
type mustWriter struct {
w io.Writer
}
func (w mustWriter) Write(b []byte) (int, error) {
n, err := w.w.Write(b)
if err != nil {
log.Fatal(err)
}
return n, nil
}
func (w mustWriter) WriteString(s string) (int, error) {
n, err := io.WriteString(w.w, s)
if err != nil {
log.Fatal(err)
}
return n, nil
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,493 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package dwarf
// Cut, pasted, tr-and-awk'ed from tables in
// http://dwarfstd.org/doc/Dwarf3.pdf
// Table 18
const (
DW_TAG_array_type = 0x01
DW_TAG_class_type = 0x02
DW_TAG_entry_point = 0x03
DW_TAG_enumeration_type = 0x04
DW_TAG_formal_parameter = 0x05
DW_TAG_imported_declaration = 0x08
DW_TAG_label = 0x0a
DW_TAG_lexical_block = 0x0b
DW_TAG_member = 0x0d
DW_TAG_pointer_type = 0x0f
DW_TAG_reference_type = 0x10
DW_TAG_compile_unit = 0x11
DW_TAG_string_type = 0x12
DW_TAG_structure_type = 0x13
DW_TAG_subroutine_type = 0x15
DW_TAG_typedef = 0x16
DW_TAG_union_type = 0x17
DW_TAG_unspecified_parameters = 0x18
DW_TAG_variant = 0x19
DW_TAG_common_block = 0x1a
DW_TAG_common_inclusion = 0x1b
DW_TAG_inheritance = 0x1c
DW_TAG_inlined_subroutine = 0x1d
DW_TAG_module = 0x1e
DW_TAG_ptr_to_member_type = 0x1f
DW_TAG_set_type = 0x20
DW_TAG_subrange_type = 0x21
DW_TAG_with_stmt = 0x22
DW_TAG_access_declaration = 0x23
DW_TAG_base_type = 0x24
DW_TAG_catch_block = 0x25
DW_TAG_const_type = 0x26
DW_TAG_constant = 0x27
DW_TAG_enumerator = 0x28
DW_TAG_file_type = 0x29
DW_TAG_friend = 0x2a
DW_TAG_namelist = 0x2b
DW_TAG_namelist_item = 0x2c
DW_TAG_packed_type = 0x2d
DW_TAG_subprogram = 0x2e
DW_TAG_template_type_parameter = 0x2f
DW_TAG_template_value_parameter = 0x30
DW_TAG_thrown_type = 0x31
DW_TAG_try_block = 0x32
DW_TAG_variant_part = 0x33
DW_TAG_variable = 0x34
DW_TAG_volatile_type = 0x35
// Dwarf3
DW_TAG_dwarf_procedure = 0x36
DW_TAG_restrict_type = 0x37
DW_TAG_interface_type = 0x38
DW_TAG_namespace = 0x39
DW_TAG_imported_module = 0x3a
DW_TAG_unspecified_type = 0x3b
DW_TAG_partial_unit = 0x3c
DW_TAG_imported_unit = 0x3d
DW_TAG_condition = 0x3f
DW_TAG_shared_type = 0x40
// Dwarf4
DW_TAG_type_unit = 0x41
DW_TAG_rvalue_reference_type = 0x42
DW_TAG_template_alias = 0x43
// User defined
DW_TAG_lo_user = 0x4080
DW_TAG_hi_user = 0xffff
)
// Table 19
const (
DW_CHILDREN_no = 0x00
DW_CHILDREN_yes = 0x01
)
// Not from the spec, but logically belongs here
const (
DW_CLS_ADDRESS = 0x01 + iota
DW_CLS_BLOCK
DW_CLS_CONSTANT
DW_CLS_FLAG
DW_CLS_PTR // lineptr, loclistptr, macptr, rangelistptr
DW_CLS_REFERENCE
DW_CLS_ADDRLOC
DW_CLS_STRING
// Go-specific internal hackery.
DW_CLS_GO_TYPEREF
)
// Table 20
const (
DW_AT_sibling = 0x01 // reference
DW_AT_location = 0x02 // block, loclistptr
DW_AT_name = 0x03 // string
DW_AT_ordering = 0x09 // constant
DW_AT_byte_size = 0x0b // block, constant, reference
DW_AT_bit_offset = 0x0c // block, constant, reference
DW_AT_bit_size = 0x0d // block, constant, reference
DW_AT_stmt_list = 0x10 // lineptr
DW_AT_low_pc = 0x11 // address
DW_AT_high_pc = 0x12 // address
DW_AT_language = 0x13 // constant
DW_AT_discr = 0x15 // reference
DW_AT_discr_value = 0x16 // constant
DW_AT_visibility = 0x17 // constant
DW_AT_import = 0x18 // reference
DW_AT_string_length = 0x19 // block, loclistptr
DW_AT_common_reference = 0x1a // reference
DW_AT_comp_dir = 0x1b // string
DW_AT_const_value = 0x1c // block, constant, string
DW_AT_containing_type = 0x1d // reference
DW_AT_default_value = 0x1e // reference
DW_AT_inline = 0x20 // constant
DW_AT_is_optional = 0x21 // flag
DW_AT_lower_bound = 0x22 // block, constant, reference
DW_AT_producer = 0x25 // string
DW_AT_prototyped = 0x27 // flag
DW_AT_return_addr = 0x2a // block, loclistptr
DW_AT_start_scope = 0x2c // constant
DW_AT_bit_stride = 0x2e // constant
DW_AT_upper_bound = 0x2f // block, constant, reference
DW_AT_abstract_origin = 0x31 // reference
DW_AT_accessibility = 0x32 // constant
DW_AT_address_class = 0x33 // constant
DW_AT_artificial = 0x34 // flag
DW_AT_base_types = 0x35 // reference
DW_AT_calling_convention = 0x36 // constant
DW_AT_count = 0x37 // block, constant, reference
DW_AT_data_member_location = 0x38 // block, constant, loclistptr
DW_AT_decl_column = 0x39 // constant
DW_AT_decl_file = 0x3a // constant
DW_AT_decl_line = 0x3b // constant
DW_AT_declaration = 0x3c // flag
DW_AT_discr_list = 0x3d // block
DW_AT_encoding = 0x3e // constant
DW_AT_external = 0x3f // flag
DW_AT_frame_base = 0x40 // block, loclistptr
DW_AT_friend = 0x41 // reference
DW_AT_identifier_case = 0x42 // constant
DW_AT_macro_info = 0x43 // macptr
DW_AT_namelist_item = 0x44 // block
DW_AT_priority = 0x45 // reference
DW_AT_segment = 0x46 // block, loclistptr
DW_AT_specification = 0x47 // reference
DW_AT_static_link = 0x48 // block, loclistptr
DW_AT_type = 0x49 // reference
DW_AT_use_location = 0x4a // block, loclistptr
DW_AT_variable_parameter = 0x4b // flag
DW_AT_virtuality = 0x4c // constant
DW_AT_vtable_elem_location = 0x4d // block, loclistptr
// Dwarf3
DW_AT_allocated = 0x4e // block, constant, reference
DW_AT_associated = 0x4f // block, constant, reference
DW_AT_data_location = 0x50 // block
DW_AT_byte_stride = 0x51 // block, constant, reference
DW_AT_entry_pc = 0x52 // address
DW_AT_use_UTF8 = 0x53 // flag
DW_AT_extension = 0x54 // reference
DW_AT_ranges = 0x55 // rangelistptr
DW_AT_trampoline = 0x56 // address, flag, reference, string
DW_AT_call_column = 0x57 // constant
DW_AT_call_file = 0x58 // constant
DW_AT_call_line = 0x59 // constant
DW_AT_description = 0x5a // string
DW_AT_binary_scale = 0x5b // constant
DW_AT_decimal_scale = 0x5c // constant
DW_AT_small = 0x5d // reference
DW_AT_decimal_sign = 0x5e // constant
DW_AT_digit_count = 0x5f // constant
DW_AT_picture_string = 0x60 // string
DW_AT_mutable = 0x61 // flag
DW_AT_threads_scaled = 0x62 // flag
DW_AT_explicit = 0x63 // flag
DW_AT_object_pointer = 0x64 // reference
DW_AT_endianity = 0x65 // constant
DW_AT_elemental = 0x66 // flag
DW_AT_pure = 0x67 // flag
DW_AT_recursive = 0x68 // flag
DW_AT_lo_user = 0x2000 // ---
DW_AT_hi_user = 0x3fff // ---
)
// Table 21
const (
DW_FORM_addr = 0x01 // address
DW_FORM_block2 = 0x03 // block
DW_FORM_block4 = 0x04 // block
DW_FORM_data2 = 0x05 // constant
DW_FORM_data4 = 0x06 // constant, lineptr, loclistptr, macptr, rangelistptr
DW_FORM_data8 = 0x07 // constant, lineptr, loclistptr, macptr, rangelistptr
DW_FORM_string = 0x08 // string
DW_FORM_block = 0x09 // block
DW_FORM_block1 = 0x0a // block
DW_FORM_data1 = 0x0b // constant
DW_FORM_flag = 0x0c // flag
DW_FORM_sdata = 0x0d // constant
DW_FORM_strp = 0x0e // string
DW_FORM_udata = 0x0f // constant
DW_FORM_ref_addr = 0x10 // reference
DW_FORM_ref1 = 0x11 // reference
DW_FORM_ref2 = 0x12 // reference
DW_FORM_ref4 = 0x13 // reference
DW_FORM_ref8 = 0x14 // reference
DW_FORM_ref_udata = 0x15 // reference
DW_FORM_indirect = 0x16 // (see Section 7.5.3)
// Dwarf4
DW_FORM_sec_offset = 0x17 // lineptr, loclistptr, macptr, rangelistptr
DW_FORM_exprloc = 0x18 // exprloc
DW_FORM_flag_present = 0x19 // flag
DW_FORM_ref_sig8 = 0x20 // reference
// Pseudo-form: expanded to data4 on IOS, udata elsewhere.
DW_FORM_udata_pseudo = 0x99
)
// Table 24 (#operands, notes)
const (
DW_OP_addr = 0x03 // 1 constant address (size target specific)
DW_OP_deref = 0x06 // 0
DW_OP_const1u = 0x08 // 1 1-byte constant
DW_OP_const1s = 0x09 // 1 1-byte constant
DW_OP_const2u = 0x0a // 1 2-byte constant
DW_OP_const2s = 0x0b // 1 2-byte constant
DW_OP_const4u = 0x0c // 1 4-byte constant
DW_OP_const4s = 0x0d // 1 4-byte constant
DW_OP_const8u = 0x0e // 1 8-byte constant
DW_OP_const8s = 0x0f // 1 8-byte constant
DW_OP_constu = 0x10 // 1 ULEB128 constant
DW_OP_consts = 0x11 // 1 SLEB128 constant
DW_OP_dup = 0x12 // 0
DW_OP_drop = 0x13 // 0
DW_OP_over = 0x14 // 0
DW_OP_pick = 0x15 // 1 1-byte stack index
DW_OP_swap = 0x16 // 0
DW_OP_rot = 0x17 // 0
DW_OP_xderef = 0x18 // 0
DW_OP_abs = 0x19 // 0
DW_OP_and = 0x1a // 0
DW_OP_div = 0x1b // 0
DW_OP_minus = 0x1c // 0
DW_OP_mod = 0x1d // 0
DW_OP_mul = 0x1e // 0
DW_OP_neg = 0x1f // 0
DW_OP_not = 0x20 // 0
DW_OP_or = 0x21 // 0
DW_OP_plus = 0x22 // 0
DW_OP_plus_uconst = 0x23 // 1 ULEB128 addend
DW_OP_shl = 0x24 // 0
DW_OP_shr = 0x25 // 0
DW_OP_shra = 0x26 // 0
DW_OP_xor = 0x27 // 0
DW_OP_skip = 0x2f // 1 signed 2-byte constant
DW_OP_bra = 0x28 // 1 signed 2-byte constant
DW_OP_eq = 0x29 // 0
DW_OP_ge = 0x2a // 0
DW_OP_gt = 0x2b // 0
DW_OP_le = 0x2c // 0
DW_OP_lt = 0x2d // 0
DW_OP_ne = 0x2e // 0
DW_OP_lit0 = 0x30 // 0 ...
DW_OP_lit31 = 0x4f // 0 literals 0..31 = (DW_OP_lit0 + literal)
DW_OP_reg0 = 0x50 // 0 ..
DW_OP_reg31 = 0x6f // 0 reg 0..31 = (DW_OP_reg0 + regnum)
DW_OP_breg0 = 0x70 // 1 ...
DW_OP_breg31 = 0x8f // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum)
DW_OP_regx = 0x90 // 1 ULEB128 register
DW_OP_fbreg = 0x91 // 1 SLEB128 offset
DW_OP_bregx = 0x92 // 2 ULEB128 register followed by SLEB128 offset
DW_OP_piece = 0x93 // 1 ULEB128 size of piece addressed
DW_OP_deref_size = 0x94 // 1 1-byte size of data retrieved
DW_OP_xderef_size = 0x95 // 1 1-byte size of data retrieved
DW_OP_nop = 0x96 // 0
DW_OP_push_object_address = 0x97 // 0
DW_OP_call2 = 0x98 // 1 2-byte offset of DIE
DW_OP_call4 = 0x99 // 1 4-byte offset of DIE
DW_OP_call_ref = 0x9a // 1 4- or 8-byte offset of DIE
DW_OP_form_tls_address = 0x9b // 0
DW_OP_call_frame_cfa = 0x9c // 0
DW_OP_bit_piece = 0x9d // 2
DW_OP_lo_user = 0xe0
DW_OP_hi_user = 0xff
)
// Table 25
const (
DW_ATE_address = 0x01
DW_ATE_boolean = 0x02
DW_ATE_complex_float = 0x03
DW_ATE_float = 0x04
DW_ATE_signed = 0x05
DW_ATE_signed_char = 0x06
DW_ATE_unsigned = 0x07
DW_ATE_unsigned_char = 0x08
DW_ATE_imaginary_float = 0x09
DW_ATE_packed_decimal = 0x0a
DW_ATE_numeric_string = 0x0b
DW_ATE_edited = 0x0c
DW_ATE_signed_fixed = 0x0d
DW_ATE_unsigned_fixed = 0x0e
DW_ATE_decimal_float = 0x0f
DW_ATE_lo_user = 0x80
DW_ATE_hi_user = 0xff
)
// Table 26
const (
DW_DS_unsigned = 0x01
DW_DS_leading_overpunch = 0x02
DW_DS_trailing_overpunch = 0x03
DW_DS_leading_separate = 0x04
DW_DS_trailing_separate = 0x05
)
// Table 27
const (
DW_END_default = 0x00
DW_END_big = 0x01
DW_END_little = 0x02
DW_END_lo_user = 0x40
DW_END_hi_user = 0xff
)
// Table 28
const (
DW_ACCESS_public = 0x01
DW_ACCESS_protected = 0x02
DW_ACCESS_private = 0x03
)
// Table 29
const (
DW_VIS_local = 0x01
DW_VIS_exported = 0x02
DW_VIS_qualified = 0x03
)
// Table 30
const (
DW_VIRTUALITY_none = 0x00
DW_VIRTUALITY_virtual = 0x01
DW_VIRTUALITY_pure_virtual = 0x02
)
// Table 31
const (
DW_LANG_C89 = 0x0001
DW_LANG_C = 0x0002
DW_LANG_Ada83 = 0x0003
DW_LANG_C_plus_plus = 0x0004
DW_LANG_Cobol74 = 0x0005
DW_LANG_Cobol85 = 0x0006
DW_LANG_Fortran77 = 0x0007
DW_LANG_Fortran90 = 0x0008
DW_LANG_Pascal83 = 0x0009
DW_LANG_Modula2 = 0x000a
// Dwarf3
DW_LANG_Java = 0x000b
DW_LANG_C99 = 0x000c
DW_LANG_Ada95 = 0x000d
DW_LANG_Fortran95 = 0x000e
DW_LANG_PLI = 0x000f
DW_LANG_ObjC = 0x0010
DW_LANG_ObjC_plus_plus = 0x0011
DW_LANG_UPC = 0x0012
DW_LANG_D = 0x0013
// Dwarf4
DW_LANG_Python = 0x0014
// Dwarf5
DW_LANG_Go = 0x0016
DW_LANG_lo_user = 0x8000
DW_LANG_hi_user = 0xffff
)
// Table 32
const (
DW_ID_case_sensitive = 0x00
DW_ID_up_case = 0x01
DW_ID_down_case = 0x02
DW_ID_case_insensitive = 0x03
)
// Table 33
const (
DW_CC_normal = 0x01
DW_CC_program = 0x02
DW_CC_nocall = 0x03
DW_CC_lo_user = 0x40
DW_CC_hi_user = 0xff
)
// Table 34
const (
DW_INL_not_inlined = 0x00
DW_INL_inlined = 0x01
DW_INL_declared_not_inlined = 0x02
DW_INL_declared_inlined = 0x03
)
// Table 35
const (
DW_ORD_row_major = 0x00
DW_ORD_col_major = 0x01
)
// Table 36
const (
DW_DSC_label = 0x00
DW_DSC_range = 0x01
)
// Table 37
const (
DW_LNS_copy = 0x01
DW_LNS_advance_pc = 0x02
DW_LNS_advance_line = 0x03
DW_LNS_set_file = 0x04
DW_LNS_set_column = 0x05
DW_LNS_negate_stmt = 0x06
DW_LNS_set_basic_block = 0x07
DW_LNS_const_add_pc = 0x08
DW_LNS_fixed_advance_pc = 0x09
// Dwarf3
DW_LNS_set_prologue_end = 0x0a
DW_LNS_set_epilogue_begin = 0x0b
DW_LNS_set_isa = 0x0c
)
// Table 38
const (
DW_LNE_end_sequence = 0x01
DW_LNE_set_address = 0x02
DW_LNE_define_file = 0x03
DW_LNE_lo_user = 0x80
DW_LNE_hi_user = 0xff
)
// Table 39
const (
DW_MACINFO_define = 0x01
DW_MACINFO_undef = 0x02
DW_MACINFO_start_file = 0x03
DW_MACINFO_end_file = 0x04
DW_MACINFO_vendor_ext = 0xff
)
// Table 40.
const (
// operand,...
DW_CFA_nop = 0x00
DW_CFA_set_loc = 0x01 // address
DW_CFA_advance_loc1 = 0x02 // 1-byte delta
DW_CFA_advance_loc2 = 0x03 // 2-byte delta
DW_CFA_advance_loc4 = 0x04 // 4-byte delta
DW_CFA_offset_extended = 0x05 // ULEB128 register, ULEB128 offset
DW_CFA_restore_extended = 0x06 // ULEB128 register
DW_CFA_undefined = 0x07 // ULEB128 register
DW_CFA_same_value = 0x08 // ULEB128 register
DW_CFA_register = 0x09 // ULEB128 register, ULEB128 register
DW_CFA_remember_state = 0x0a
DW_CFA_restore_state = 0x0b
DW_CFA_def_cfa = 0x0c // ULEB128 register, ULEB128 offset
DW_CFA_def_cfa_register = 0x0d // ULEB128 register
DW_CFA_def_cfa_offset = 0x0e // ULEB128 offset
DW_CFA_def_cfa_expression = 0x0f // BLOCK
DW_CFA_expression = 0x10 // ULEB128 register, BLOCK
DW_CFA_offset_extended_sf = 0x11 // ULEB128 register, SLEB128 offset
DW_CFA_def_cfa_sf = 0x12 // ULEB128 register, SLEB128 offset
DW_CFA_def_cfa_offset_sf = 0x13 // SLEB128 offset
DW_CFA_val_offset = 0x14 // ULEB128, ULEB128
DW_CFA_val_offset_sf = 0x15 // ULEB128, SLEB128
DW_CFA_val_expression = 0x16 // ULEB128, BLOCK
DW_CFA_lo_user = 0x1c
DW_CFA_hi_user = 0x3f
// Opcodes that take an addend operand.
DW_CFA_advance_loc = 0x1 << 6 // +delta
DW_CFA_offset = 0x2 << 6 // +register (ULEB128 offset)
DW_CFA_restore = 0x3 << 6 // +register
)

View File

@ -0,0 +1,45 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package goobj
// Builtin (compiler-generated) function references appear
// frequently. We assign special indices for them, so they
// don't need to be referenced by name.
// NBuiltin returns the number of listed builtin
// symbols.
func NBuiltin() int {
return len(builtins)
}
// BuiltinName returns the name and ABI of the i-th
// builtin symbol.
func BuiltinName(i int) (string, int) {
return builtins[i].name, builtins[i].abi
}
// BuiltinIdx returns the index of the builtin with the
// given name and abi, or -1 if it is not a builtin.
func BuiltinIdx(name string, abi int) int {
i, ok := builtinMap[name]
if !ok {
return -1
}
if builtins[i].abi != abi {
return -1
}
return i
}
//go:generate go run mkbuiltin.go
var builtinMap map[string]int
func init() {
builtinMap = make(map[string]int, len(builtins))
for i, b := range builtins {
builtinMap[b.name] = i
}
}

View File

@ -0,0 +1,245 @@
// Code generated by mkbuiltin.go. DO NOT EDIT.
package goobj
var builtins = [...]struct {
name string
abi int
}{
{"runtime.newobject", 1},
{"runtime.mallocgc", 1},
{"runtime.panicdivide", 1},
{"runtime.panicshift", 1},
{"runtime.panicmakeslicelen", 1},
{"runtime.panicmakeslicecap", 1},
{"runtime.throwinit", 1},
{"runtime.panicwrap", 1},
{"runtime.gopanic", 1},
{"runtime.gorecover", 1},
{"runtime.goschedguarded", 1},
{"runtime.goPanicIndex", 1},
{"runtime.goPanicIndexU", 1},
{"runtime.goPanicSliceAlen", 1},
{"runtime.goPanicSliceAlenU", 1},
{"runtime.goPanicSliceAcap", 1},
{"runtime.goPanicSliceAcapU", 1},
{"runtime.goPanicSliceB", 1},
{"runtime.goPanicSliceBU", 1},
{"runtime.goPanicSlice3Alen", 1},
{"runtime.goPanicSlice3AlenU", 1},
{"runtime.goPanicSlice3Acap", 1},
{"runtime.goPanicSlice3AcapU", 1},
{"runtime.goPanicSlice3B", 1},
{"runtime.goPanicSlice3BU", 1},
{"runtime.goPanicSlice3C", 1},
{"runtime.goPanicSlice3CU", 1},
{"runtime.printbool", 1},
{"runtime.printfloat", 1},
{"runtime.printint", 1},
{"runtime.printhex", 1},
{"runtime.printuint", 1},
{"runtime.printcomplex", 1},
{"runtime.printstring", 1},
{"runtime.printpointer", 1},
{"runtime.printiface", 1},
{"runtime.printeface", 1},
{"runtime.printslice", 1},
{"runtime.printnl", 1},
{"runtime.printsp", 1},
{"runtime.printlock", 1},
{"runtime.printunlock", 1},
{"runtime.concatstring2", 1},
{"runtime.concatstring3", 1},
{"runtime.concatstring4", 1},
{"runtime.concatstring5", 1},
{"runtime.concatstrings", 1},
{"runtime.cmpstring", 1},
{"runtime.intstring", 1},
{"runtime.slicebytetostring", 1},
{"runtime.slicebytetostringtmp", 1},
{"runtime.slicerunetostring", 1},
{"runtime.stringtoslicebyte", 1},
{"runtime.stringtoslicerune", 1},
{"runtime.slicecopy", 1},
{"runtime.slicestringcopy", 1},
{"runtime.decoderune", 1},
{"runtime.countrunes", 1},
{"runtime.convI2I", 1},
{"runtime.convT16", 1},
{"runtime.convT32", 1},
{"runtime.convT64", 1},
{"runtime.convTstring", 1},
{"runtime.convTslice", 1},
{"runtime.convT2E", 1},
{"runtime.convT2Enoptr", 1},
{"runtime.convT2I", 1},
{"runtime.convT2Inoptr", 1},
{"runtime.assertE2I", 1},
{"runtime.assertE2I2", 1},
{"runtime.assertI2I", 1},
{"runtime.assertI2I2", 1},
{"runtime.panicdottypeE", 1},
{"runtime.panicdottypeI", 1},
{"runtime.panicnildottype", 1},
{"runtime.ifaceeq", 1},
{"runtime.efaceeq", 1},
{"runtime.fastrand", 1},
{"runtime.makemap64", 1},
{"runtime.makemap", 1},
{"runtime.makemap_small", 1},
{"runtime.mapaccess1", 1},
{"runtime.mapaccess1_fast32", 1},
{"runtime.mapaccess1_fast64", 1},
{"runtime.mapaccess1_faststr", 1},
{"runtime.mapaccess1_fat", 1},
{"runtime.mapaccess2", 1},
{"runtime.mapaccess2_fast32", 1},
{"runtime.mapaccess2_fast64", 1},
{"runtime.mapaccess2_faststr", 1},
{"runtime.mapaccess2_fat", 1},
{"runtime.mapassign", 1},
{"runtime.mapassign_fast32", 1},
{"runtime.mapassign_fast32ptr", 1},
{"runtime.mapassign_fast64", 1},
{"runtime.mapassign_fast64ptr", 1},
{"runtime.mapassign_faststr", 1},
{"runtime.mapiterinit", 1},
{"runtime.mapdelete", 1},
{"runtime.mapdelete_fast32", 1},
{"runtime.mapdelete_fast64", 1},
{"runtime.mapdelete_faststr", 1},
{"runtime.mapiternext", 1},
{"runtime.mapclear", 1},
{"runtime.makechan64", 1},
{"runtime.makechan", 1},
{"runtime.chanrecv1", 1},
{"runtime.chanrecv2", 1},
{"runtime.chansend1", 1},
{"runtime.closechan", 1},
{"runtime.writeBarrier", 0},
{"runtime.typedmemmove", 1},
{"runtime.typedmemclr", 1},
{"runtime.typedslicecopy", 1},
{"runtime.selectnbsend", 1},
{"runtime.selectnbrecv", 1},
{"runtime.selectnbrecv2", 1},
{"runtime.selectsetpc", 1},
{"runtime.selectgo", 1},
{"runtime.block", 1},
{"runtime.makeslice", 1},
{"runtime.makeslice64", 1},
{"runtime.makeslicecopy", 1},
{"runtime.growslice", 1},
{"runtime.memmove", 1},
{"runtime.memclrNoHeapPointers", 1},
{"runtime.memclrHasPointers", 1},
{"runtime.memequal", 1},
{"runtime.memequal0", 1},
{"runtime.memequal8", 1},
{"runtime.memequal16", 1},
{"runtime.memequal32", 1},
{"runtime.memequal64", 1},
{"runtime.memequal128", 1},
{"runtime.f32equal", 1},
{"runtime.f64equal", 1},
{"runtime.c64equal", 1},
{"runtime.c128equal", 1},
{"runtime.strequal", 1},
{"runtime.interequal", 1},
{"runtime.nilinterequal", 1},
{"runtime.memhash", 1},
{"runtime.memhash0", 1},
{"runtime.memhash8", 1},
{"runtime.memhash16", 1},
{"runtime.memhash32", 1},
{"runtime.memhash64", 1},
{"runtime.memhash128", 1},
{"runtime.f32hash", 1},
{"runtime.f64hash", 1},
{"runtime.c64hash", 1},
{"runtime.c128hash", 1},
{"runtime.strhash", 1},
{"runtime.interhash", 1},
{"runtime.nilinterhash", 1},
{"runtime.int64div", 1},
{"runtime.uint64div", 1},
{"runtime.int64mod", 1},
{"runtime.uint64mod", 1},
{"runtime.float64toint64", 1},
{"runtime.float64touint64", 1},
{"runtime.float64touint32", 1},
{"runtime.int64tofloat64", 1},
{"runtime.uint64tofloat64", 1},
{"runtime.uint32tofloat64", 1},
{"runtime.complex128div", 1},
{"runtime.racefuncenter", 1},
{"runtime.racefuncenterfp", 1},
{"runtime.racefuncexit", 1},
{"runtime.raceread", 1},
{"runtime.racewrite", 1},
{"runtime.racereadrange", 1},
{"runtime.racewriterange", 1},
{"runtime.msanread", 1},
{"runtime.msanwrite", 1},
{"runtime.checkptrAlignment", 1},
{"runtime.checkptrArithmetic", 1},
{"runtime.libfuzzerTraceCmp1", 1},
{"runtime.libfuzzerTraceCmp2", 1},
{"runtime.libfuzzerTraceCmp4", 1},
{"runtime.libfuzzerTraceCmp8", 1},
{"runtime.libfuzzerTraceConstCmp1", 1},
{"runtime.libfuzzerTraceConstCmp2", 1},
{"runtime.libfuzzerTraceConstCmp4", 1},
{"runtime.libfuzzerTraceConstCmp8", 1},
{"runtime.x86HasPOPCNT", 0},
{"runtime.x86HasSSE41", 0},
{"runtime.x86HasFMA", 0},
{"runtime.armHasVFPv4", 0},
{"runtime.arm64HasATOMICS", 0},
{"runtime.deferproc", 1},
{"runtime.deferprocStack", 1},
{"runtime.deferreturn", 1},
{"runtime.newproc", 1},
{"runtime.panicoverflow", 1},
{"runtime.sigpanic", 1},
{"runtime.gcWriteBarrier", 0},
{"runtime.morestack", 0},
{"runtime.morestackc", 0},
{"runtime.morestack_noctxt", 0},
{"type.int8", 0},
{"type.*int8", 0},
{"type.uint8", 0},
{"type.*uint8", 0},
{"type.int16", 0},
{"type.*int16", 0},
{"type.uint16", 0},
{"type.*uint16", 0},
{"type.int32", 0},
{"type.*int32", 0},
{"type.uint32", 0},
{"type.*uint32", 0},
{"type.int64", 0},
{"type.*int64", 0},
{"type.uint64", 0},
{"type.*uint64", 0},
{"type.float32", 0},
{"type.*float32", 0},
{"type.float64", 0},
{"type.*float64", 0},
{"type.complex64", 0},
{"type.*complex64", 0},
{"type.complex128", 0},
{"type.*complex128", 0},
{"type.unsafe.Pointer", 0},
{"type.*unsafe.Pointer", 0},
{"type.uintptr", 0},
{"type.*uintptr", 0},
{"type.bool", 0},
{"type.*bool", 0},
{"type.string", 0},
{"type.*string", 0},
{"type.error", 0},
{"type.*error", 0},
{"type.func(error) string", 0},
{"type.*func(error) string", 0},
}

View File

@ -0,0 +1,233 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package goobj
import (
"bytes"
"github.com/twitchyliquid64/golang-asm/objabi"
"encoding/binary"
)
// CUFileIndex is used to index the filenames that are stored in the
// per-package/per-CU FileList.
type CUFileIndex uint32
// FuncInfo is serialized as a symbol (aux symbol). The symbol data is
// the binary encoding of the struct below.
//
// TODO: make each pcdata a separate symbol?
type FuncInfo struct {
Args uint32
Locals uint32
FuncID objabi.FuncID
Pcsp uint32
Pcfile uint32
Pcline uint32
Pcinline uint32
Pcdata []uint32
PcdataEnd uint32
Funcdataoff []uint32
File []CUFileIndex
InlTree []InlTreeNode
}
func (a *FuncInfo) Write(w *bytes.Buffer) {
var b [4]byte
writeUint32 := func(x uint32) {
binary.LittleEndian.PutUint32(b[:], x)
w.Write(b[:])
}
writeUint32(a.Args)
writeUint32(a.Locals)
writeUint32(uint32(a.FuncID))
writeUint32(a.Pcsp)
writeUint32(a.Pcfile)
writeUint32(a.Pcline)
writeUint32(a.Pcinline)
writeUint32(uint32(len(a.Pcdata)))
for _, x := range a.Pcdata {
writeUint32(x)
}
writeUint32(a.PcdataEnd)
writeUint32(uint32(len(a.Funcdataoff)))
for _, x := range a.Funcdataoff {
writeUint32(x)
}
writeUint32(uint32(len(a.File)))
for _, f := range a.File {
writeUint32(uint32(f))
}
writeUint32(uint32(len(a.InlTree)))
for i := range a.InlTree {
a.InlTree[i].Write(w)
}
}
func (a *FuncInfo) Read(b []byte) {
readUint32 := func() uint32 {
x := binary.LittleEndian.Uint32(b)
b = b[4:]
return x
}
a.Args = readUint32()
a.Locals = readUint32()
a.FuncID = objabi.FuncID(readUint32())
a.Pcsp = readUint32()
a.Pcfile = readUint32()
a.Pcline = readUint32()
a.Pcinline = readUint32()
pcdatalen := readUint32()
a.Pcdata = make([]uint32, pcdatalen)
for i := range a.Pcdata {
a.Pcdata[i] = readUint32()
}
a.PcdataEnd = readUint32()
funcdataofflen := readUint32()
a.Funcdataoff = make([]uint32, funcdataofflen)
for i := range a.Funcdataoff {
a.Funcdataoff[i] = readUint32()
}
filelen := readUint32()
a.File = make([]CUFileIndex, filelen)
for i := range a.File {
a.File[i] = CUFileIndex(readUint32())
}
inltreelen := readUint32()
a.InlTree = make([]InlTreeNode, inltreelen)
for i := range a.InlTree {
b = a.InlTree[i].Read(b)
}
}
// FuncInfoLengths is a cache containing a roadmap of offsets and
// lengths for things within a serialized FuncInfo. Each length field
// stores the number of items (e.g. files, inltree nodes, etc), and the
// corresponding "off" field stores the byte offset of the start of
// the items in question.
type FuncInfoLengths struct {
NumPcdata uint32
PcdataOff uint32
NumFuncdataoff uint32
FuncdataoffOff uint32
NumFile uint32
FileOff uint32
NumInlTree uint32
InlTreeOff uint32
Initialized bool
}
func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths {
var result FuncInfoLengths
const numpcdataOff = 28
result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:])
result.PcdataOff = numpcdataOff + 4
numfuncdataoffOff := result.PcdataOff + 4*(result.NumPcdata+1)
result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:])
result.FuncdataoffOff = numfuncdataoffOff + 4
numfileOff := result.FuncdataoffOff + 4*result.NumFuncdataoff
result.NumFile = binary.LittleEndian.Uint32(b[numfileOff:])
result.FileOff = numfileOff + 4
numinltreeOff := result.FileOff + 4*result.NumFile
result.NumInlTree = binary.LittleEndian.Uint32(b[numinltreeOff:])
result.InlTreeOff = numinltreeOff + 4
result.Initialized = true
return result
}
func (*FuncInfo) ReadArgs(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) }
func (*FuncInfo) ReadFuncID(b []byte) uint32 { return binary.LittleEndian.Uint32(b[8:]) }
// return start and end offsets.
func (*FuncInfo) ReadPcsp(b []byte) (uint32, uint32) {
return binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])
}
// return start and end offsets.
func (*FuncInfo) ReadPcfile(b []byte) (uint32, uint32) {
return binary.LittleEndian.Uint32(b[16:]), binary.LittleEndian.Uint32(b[20:])
}
// return start and end offsets.
func (*FuncInfo) ReadPcline(b []byte) (uint32, uint32) {
return binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])
}
// return start and end offsets.
func (*FuncInfo) ReadPcinline(b []byte, pcdataoffset uint32) (uint32, uint32) {
return binary.LittleEndian.Uint32(b[24:]), binary.LittleEndian.Uint32(b[pcdataoffset:])
}
// return start and end offsets.
func (*FuncInfo) ReadPcdata(b []byte, pcdataoffset uint32, k uint32) (uint32, uint32) {
return binary.LittleEndian.Uint32(b[pcdataoffset+4*k:]), binary.LittleEndian.Uint32(b[pcdataoffset+4+4*k:])
}
func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 {
return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:]))
}
func (*FuncInfo) ReadFile(b []byte, filesoff uint32, k uint32) CUFileIndex {
return CUFileIndex(binary.LittleEndian.Uint32(b[filesoff+4*k:]))
}
func (*FuncInfo) ReadInlTree(b []byte, inltreeoff uint32, k uint32) InlTreeNode {
const inlTreeNodeSize = 4 * 6
var result InlTreeNode
result.Read(b[inltreeoff+k*inlTreeNodeSize:])
return result
}
// InlTreeNode is the serialized form of FileInfo.InlTree.
type InlTreeNode struct {
Parent int32
File CUFileIndex
Line int32
Func SymRef
ParentPC int32
}
func (inl *InlTreeNode) Write(w *bytes.Buffer) {
var b [4]byte
writeUint32 := func(x uint32) {
binary.LittleEndian.PutUint32(b[:], x)
w.Write(b[:])
}
writeUint32(uint32(inl.Parent))
writeUint32(uint32(inl.File))
writeUint32(uint32(inl.Line))
writeUint32(inl.Func.PkgIdx)
writeUint32(inl.Func.SymIdx)
writeUint32(uint32(inl.ParentPC))
}
// Read an InlTreeNode from b, return the remaining bytes.
func (inl *InlTreeNode) Read(b []byte) []byte {
readUint32 := func() uint32 {
x := binary.LittleEndian.Uint32(b)
b = b[4:]
return x
}
inl.Parent = int32(readUint32())
inl.File = CUFileIndex(readUint32())
inl.Line = int32(readUint32())
inl.Func = SymRef{readUint32(), readUint32()}
inl.ParentPC = int32(readUint32())
return b
}

View File

@ -0,0 +1,871 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This package defines the Go object file format, and provide "low-level" functions
// for reading and writing object files.
// The object file is understood by the compiler, assembler, linker, and tools. They
// have "high level" code that operates on object files, handling application-specific
// logics, and use this package for the actual reading and writing. Specifically, the
// code below:
//
// - cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile)
// - cmd/internal/objfile/goobj.go (used cmd/nm, cmd/objdump)
// - cmd/link/internal/loader package (used by cmd/link)
//
// If the object file format changes, they may (or may not) need to change.
package goobj
import (
"bytes"
"github.com/twitchyliquid64/golang-asm/bio"
"crypto/sha1"
"encoding/binary"
"errors"
"fmt"
"github.com/twitchyliquid64/golang-asm/unsafeheader"
"io"
"unsafe"
)
// New object file format.
//
// Header struct {
// Magic [...]byte // "\x00go116ld"
// Fingerprint [8]byte
// Flags uint32
// Offsets [...]uint32 // byte offset of each block below
// }
//
// Strings [...]struct {
// Data [...]byte
// }
//
// Autolib [...]struct { // imported packages (for file loading)
// Pkg string
// Fingerprint [8]byte
// }
//
// PkgIndex [...]string // referenced packages by index
//
// Files [...]string
//
// SymbolDefs [...]struct {
// Name string
// ABI uint16
// Type uint8
// Flag uint8
// Flag2 uint8
// Size uint32
// }
// Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions
// ... // same as SymbolDefs
// }
// HashedDefs [...]struct { // hashed (content-addressable) symbol definitions
// ... // same as SymbolDefs
// }
// NonPkgDefs [...]struct { // non-pkg symbol definitions
// ... // same as SymbolDefs
// }
// NonPkgRefs [...]struct { // non-pkg symbol references
// ... // same as SymbolDefs
// }
//
// RefFlags [...]struct { // referenced symbol flags
// Sym symRef
// Flag uint8
// Flag2 uint8
// }
//
// Hash64 [...][8]byte
// Hash [...][N]byte
//
// RelocIndex [...]uint32 // index to Relocs
// AuxIndex [...]uint32 // index to Aux
// DataIndex [...]uint32 // offset to Data
//
// Relocs [...]struct {
// Off int32
// Size uint8
// Type uint8
// Add int64
// Sym symRef
// }
//
// Aux [...]struct {
// Type uint8
// Sym symRef
// }
//
// Data [...]byte
// Pcdata [...]byte
//
// // blocks only used by tools (objdump, nm)
//
// RefNames [...]struct { // referenced symbol names
// Sym symRef
// Name string
// // TODO: include ABI version as well?
// }
//
// string is encoded as is a uint32 length followed by a uint32 offset
// that points to the corresponding string bytes.
//
// symRef is struct { PkgIdx, SymIdx uint32 }.
//
// Slice type (e.g. []symRef) is encoded as a length prefix (uint32)
// followed by that number of elements.
//
// The types below correspond to the encoded data structure in the
// object file.
// Symbol indexing.
//
// Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx },
// as the symRef struct above.
//
// PkgIdx is either a predeclared index (see PkgIdxNone below) or
// an index of an imported package. For the latter case, PkgIdx is the
// index of the package in the PkgIndex array. 0 is an invalid index.
//
// SymIdx is the index of the symbol in the given package.
// - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the
// SymbolDefs array.
// - If PkgIdx is PkgIdxHashed64, SymIdx is the index of the symbol in the
// Hashed64Defs array.
// - If PkgIdx is PkgIdxHashed, SymIdx is the index of the symbol in the
// HashedDefs array.
// - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the
// NonPkgDefs array (could natually overflow to NonPkgRefs array).
// - Otherwise, SymIdx is the index of the symbol in some other package's
// SymbolDefs array.
//
// {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0.
//
// Hash contains the content hashes of content-addressable symbols, of
// which PkgIdx is PkgIdxHashed, in the same order of HashedDefs array.
// Hash64 is similar, for PkgIdxHashed64 symbols.
//
// RelocIndex, AuxIndex, and DataIndex contains indices/offsets to
// Relocs/Aux/Data blocks, one element per symbol, first for all the
// defined symbols, then all the defined hashed and non-package symbols,
// in the same order of SymbolDefs/Hashed64Defs/HashedDefs/NonPkgDefs
// arrays. For N total defined symbols, the array is of length N+1. The
// last element is the total number of relocations (aux symbols, data
// blocks, etc.).
//
// They can be accessed by index. For the i-th symbol, its relocations
// are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive)
// elements in the Relocs array. Aux/Data are likewise. (The index is
// 0-based.)
// Auxiliary symbols.
//
// Each symbol may (or may not) be associated with a number of auxiliary
// symbols. They are described in the Aux block. See Aux struct below.
// Currently a symbol's Gotype, FuncInfo, and associated DWARF symbols
// are auxiliary symbols.
const stringRefSize = 8 // two uint32s
type FingerprintType [8]byte
func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} }
// Package Index.
const (
PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols
PkgIdxHashed64 // Short hashed (content-addressable) symbols
PkgIdxHashed // Hashed (content-addressable) symbols
PkgIdxBuiltin // Predefined runtime symbols (ex: runtime.newobject)
PkgIdxSelf // Symbols defined in the current package
PkgIdxInvalid = 0
// The index of other referenced packages starts from 1.
)
// Blocks
const (
BlkAutolib = iota
BlkPkgIdx
BlkFile
BlkSymdef
BlkHashed64def
BlkHasheddef
BlkNonpkgdef
BlkNonpkgref
BlkRefFlags
BlkHash64
BlkHash
BlkRelocIdx
BlkAuxIdx
BlkDataIdx
BlkReloc
BlkAux
BlkData
BlkPcdata
BlkRefName
BlkEnd
NBlk
)
// File header.
// TODO: probably no need to export this.
type Header struct {
Magic string
Fingerprint FingerprintType
Flags uint32
Offsets [NBlk]uint32
}
const Magic = "\x00go116ld"
func (h *Header) Write(w *Writer) {
w.RawString(h.Magic)
w.Bytes(h.Fingerprint[:])
w.Uint32(h.Flags)
for _, x := range h.Offsets {
w.Uint32(x)
}
}
func (h *Header) Read(r *Reader) error {
b := r.BytesAt(0, len(Magic))
h.Magic = string(b)
if h.Magic != Magic {
return errors.New("wrong magic, not a Go object file")
}
off := uint32(len(h.Magic))
copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint)))
off += 8
h.Flags = r.uint32At(off)
off += 4
for i := range h.Offsets {
h.Offsets[i] = r.uint32At(off)
off += 4
}
return nil
}
func (h *Header) Size() int {
return len(h.Magic) + 4 + 4*len(h.Offsets)
}
// Autolib
type ImportedPkg struct {
Pkg string
Fingerprint FingerprintType
}
const importedPkgSize = stringRefSize + 8
func (p *ImportedPkg) Write(w *Writer) {
w.StringRef(p.Pkg)
w.Bytes(p.Fingerprint[:])
}
// Symbol definition.
//
// Serialized format:
// Sym struct {
// Name string
// ABI uint16
// Type uint8
// Flag uint8
// Flag2 uint8
// Siz uint32
// Align uint32
// }
type Sym [SymSize]byte
const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4
const SymABIstatic = ^uint16(0)
const (
ObjFlagShared = 1 << iota // this object is built with -shared
ObjFlagNeedNameExpansion // the linker needs to expand `"".` to package path in symbol names
ObjFlagFromAssembly // object is from asm src, not go
)
// Sym.Flag
const (
SymFlagDupok = 1 << iota
SymFlagLocal
SymFlagTypelink
SymFlagLeaf
SymFlagNoSplit
SymFlagReflectMethod
SymFlagGoType
SymFlagTopFrame
)
// Sym.Flag2
const (
SymFlagUsedInIface = 1 << iota
SymFlagItab
)
// Returns the length of the name of the symbol.
func (s *Sym) NameLen(r *Reader) int {
return int(binary.LittleEndian.Uint32(s[:]))
}
func (s *Sym) Name(r *Reader) string {
len := binary.LittleEndian.Uint32(s[:])
off := binary.LittleEndian.Uint32(s[4:])
return r.StringAt(off, len)
}
func (s *Sym) ABI() uint16 { return binary.LittleEndian.Uint16(s[8:]) }
func (s *Sym) Type() uint8 { return s[10] }
func (s *Sym) Flag() uint8 { return s[11] }
func (s *Sym) Flag2() uint8 { return s[12] }
func (s *Sym) Siz() uint32 { return binary.LittleEndian.Uint32(s[13:]) }
func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) }
func (s *Sym) Dupok() bool { return s.Flag()&SymFlagDupok != 0 }
func (s *Sym) Local() bool { return s.Flag()&SymFlagLocal != 0 }
func (s *Sym) Typelink() bool { return s.Flag()&SymFlagTypelink != 0 }
func (s *Sym) Leaf() bool { return s.Flag()&SymFlagLeaf != 0 }
func (s *Sym) NoSplit() bool { return s.Flag()&SymFlagNoSplit != 0 }
func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 }
func (s *Sym) IsGoType() bool { return s.Flag()&SymFlagGoType != 0 }
func (s *Sym) TopFrame() bool { return s.Flag()&SymFlagTopFrame != 0 }
func (s *Sym) UsedInIface() bool { return s.Flag2()&SymFlagUsedInIface != 0 }
func (s *Sym) IsItab() bool { return s.Flag2()&SymFlagItab != 0 }
func (s *Sym) SetName(x string, w *Writer) {
binary.LittleEndian.PutUint32(s[:], uint32(len(x)))
binary.LittleEndian.PutUint32(s[4:], w.stringOff(x))
}
func (s *Sym) SetABI(x uint16) { binary.LittleEndian.PutUint16(s[8:], x) }
func (s *Sym) SetType(x uint8) { s[10] = x }
func (s *Sym) SetFlag(x uint8) { s[11] = x }
func (s *Sym) SetFlag2(x uint8) { s[12] = x }
func (s *Sym) SetSiz(x uint32) { binary.LittleEndian.PutUint32(s[13:], x) }
func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) }
func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) }
// for testing
func (s *Sym) fromBytes(b []byte) { copy(s[:], b) }
// Symbol reference.
type SymRef struct {
PkgIdx uint32
SymIdx uint32
}
// Hash64
type Hash64Type [Hash64Size]byte
const Hash64Size = 8
// Hash
type HashType [HashSize]byte
const HashSize = sha1.Size
// Relocation.
//
// Serialized format:
// Reloc struct {
// Off int32
// Siz uint8
// Type uint8
// Add int64
// Sym SymRef
// }
type Reloc [RelocSize]byte
const RelocSize = 4 + 1 + 1 + 8 + 8
func (r *Reloc) Off() int32 { return int32(binary.LittleEndian.Uint32(r[:])) }
func (r *Reloc) Siz() uint8 { return r[4] }
func (r *Reloc) Type() uint8 { return r[5] }
func (r *Reloc) Add() int64 { return int64(binary.LittleEndian.Uint64(r[6:])) }
func (r *Reloc) Sym() SymRef {
return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])}
}
func (r *Reloc) SetOff(x int32) { binary.LittleEndian.PutUint32(r[:], uint32(x)) }
func (r *Reloc) SetSiz(x uint8) { r[4] = x }
func (r *Reloc) SetType(x uint8) { r[5] = x }
func (r *Reloc) SetAdd(x int64) { binary.LittleEndian.PutUint64(r[6:], uint64(x)) }
func (r *Reloc) SetSym(x SymRef) {
binary.LittleEndian.PutUint32(r[14:], x.PkgIdx)
binary.LittleEndian.PutUint32(r[18:], x.SymIdx)
}
func (r *Reloc) Set(off int32, size uint8, typ uint8, add int64, sym SymRef) {
r.SetOff(off)
r.SetSiz(size)
r.SetType(typ)
r.SetAdd(add)
r.SetSym(sym)
}
func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) }
// for testing
func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) }
// Aux symbol info.
//
// Serialized format:
// Aux struct {
// Type uint8
// Sym SymRef
// }
type Aux [AuxSize]byte
const AuxSize = 1 + 8
// Aux Type
const (
AuxGotype = iota
AuxFuncInfo
AuxFuncdata
AuxDwarfInfo
AuxDwarfLoc
AuxDwarfRanges
AuxDwarfLines
// TODO: more. Pcdata?
)
func (a *Aux) Type() uint8 { return a[0] }
func (a *Aux) Sym() SymRef {
return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])}
}
func (a *Aux) SetType(x uint8) { a[0] = x }
func (a *Aux) SetSym(x SymRef) {
binary.LittleEndian.PutUint32(a[1:], x.PkgIdx)
binary.LittleEndian.PutUint32(a[5:], x.SymIdx)
}
func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
// for testing
func (a *Aux) fromBytes(b []byte) { copy(a[:], b) }
// Referenced symbol flags.
//
// Serialized format:
// RefFlags struct {
// Sym symRef
// Flag uint8
// Flag2 uint8
// }
type RefFlags [RefFlagsSize]byte
const RefFlagsSize = 8 + 1 + 1
func (r *RefFlags) Sym() SymRef {
return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])}
}
func (r *RefFlags) Flag() uint8 { return r[8] }
func (r *RefFlags) Flag2() uint8 { return r[9] }
func (r *RefFlags) SetSym(x SymRef) {
binary.LittleEndian.PutUint32(r[:], x.PkgIdx)
binary.LittleEndian.PutUint32(r[4:], x.SymIdx)
}
func (r *RefFlags) SetFlag(x uint8) { r[8] = x }
func (r *RefFlags) SetFlag2(x uint8) { r[9] = x }
func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) }
// Referenced symbol name.
//
// Serialized format:
// RefName struct {
// Sym symRef
// Name string
// }
type RefName [RefNameSize]byte
const RefNameSize = 8 + stringRefSize
func (n *RefName) Sym() SymRef {
return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])}
}
func (n *RefName) Name(r *Reader) string {
len := binary.LittleEndian.Uint32(n[8:])
off := binary.LittleEndian.Uint32(n[12:])
return r.StringAt(off, len)
}
func (n *RefName) SetSym(x SymRef) {
binary.LittleEndian.PutUint32(n[:], x.PkgIdx)
binary.LittleEndian.PutUint32(n[4:], x.SymIdx)
}
func (n *RefName) SetName(x string, w *Writer) {
binary.LittleEndian.PutUint32(n[8:], uint32(len(x)))
binary.LittleEndian.PutUint32(n[12:], w.stringOff(x))
}
func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) }
type Writer struct {
wr *bio.Writer
stringMap map[string]uint32
off uint32 // running offset
}
func NewWriter(wr *bio.Writer) *Writer {
return &Writer{wr: wr, stringMap: make(map[string]uint32)}
}
func (w *Writer) AddString(s string) {
if _, ok := w.stringMap[s]; ok {
return
}
w.stringMap[s] = w.off
w.RawString(s)
}
func (w *Writer) stringOff(s string) uint32 {
off, ok := w.stringMap[s]
if !ok {
panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
}
return off
}
func (w *Writer) StringRef(s string) {
w.Uint32(uint32(len(s)))
w.Uint32(w.stringOff(s))
}
func (w *Writer) RawString(s string) {
w.wr.WriteString(s)
w.off += uint32(len(s))
}
func (w *Writer) Bytes(s []byte) {
w.wr.Write(s)
w.off += uint32(len(s))
}
func (w *Writer) Uint64(x uint64) {
var b [8]byte
binary.LittleEndian.PutUint64(b[:], x)
w.wr.Write(b[:])
w.off += 8
}
func (w *Writer) Uint32(x uint32) {
var b [4]byte
binary.LittleEndian.PutUint32(b[:], x)
w.wr.Write(b[:])
w.off += 4
}
func (w *Writer) Uint16(x uint16) {
var b [2]byte
binary.LittleEndian.PutUint16(b[:], x)
w.wr.Write(b[:])
w.off += 2
}
func (w *Writer) Uint8(x uint8) {
w.wr.WriteByte(x)
w.off++
}
func (w *Writer) Offset() uint32 {
return w.off
}
type Reader struct {
b []byte // mmapped bytes, if not nil
readonly bool // whether b is backed with read-only memory
rd io.ReaderAt
start uint32
h Header // keep block offsets
}
func NewReaderFromBytes(b []byte, readonly bool) *Reader {
r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0}
err := r.h.Read(r)
if err != nil {
return nil
}
return r
}
func (r *Reader) BytesAt(off uint32, len int) []byte {
if len == 0 {
return nil
}
end := int(off) + len
return r.b[int(off):end:end]
}
func (r *Reader) uint64At(off uint32) uint64 {
b := r.BytesAt(off, 8)
return binary.LittleEndian.Uint64(b)
}
func (r *Reader) int64At(off uint32) int64 {
return int64(r.uint64At(off))
}
func (r *Reader) uint32At(off uint32) uint32 {
b := r.BytesAt(off, 4)
return binary.LittleEndian.Uint32(b)
}
func (r *Reader) int32At(off uint32) int32 {
return int32(r.uint32At(off))
}
func (r *Reader) uint16At(off uint32) uint16 {
b := r.BytesAt(off, 2)
return binary.LittleEndian.Uint16(b)
}
func (r *Reader) uint8At(off uint32) uint8 {
b := r.BytesAt(off, 1)
return b[0]
}
func (r *Reader) StringAt(off uint32, len uint32) string {
b := r.b[off : off+len]
if r.readonly {
return toString(b) // backed by RO memory, ok to make unsafe string
}
return string(b)
}
func toString(b []byte) string {
if len(b) == 0 {
return ""
}
var s string
hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
hdr.Data = unsafe.Pointer(&b[0])
hdr.Len = len(b)
return s
}
func (r *Reader) StringRef(off uint32) string {
l := r.uint32At(off)
return r.StringAt(r.uint32At(off+4), l)
}
func (r *Reader) Fingerprint() FingerprintType {
return r.h.Fingerprint
}
func (r *Reader) Autolib() []ImportedPkg {
n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize
s := make([]ImportedPkg, n)
off := r.h.Offsets[BlkAutolib]
for i := range s {
s[i].Pkg = r.StringRef(off)
copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
off += importedPkgSize
}
return s
}
func (r *Reader) Pkglist() []string {
n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
s := make([]string, n)
off := r.h.Offsets[BlkPkgIdx]
for i := range s {
s[i] = r.StringRef(off)
off += stringRefSize
}
return s
}
func (r *Reader) NPkg() int {
return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize
}
func (r *Reader) Pkg(i int) string {
off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
return r.StringRef(off)
}
func (r *Reader) NFile() int {
return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize
}
func (r *Reader) File(i int) string {
off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize
return r.StringRef(off)
}
func (r *Reader) NSym() int {
return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize
}
func (r *Reader) NHashed64def() int {
return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize
}
func (r *Reader) NHasheddef() int {
return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize
}
func (r *Reader) NNonpkgdef() int {
return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize
}
func (r *Reader) NNonpkgref() int {
return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize
}
// SymOff returns the offset of the i-th symbol.
func (r *Reader) SymOff(i uint32) uint32 {
return r.h.Offsets[BlkSymdef] + uint32(i*SymSize)
}
// Sym returns a pointer to the i-th symbol.
func (r *Reader) Sym(i uint32) *Sym {
off := r.SymOff(i)
return (*Sym)(unsafe.Pointer(&r.b[off]))
}
// NRefFlags returns the number of referenced symbol flags.
func (r *Reader) NRefFlags() int {
return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize
}
// RefFlags returns a pointer to the i-th referenced symbol flags.
// Note: here i is not a local symbol index, just a counter.
func (r *Reader) RefFlags(i int) *RefFlags {
off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize)
return (*RefFlags)(unsafe.Pointer(&r.b[off]))
}
// Hash64 returns the i-th short hashed symbol's hash.
// Note: here i is the index of short hashed symbols, not all symbols
// (unlike other accessors).
func (r *Reader) Hash64(i uint32) uint64 {
off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size)
return r.uint64At(off)
}
// Hash returns a pointer to the i-th hashed symbol's hash.
// Note: here i is the index of hashed symbols, not all symbols
// (unlike other accessors).
func (r *Reader) Hash(i uint32) *HashType {
off := r.h.Offsets[BlkHash] + uint32(i*HashSize)
return (*HashType)(unsafe.Pointer(&r.b[off]))
}
// NReloc returns the number of relocations of the i-th symbol.
func (r *Reader) NReloc(i uint32) int {
relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
}
// RelocOff returns the offset of the j-th relocation of the i-th symbol.
func (r *Reader) RelocOff(i uint32, j int) uint32 {
relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
relocIdx := r.uint32At(relocIdxOff)
return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize)
}
// Reloc returns a pointer to the j-th relocation of the i-th symbol.
func (r *Reader) Reloc(i uint32, j int) *Reloc {
off := r.RelocOff(i, j)
return (*Reloc)(unsafe.Pointer(&r.b[off]))
}
// Relocs returns a pointer to the relocations of the i-th symbol.
func (r *Reader) Relocs(i uint32) []Reloc {
off := r.RelocOff(i, 0)
n := r.NReloc(i)
return (*[1 << 20]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n]
}
// NAux returns the number of aux symbols of the i-th symbol.
func (r *Reader) NAux(i uint32) int {
auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
}
// AuxOff returns the offset of the j-th aux symbol of the i-th symbol.
func (r *Reader) AuxOff(i uint32, j int) uint32 {
auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
auxIdx := r.uint32At(auxIdxOff)
return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize)
}
// Aux returns a pointer to the j-th aux symbol of the i-th symbol.
func (r *Reader) Aux(i uint32, j int) *Aux {
off := r.AuxOff(i, j)
return (*Aux)(unsafe.Pointer(&r.b[off]))
}
// Auxs returns the aux symbols of the i-th symbol.
func (r *Reader) Auxs(i uint32) []Aux {
off := r.AuxOff(i, 0)
n := r.NAux(i)
return (*[1 << 20]Aux)(unsafe.Pointer(&r.b[off]))[:n:n]
}
// DataOff returns the offset of the i-th symbol's data.
func (r *Reader) DataOff(i uint32) uint32 {
dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
}
// DataSize returns the size of the i-th symbol's data.
func (r *Reader) DataSize(i uint32) int {
dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff))
}
// Data returns the i-th symbol's data.
func (r *Reader) Data(i uint32) []byte {
dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
base := r.h.Offsets[BlkData]
off := r.uint32At(dataIdxOff)
end := r.uint32At(dataIdxOff + 4)
return r.BytesAt(base+off, int(end-off))
}
// AuxDataBase returns the base offset of the aux data block.
func (r *Reader) PcdataBase() uint32 {
return r.h.Offsets[BlkPcdata]
}
// NRefName returns the number of referenced symbol names.
func (r *Reader) NRefName() int {
return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
}
// RefName returns a pointer to the i-th referenced symbol name.
// Note: here i is not a local symbol index, just a counter.
func (r *Reader) RefName(i int) *RefName {
off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize)
return (*RefName)(unsafe.Pointer(&r.b[off]))
}
// ReadOnly returns whether r.BytesAt returns read-only bytes.
func (r *Reader) ReadOnly() bool {
return r.readonly
}
// Flags returns the flag bits read from the object file header.
func (r *Reader) Flags() uint32 {
return r.h.Flags
}
func (r *Reader) Shared() bool { return r.Flags()&ObjFlagShared != 0 }
func (r *Reader) NeedNameExpansion() bool { return r.Flags()&ObjFlagNeedNameExpansion != 0 }
func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 }

View File

@ -0,0 +1,16 @@
// Code generated by "stringer -type ABI"; DO NOT EDIT.
package obj
import "strconv"
const _ABI_name = "ABI0ABIInternalABICount"
var _ABI_index = [...]uint8{0, 4, 15, 23}
func (i ABI) String() string {
if i >= ABI(len(_ABI_index)-1) {
return "ABI(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _ABI_name[_ABI_index[i]:_ABI_index[i+1]]
}

View File

@ -0,0 +1,16 @@
// Code generated by "stringer -type AddrType"; DO NOT EDIT.
package obj
import "strconv"
const _AddrType_name = "TYPE_NONETYPE_BRANCHTYPE_TEXTSIZETYPE_MEMTYPE_CONSTTYPE_FCONSTTYPE_SCONSTTYPE_REGTYPE_ADDRTYPE_SHIFTTYPE_REGREGTYPE_REGREG2TYPE_INDIRTYPE_REGLIST"
var _AddrType_index = [...]uint8{0, 9, 20, 33, 41, 51, 62, 73, 81, 90, 100, 111, 123, 133, 145}
func (i AddrType) String() string {
if i >= AddrType(len(_AddrType_index)-1) {
return "AddrType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _AddrType_name[_AddrType_index[i]:_AddrType_index[i+1]]
}

View File

@ -0,0 +1,410 @@
// Inferno utils/5c/5.out.h
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5c/5.out.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package arm
import "github.com/twitchyliquid64/golang-asm/obj"
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm
const (
NSNAME = 8
NSYM = 50
NREG = 16
)
/* -1 disables use of REGARG */
const (
REGARG = -1
)
const (
REG_R0 = obj.RBaseARM + iota // must be 16-aligned
REG_R1
REG_R2
REG_R3
REG_R4
REG_R5
REG_R6
REG_R7
REG_R8
REG_R9
REG_R10
REG_R11
REG_R12
REG_R13
REG_R14
REG_R15
REG_F0 // must be 16-aligned
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_F8
REG_F9
REG_F10
REG_F11
REG_F12
REG_F13
REG_F14
REG_F15
REG_FPSR // must be 2-aligned
REG_FPCR
REG_CPSR // must be 2-aligned
REG_SPSR
REGRET = REG_R0
/* compiler allocates R1 up as temps */
/* compiler allocates register variables R3 up */
/* compiler allocates external registers R10 down */
REGEXT = REG_R10
/* these two registers are declared in runtime.h */
REGG = REGEXT - 0
REGM = REGEXT - 1
REGCTXT = REG_R7
REGTMP = REG_R11
REGSP = REG_R13
REGLINK = REG_R14
REGPC = REG_R15
NFREG = 16
/* compiler allocates register variables F0 up */
/* compiler allocates external registers F7 down */
FREGRET = REG_F0
FREGEXT = REG_F7
FREGTMP = REG_F15
)
// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040b/IHI0040B_aadwarf.pdf
var ARMDWARFRegisters = map[int16]int16{}
func init() {
// f assigns dwarfregisters[from:to] = (base):(step*(to-from)+base)
f := func(from, to, base, step int16) {
for r := int16(from); r <= to; r++ {
ARMDWARFRegisters[r] = step*(r-from) + base
}
}
f(REG_R0, REG_R15, 0, 1)
f(REG_F0, REG_F15, 64, 2) // Use d0 through D15, aka S0, S2, ..., S30
}
// Special registers, after subtracting obj.RBaseARM, bit 9 indicates
// a special register and the low bits select the register.
const (
REG_SPECIAL = obj.RBaseARM + 1<<9 + iota
REG_MB_SY
REG_MB_ST
REG_MB_ISH
REG_MB_ISHST
REG_MB_NSH
REG_MB_NSHST
REG_MB_OSH
REG_MB_OSHST
MAXREG
)
const (
C_NONE = iota
C_REG
C_REGREG
C_REGREG2
C_REGLIST
C_SHIFT /* register shift R>>x */
C_SHIFTADDR /* memory address with shifted offset R>>x(R) */
C_FREG
C_PSR
C_FCR
C_SPR /* REG_MB_SY */
C_RCON /* 0xff rotated */
C_NCON /* ~RCON */
C_RCON2A /* OR of two disjoint C_RCON constants */
C_RCON2S /* subtraction of two disjoint C_RCON constants */
C_SCON /* 0xffff */
C_LCON
C_LCONADDR
C_ZFCON
C_SFCON
C_LFCON
C_RACON
C_LACON
C_SBRA
C_LBRA
C_HAUTO /* halfword insn offset (-0xff to 0xff) */
C_FAUTO /* float insn offset (0 to 0x3fc, word aligned) */
C_HFAUTO /* both H and F */
C_SAUTO /* -0xfff to 0xfff */
C_LAUTO
C_HOREG
C_FOREG
C_HFOREG
C_SOREG
C_ROREG
C_SROREG /* both nil and R */
C_LOREG
C_PC
C_SP
C_HREG
C_ADDR /* reference to relocatable address */
// TLS "var" in local exec mode: will become a constant offset from
// thread local base that is ultimately chosen by the program linker.
C_TLS_LE
// TLS "var" in initial exec mode: will become a memory address (chosen
// by the program linker) that the dynamic linker will fill with the
// offset from the thread local base.
C_TLS_IE
C_TEXTSIZE
C_GOK
C_NCLASS /* must be the last */
)
const (
AAND = obj.ABaseARM + obj.A_ARCHSPECIFIC + iota
AEOR
ASUB
ARSB
AADD
AADC
ASBC
ARSC
ATST
ATEQ
ACMP
ACMN
AORR
ABIC
AMVN
/*
* Do not reorder or fragment the conditional branch
* opcodes, or the predication code will break
*/
ABEQ
ABNE
ABCS
ABHS
ABCC
ABLO
ABMI
ABPL
ABVS
ABVC
ABHI
ABLS
ABGE
ABLT
ABGT
ABLE
AMOVWD
AMOVWF
AMOVDW
AMOVFW
AMOVFD
AMOVDF
AMOVF
AMOVD
ACMPF
ACMPD
AADDF
AADDD
ASUBF
ASUBD
AMULF
AMULD
ANMULF
ANMULD
AMULAF
AMULAD
ANMULAF
ANMULAD
AMULSF
AMULSD
ANMULSF
ANMULSD
AFMULAF
AFMULAD
AFNMULAF
AFNMULAD
AFMULSF
AFMULSD
AFNMULSF
AFNMULSD
ADIVF
ADIVD
ASQRTF
ASQRTD
AABSF
AABSD
ANEGF
ANEGD
ASRL
ASRA
ASLL
AMULU
ADIVU
AMUL
AMMUL
ADIV
AMOD
AMODU
ADIVHW
ADIVUHW
AMOVB
AMOVBS
AMOVBU
AMOVH
AMOVHS
AMOVHU
AMOVW
AMOVM
ASWPBU
ASWPW
ARFE
ASWI
AMULA
AMULS
AMMULA
AMMULS
AWORD
AMULL
AMULAL
AMULLU
AMULALU
ABX
ABXRET
ADWORD
ALDREX
ASTREX
ALDREXD
ASTREXD
ADMB
APLD
ACLZ
AREV
AREV16
AREVSH
ARBIT
AXTAB
AXTAH
AXTABU
AXTAHU
ABFX
ABFXU
ABFC
ABFI
AMULWT
AMULWB
AMULBB
AMULAWT
AMULAWB
AMULABB
AMRC // MRC/MCR
ALAST
// aliases
AB = obj.AJMP
ABL = obj.ACALL
)
/* scond byte */
const (
C_SCOND = (1 << 4) - 1
C_SBIT = 1 << 4
C_PBIT = 1 << 5
C_WBIT = 1 << 6
C_FBIT = 1 << 7 /* psr flags-only */
C_UBIT = 1 << 7 /* up bit, unsigned bit */
// These constants are the ARM condition codes encodings,
// XORed with 14 so that C_SCOND_NONE has value 0,
// so that a zeroed Prog.scond means "always execute".
C_SCOND_XOR = 14
C_SCOND_EQ = 0 ^ C_SCOND_XOR
C_SCOND_NE = 1 ^ C_SCOND_XOR
C_SCOND_HS = 2 ^ C_SCOND_XOR
C_SCOND_LO = 3 ^ C_SCOND_XOR
C_SCOND_MI = 4 ^ C_SCOND_XOR
C_SCOND_PL = 5 ^ C_SCOND_XOR
C_SCOND_VS = 6 ^ C_SCOND_XOR
C_SCOND_VC = 7 ^ C_SCOND_XOR
C_SCOND_HI = 8 ^ C_SCOND_XOR
C_SCOND_LS = 9 ^ C_SCOND_XOR
C_SCOND_GE = 10 ^ C_SCOND_XOR
C_SCOND_LT = 11 ^ C_SCOND_XOR
C_SCOND_GT = 12 ^ C_SCOND_XOR
C_SCOND_LE = 13 ^ C_SCOND_XOR
C_SCOND_NONE = 14 ^ C_SCOND_XOR
C_SCOND_NV = 15 ^ C_SCOND_XOR
/* D_SHIFT type */
SHIFT_LL = 0 << 5
SHIFT_LR = 1 << 5
SHIFT_AR = 2 << 5
SHIFT_RR = 3 << 5
)

View File

@ -0,0 +1,144 @@
// Code generated by stringer -i a.out.go -o anames.go -p arm; DO NOT EDIT.
package arm
import "github.com/twitchyliquid64/golang-asm/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "AND",
"EOR",
"SUB",
"RSB",
"ADD",
"ADC",
"SBC",
"RSC",
"TST",
"TEQ",
"CMP",
"CMN",
"ORR",
"BIC",
"MVN",
"BEQ",
"BNE",
"BCS",
"BHS",
"BCC",
"BLO",
"BMI",
"BPL",
"BVS",
"BVC",
"BHI",
"BLS",
"BGE",
"BLT",
"BGT",
"BLE",
"MOVWD",
"MOVWF",
"MOVDW",
"MOVFW",
"MOVFD",
"MOVDF",
"MOVF",
"MOVD",
"CMPF",
"CMPD",
"ADDF",
"ADDD",
"SUBF",
"SUBD",
"MULF",
"MULD",
"NMULF",
"NMULD",
"MULAF",
"MULAD",
"NMULAF",
"NMULAD",
"MULSF",
"MULSD",
"NMULSF",
"NMULSD",
"FMULAF",
"FMULAD",
"FNMULAF",
"FNMULAD",
"FMULSF",
"FMULSD",
"FNMULSF",
"FNMULSD",
"DIVF",
"DIVD",
"SQRTF",
"SQRTD",
"ABSF",
"ABSD",
"NEGF",
"NEGD",
"SRL",
"SRA",
"SLL",
"MULU",
"DIVU",
"MUL",
"MMUL",
"DIV",
"MOD",
"MODU",
"DIVHW",
"DIVUHW",
"MOVB",
"MOVBS",
"MOVBU",
"MOVH",
"MOVHS",
"MOVHU",
"MOVW",
"MOVM",
"SWPBU",
"SWPW",
"RFE",
"SWI",
"MULA",
"MULS",
"MMULA",
"MMULS",
"WORD",
"MULL",
"MULAL",
"MULLU",
"MULALU",
"BX",
"BXRET",
"DWORD",
"LDREX",
"STREX",
"LDREXD",
"STREXD",
"DMB",
"PLD",
"CLZ",
"REV",
"REV16",
"REVSH",
"RBIT",
"XTAB",
"XTAH",
"XTABU",
"XTAHU",
"BFX",
"BFXU",
"BFC",
"BFI",
"MULWT",
"MULWB",
"MULBB",
"MULAWT",
"MULAWB",
"MULABB",
"MRC",
"LAST",
}

View File

@ -0,0 +1,77 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm
var cnames5 = []string{
"NONE",
"REG",
"REGREG",
"REGREG2",
"REGLIST",
"SHIFT",
"SHIFTADDR",
"FREG",
"PSR",
"FCR",
"SPR",
"RCON",
"NCON",
"RCON2A",
"RCON2S",
"SCON",
"LCON",
"LCONADDR",
"ZFCON",
"SFCON",
"LFCON",
"RACON",
"LACON",
"SBRA",
"LBRA",
"HAUTO",
"FAUTO",
"HFAUTO",
"SAUTO",
"LAUTO",
"HOREG",
"FOREG",
"HFOREG",
"SOREG",
"ROREG",
"SROREG",
"LOREG",
"PC",
"SP",
"HREG",
"ADDR",
"C_TLS_LE",
"C_TLS_IE",
"TEXTSIZE",
"GOK",
"NCLASS",
"SCOND = (1<<4)-1",
"SBIT = 1<<4",
"PBIT = 1<<5",
"WBIT = 1<<6",
"FBIT = 1<<7",
"UBIT = 1<<7",
"SCOND_XOR = 14",
"SCOND_EQ = 0 ^ C_SCOND_XOR",
"SCOND_NE = 1 ^ C_SCOND_XOR",
"SCOND_HS = 2 ^ C_SCOND_XOR",
"SCOND_LO = 3 ^ C_SCOND_XOR",
"SCOND_MI = 4 ^ C_SCOND_XOR",
"SCOND_PL = 5 ^ C_SCOND_XOR",
"SCOND_VS = 6 ^ C_SCOND_XOR",
"SCOND_VC = 7 ^ C_SCOND_XOR",
"SCOND_HI = 8 ^ C_SCOND_XOR",
"SCOND_LS = 9 ^ C_SCOND_XOR",
"SCOND_GE = 10 ^ C_SCOND_XOR",
"SCOND_LT = 11 ^ C_SCOND_XOR",
"SCOND_GT = 12 ^ C_SCOND_XOR",
"SCOND_LE = 13 ^ C_SCOND_XOR",
"SCOND_NONE = 14 ^ C_SCOND_XOR",
"SCOND_NV = 15 ^ C_SCOND_XOR",
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,124 @@
// Inferno utils/5c/list.c
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5c/list.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package arm
import (
"github.com/twitchyliquid64/golang-asm/obj"
"fmt"
)
func init() {
obj.RegisterRegister(obj.RBaseARM, MAXREG, rconv)
obj.RegisterOpcode(obj.ABaseARM, Anames)
obj.RegisterRegisterList(obj.RegListARMLo, obj.RegListARMHi, rlconv)
obj.RegisterOpSuffix("arm", obj.CConvARM)
}
func rconv(r int) string {
if r == 0 {
return "NONE"
}
if r == REGG {
// Special case.
return "g"
}
if REG_R0 <= r && r <= REG_R15 {
return fmt.Sprintf("R%d", r-REG_R0)
}
if REG_F0 <= r && r <= REG_F15 {
return fmt.Sprintf("F%d", r-REG_F0)
}
switch r {
case REG_FPSR:
return "FPSR"
case REG_FPCR:
return "FPCR"
case REG_CPSR:
return "CPSR"
case REG_SPSR:
return "SPSR"
case REG_MB_SY:
return "MB_SY"
case REG_MB_ST:
return "MB_ST"
case REG_MB_ISH:
return "MB_ISH"
case REG_MB_ISHST:
return "MB_ISHST"
case REG_MB_NSH:
return "MB_NSH"
case REG_MB_NSHST:
return "MB_NSHST"
case REG_MB_OSH:
return "MB_OSH"
case REG_MB_OSHST:
return "MB_OSHST"
}
return fmt.Sprintf("Rgok(%d)", r-obj.RBaseARM)
}
func DRconv(a int) string {
s := "C_??"
if a >= C_NONE && a <= C_NCLASS {
s = cnames5[a]
}
var fp string
fp += s
return fp
}
func rlconv(list int64) string {
str := ""
for i := 0; i < 16; i++ {
if list&(1<<uint(i)) != 0 {
if str == "" {
str += "["
} else {
str += ","
}
// This is ARM-specific; R10 is g.
if i == REGG-REG_R0 {
str += "g"
} else {
str += fmt.Sprintf("R%d", i)
}
}
}
str += "]"
return str
}

View File

@ -0,0 +1,784 @@
// Derived from Inferno utils/5c/swt.c
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5c/swt.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package arm
import (
"github.com/twitchyliquid64/golang-asm/obj"
"github.com/twitchyliquid64/golang-asm/objabi"
"github.com/twitchyliquid64/golang-asm/sys"
)
var progedit_tlsfallback *obj.LSym
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p.From.Class = 0
p.To.Class = 0
c := ctxt5{ctxt: ctxt, newprog: newprog}
// Rewrite B/BL to symbol as TYPE_BRANCH.
switch p.As {
case AB, ABL, obj.ADUFFZERO, obj.ADUFFCOPY:
if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
p.To.Type = obj.TYPE_BRANCH
}
}
// Replace TLS register fetches on older ARM processors.
switch p.As {
// Treat MRC 15, 0, <reg>, C13, C0, 3 specially.
case AMRC:
if p.To.Offset&0xffff0fff == 0xee1d0f70 {
// Because the instruction might be rewritten to a BL which returns in R0
// the register must be zero.
if p.To.Offset&0xf000 != 0 {
ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line())
}
if objabi.GOARM < 7 {
// Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension.
if progedit_tlsfallback == nil {
progedit_tlsfallback = ctxt.Lookup("runtime.read_tls_fallback")
}
// MOVW LR, R11
p.As = AMOVW
p.From.Type = obj.TYPE_REG
p.From.Reg = REGLINK
p.To.Type = obj.TYPE_REG
p.To.Reg = REGTMP
// BL runtime.read_tls_fallback(SB)
p = obj.Appendp(p, newprog)
p.As = ABL
p.To.Type = obj.TYPE_BRANCH
p.To.Sym = progedit_tlsfallback
p.To.Offset = 0
// MOVW R11, LR
p = obj.Appendp(p, newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_REG
p.From.Reg = REGTMP
p.To.Type = obj.TYPE_REG
p.To.Reg = REGLINK
break
}
}
// Otherwise, MRC/MCR instructions need no further treatment.
p.As = AWORD
}
// Rewrite float constants to values stored in memory.
switch p.As {
case AMOVF:
if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
f32 := float32(p.From.Val.(float64))
p.From.Type = obj.TYPE_MEM
p.From.Sym = ctxt.Float32Sym(f32)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
case AMOVD:
if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
p.From.Type = obj.TYPE_MEM
p.From.Sym = ctxt.Float64Sym(p.From.Val.(float64))
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
}
if ctxt.Flag_dynlink {
c.rewriteToUseGot(p)
}
}
// Rewrite p, if necessary, to access global data via the global offset table.
func (c *ctxt5) rewriteToUseGot(p *obj.Prog) {
if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
// ADUFFxxx $offset
// becomes
// MOVW runtime.duffxxx@GOT, R9
// ADD $offset, R9
// CALL (R9)
var sym *obj.LSym
if p.As == obj.ADUFFZERO {
sym = c.ctxt.Lookup("runtime.duffzero")
} else {
sym = c.ctxt.Lookup("runtime.duffcopy")
}
offset := p.To.Offset
p.As = AMOVW
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
p.From.Sym = sym
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R9
p.To.Name = obj.NAME_NONE
p.To.Offset = 0
p.To.Sym = nil
p1 := obj.Appendp(p, c.newprog)
p1.As = AADD
p1.From.Type = obj.TYPE_CONST
p1.From.Offset = offset
p1.To.Type = obj.TYPE_REG
p1.To.Reg = REG_R9
p2 := obj.Appendp(p1, c.newprog)
p2.As = obj.ACALL
p2.To.Type = obj.TYPE_MEM
p2.To.Reg = REG_R9
return
}
// We only care about global data: NAME_EXTERN means a global
// symbol in the Go sense, and p.Sym.Local is true for a few
// internally defined symbols.
if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
// MOVW $sym, Rx becomes MOVW sym@GOT, Rx
// MOVW $sym+<off>, Rx becomes MOVW sym@GOT, Rx; ADD <off>, Rx
if p.As != AMOVW {
c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
}
if p.To.Type != obj.TYPE_REG {
c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
}
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
if p.From.Offset != 0 {
q := obj.Appendp(p, c.newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = p.From.Offset
q.To = p.To
p.From.Offset = 0
}
}
if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
var source *obj.Addr
// MOVx sym, Ry becomes MOVW sym@GOT, R9; MOVx (R9), Ry
// MOVx Ry, sym becomes MOVW sym@GOT, R9; MOVx Ry, (R9)
// An addition may be inserted between the two MOVs if there is an offset.
if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
}
source = &p.From
} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
source = &p.To
} else {
return
}
if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
return
}
if source.Sym.Type == objabi.STLSBSS {
return
}
if source.Type != obj.TYPE_MEM {
c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
p1 := obj.Appendp(p, c.newprog)
p2 := obj.Appendp(p1, c.newprog)
p1.As = AMOVW
p1.From.Type = obj.TYPE_MEM
p1.From.Sym = source.Sym
p1.From.Name = obj.NAME_GOTREF
p1.To.Type = obj.TYPE_REG
p1.To.Reg = REG_R9
p2.As = p.As
p2.From = p.From
p2.To = p.To
if p.From.Name == obj.NAME_EXTERN {
p2.From.Reg = REG_R9
p2.From.Name = obj.NAME_NONE
p2.From.Sym = nil
} else if p.To.Name == obj.NAME_EXTERN {
p2.To.Reg = REG_R9
p2.To.Name = obj.NAME_NONE
p2.To.Sym = nil
} else {
return
}
obj.Nopout(p)
}
// Prog.mark
const (
FOLL = 1 << 0
LABEL = 1 << 1
LEAF = 1 << 2
)
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize := int32(0)
if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
return
}
c := ctxt5{ctxt: ctxt, cursym: cursym, newprog: newprog}
p := c.cursym.Func.Text
autoffset := int32(p.To.Offset)
if autoffset == -4 {
// Historical way to mark NOFRAME.
p.From.Sym.Set(obj.AttrNoFrame, true)
autoffset = 0
}
if autoffset < 0 || autoffset%4 != 0 {
c.ctxt.Diag("frame size %d not 0 or a positive multiple of 4", autoffset)
}
if p.From.Sym.NoFrame() {
if autoffset != 0 {
c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", autoffset)
}
}
cursym.Func.Locals = autoffset
cursym.Func.Args = p.To.Val.(int32)
/*
* find leaf subroutines
*/
for p := cursym.Func.Text; p != nil; p = p.Link {
switch p.As {
case obj.ATEXT:
p.Mark |= LEAF
case ADIV, ADIVU, AMOD, AMODU:
cursym.Func.Text.Mark &^= LEAF
case ABL,
ABX,
obj.ADUFFZERO,
obj.ADUFFCOPY:
cursym.Func.Text.Mark &^= LEAF
}
}
var q2 *obj.Prog
for p := cursym.Func.Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
autosize = autoffset
if p.Mark&LEAF != 0 && autosize == 0 {
// A leaf function with no locals has no frame.
p.From.Sym.Set(obj.AttrNoFrame, true)
}
if !p.From.Sym.NoFrame() {
// If there is a stack frame at all, it includes
// space to save the LR.
autosize += 4
}
if autosize == 0 && cursym.Func.Text.Mark&LEAF == 0 {
// A very few functions that do not return to their caller
// are not identified as leaves but still have no frame.
if ctxt.Debugvlog {
ctxt.Logf("save suppressed in: %s\n", cursym.Name)
}
cursym.Func.Text.Mark |= LEAF
}
// FP offsets need an updated p.To.Offset.
p.To.Offset = int64(autosize) - 4
if cursym.Func.Text.Mark&LEAF != 0 {
cursym.Set(obj.AttrLeaf, true)
if p.From.Sym.NoFrame() {
break
}
}
if !p.From.Sym.NoSplit() {
p = c.stacksplit(p, autosize) // emit split check
}
// MOVW.W R14,$-autosize(SP)
p = obj.Appendp(p, c.newprog)
p.As = AMOVW
p.Scond |= C_WBIT
p.From.Type = obj.TYPE_REG
p.From.Reg = REGLINK
p.To.Type = obj.TYPE_MEM
p.To.Offset = int64(-autosize)
p.To.Reg = REGSP
p.Spadj = autosize
if cursym.Func.Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOVW g_panic(g), R1
// CMP $0, R1
// B.NE checkargp
// end:
// NOP
// ... function ...
// checkargp:
// MOVW panic_argp(R1), R2
// ADD $(autosize+4), R13, R3
// CMP R2, R3
// B.NE end
// ADD $4, R13, R4
// MOVW R4, panic_argp(R1)
// B end
//
// The NOP is needed to give the jumps somewhere to land.
// It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes.
p = obj.Appendp(p, newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_CONST
p.From.Offset = 0
p.Reg = REG_R1
// B.NE checkargp
bne := obj.Appendp(p, newprog)
bne.As = ABNE
bne.To.Type = obj.TYPE_BRANCH
// end: NOP
end := obj.Appendp(bne, newprog)
end.As = obj.ANOP
// find end of function
var last *obj.Prog
for last = end; last.Link != nil; last = last.Link {
}
// MOVW panic_argp(R1), R2
mov := obj.Appendp(last, newprog)
mov.As = AMOVW
mov.From.Type = obj.TYPE_MEM
mov.From.Reg = REG_R1
mov.From.Offset = 0 // Panic.argp
mov.To.Type = obj.TYPE_REG
mov.To.Reg = REG_R2
// B.NE branch target is MOVW above
bne.To.SetTarget(mov)
// ADD $(autosize+4), R13, R3
p = obj.Appendp(mov, newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(autosize) + 4
p.Reg = REG_R13
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
// CMP R2, R3
p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R2
p.Reg = REG_R3
// B.NE end
p = obj.Appendp(p, newprog)
p.As = ABNE
p.To.Type = obj.TYPE_BRANCH
p.To.SetTarget(end)
// ADD $4, R13, R4
p = obj.Appendp(p, newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = 4
p.Reg = REG_R13
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
// MOVW R4, panic_argp(R1)
p = obj.Appendp(p, newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R4
p.To.Type = obj.TYPE_MEM
p.To.Reg = REG_R1
p.To.Offset = 0 // Panic.argp
// B end
p = obj.Appendp(p, newprog)
p.As = AB
p.To.Type = obj.TYPE_BRANCH
p.To.SetTarget(end)
// reset for subsequent passes
p = end
}
case obj.ARET:
nocache(p)
if cursym.Func.Text.Mark&LEAF != 0 {
if autosize == 0 {
p.As = AB
p.From = obj.Addr{}
if p.To.Sym != nil { // retjmp
p.To.Type = obj.TYPE_BRANCH
} else {
p.To.Type = obj.TYPE_MEM
p.To.Offset = 0
p.To.Reg = REGLINK
}
break
}
}
p.As = AMOVW
p.Scond |= C_PBIT
p.From.Type = obj.TYPE_MEM
p.From.Offset = int64(autosize)
p.From.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REGPC
// If there are instructions following
// this ARET, they come from a branch
// with the same stackframe, so no spadj.
if p.To.Sym != nil { // retjmp
p.To.Reg = REGLINK
q2 = obj.Appendp(p, newprog)
q2.As = AB
q2.To.Type = obj.TYPE_BRANCH
q2.To.Sym = p.To.Sym
p.To.Sym = nil
p = q2
}
case AADD:
if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
p.Spadj = int32(-p.From.Offset)
}
case ASUB:
if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
p.Spadj = int32(p.From.Offset)
}
case ADIV, ADIVU, AMOD, AMODU:
if cursym.Func.Text.From.Sym.NoSplit() {
ctxt.Diag("cannot divide in NOSPLIT function")
}
const debugdivmod = false
if debugdivmod {
break
}
if p.From.Type != obj.TYPE_REG {
break
}
if p.To.Type != obj.TYPE_REG {
break
}
// Make copy because we overwrite p below.
q1 := *p
if q1.Reg == REGTMP || q1.Reg == 0 && q1.To.Reg == REGTMP {
ctxt.Diag("div already using REGTMP: %v", p)
}
/* MOV m(g),REGTMP */
p.As = AMOVW
p.Pos = q1.Pos
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 6 * 4 // offset of g.m
p.Reg = 0
p.To.Type = obj.TYPE_REG
p.To.Reg = REGTMP
/* MOV a,m_divmod(REGTMP) */
p = obj.Appendp(p, newprog)
p.As = AMOVW
p.Pos = q1.Pos
p.From.Type = obj.TYPE_REG
p.From.Reg = q1.From.Reg
p.To.Type = obj.TYPE_MEM
p.To.Reg = REGTMP
p.To.Offset = 8 * 4 // offset of m.divmod
/* MOV b, R8 */
p = obj.Appendp(p, newprog)
p.As = AMOVW
p.Pos = q1.Pos
p.From.Type = obj.TYPE_REG
p.From.Reg = q1.Reg
if q1.Reg == 0 {
p.From.Reg = q1.To.Reg
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R8
p.To.Offset = 0
/* CALL appropriate */
p = obj.Appendp(p, newprog)
p.As = ABL
p.Pos = q1.Pos
p.To.Type = obj.TYPE_BRANCH
switch o {
case ADIV:
p.To.Sym = symdiv
case ADIVU:
p.To.Sym = symdivu
case AMOD:
p.To.Sym = symmod
case AMODU:
p.To.Sym = symmodu
}
/* MOV REGTMP, b */
p = obj.Appendp(p, newprog)
p.As = AMOVW
p.Pos = q1.Pos
p.From.Type = obj.TYPE_REG
p.From.Reg = REGTMP
p.From.Offset = 0
p.To.Type = obj.TYPE_REG
p.To.Reg = q1.To.Reg
case AMOVW:
if (p.Scond&C_WBIT != 0) && p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
p.Spadj = int32(-p.To.Offset)
}
if (p.Scond&C_PBIT != 0) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP && p.To.Reg != REGPC {
p.Spadj = int32(-p.From.Offset)
}
if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
p.Spadj = int32(-p.From.Offset)
}
case obj.AGETCALLERPC:
if cursym.Leaf() {
/* MOVW LR, Rd */
p.As = AMOVW
p.From.Type = obj.TYPE_REG
p.From.Reg = REGLINK
} else {
/* MOVW (RSP), Rd */
p.As = AMOVW
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGSP
}
}
}
}
func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
// MOVW g_stackguard(g), R1
p = obj.Appendp(p, c.newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
if c.cursym.CFunc() {
p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
// Mark the stack bound check and morestack call async nonpreemptible.
// If we get preempted here, when resumed the preemption request is
// cleared, but we'll still call morestack, which will double the stack
// unnecessarily. See issue #35470.
p = c.ctxt.StartUnsafePoint(p, c.newprog)
if framesize <= objabi.StackSmall {
// small stack: SP < stackguard
// CMP stackguard, SP
p = obj.Appendp(p, c.newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REGSP
} else if framesize <= objabi.StackBig {
// large stack: SP-framesize < stackguard-StackSmall
// MOVW $-(framesize-StackSmall)(SP), R2
// CMP stackguard, R2
p = obj.Appendp(p, c.newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_ADDR
p.From.Reg = REGSP
p.From.Offset = -(int64(framesize) - objabi.StackSmall)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(p, c.newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REG_R2
} else {
// Such a large stack we need to protect against wraparound
// if SP is close to zero.
// SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
// The +StackGuard on both sides is required to keep the left side positive:
// SP is allowed to be slightly below stackguard. See stack.h.
// CMP $StackPreempt, R1
// MOVW.NE $StackGuard(SP), R2
// SUB.NE R1, R2
// MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
// CMP.NE R3, R2
p = obj.Appendp(p, c.newprog)
p.As = ACMP
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(uint32(objabi.StackPreempt & (1<<32 - 1)))
p.Reg = REG_R1
p = obj.Appendp(p, c.newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_ADDR
p.From.Reg = REGSP
p.From.Offset = int64(objabi.StackGuard)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p.Scond = C_SCOND_NE
p = obj.Appendp(p, c.newprog)
p.As = ASUB
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p.Scond = C_SCOND_NE
p = obj.Appendp(p, c.newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_ADDR
p.From.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
p.Scond = C_SCOND_NE
p = obj.Appendp(p, c.newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.Reg = REG_R2
p.Scond = C_SCOND_NE
}
// BLS call-to-morestack
bls := obj.Appendp(p, c.newprog)
bls.As = ABLS
bls.To.Type = obj.TYPE_BRANCH
end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
var last *obj.Prog
for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
}
// Now we are at the end of the function, but logically
// we are still in function prologue. We need to fix the
// SP data and PCDATA.
spfix := obj.Appendp(last, c.newprog)
spfix.As = obj.ANOP
spfix.Spadj = -framesize
pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
// MOVW LR, R3
movw := obj.Appendp(pcdata, c.newprog)
movw.As = AMOVW
movw.From.Type = obj.TYPE_REG
movw.From.Reg = REGLINK
movw.To.Type = obj.TYPE_REG
movw.To.Reg = REG_R3
bls.To.SetTarget(movw)
// BL runtime.morestack
call := obj.Appendp(movw, c.newprog)
call.As = obj.ACALL
call.To.Type = obj.TYPE_BRANCH
morestack := "runtime.morestack"
switch {
case c.cursym.CFunc():
morestack = "runtime.morestackc"
case !c.cursym.Func.Text.From.Sym.NeedCtxt():
morestack = "runtime.morestack_noctxt"
}
call.To.Sym = c.ctxt.Lookup(morestack)
pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
// B start
b := obj.Appendp(pcdata, c.newprog)
b.As = obj.AJMP
b.To.Type = obj.TYPE_BRANCH
b.To.SetTarget(c.cursym.Func.Text.Link)
b.Spadj = +framesize
return end
}
var unaryDst = map[obj.As]bool{
ASWI: true,
AWORD: true,
}
var Linkarm = obj.LinkArch{
Arch: sys.ArchARM,
Init: buildop,
Preprocess: preprocess,
Assemble: span5,
Progedit: progedit,
UnaryDst: unaryDst,
DWARFRegisters: ARMDWARFRegisters,
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,512 @@
// Code generated by stringer -i a.out.go -o anames.go -p arm64; DO NOT EDIT.
package arm64
import "github.com/twitchyliquid64/golang-asm/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "ADC",
"ADCS",
"ADCSW",
"ADCW",
"ADD",
"ADDS",
"ADDSW",
"ADDW",
"ADR",
"ADRP",
"AND",
"ANDS",
"ANDSW",
"ANDW",
"ASR",
"ASRW",
"AT",
"BFI",
"BFIW",
"BFM",
"BFMW",
"BFXIL",
"BFXILW",
"BIC",
"BICS",
"BICSW",
"BICW",
"BRK",
"CBNZ",
"CBNZW",
"CBZ",
"CBZW",
"CCMN",
"CCMNW",
"CCMP",
"CCMPW",
"CINC",
"CINCW",
"CINV",
"CINVW",
"CLREX",
"CLS",
"CLSW",
"CLZ",
"CLZW",
"CMN",
"CMNW",
"CMP",
"CMPW",
"CNEG",
"CNEGW",
"CRC32B",
"CRC32CB",
"CRC32CH",
"CRC32CW",
"CRC32CX",
"CRC32H",
"CRC32W",
"CRC32X",
"CSEL",
"CSELW",
"CSET",
"CSETM",
"CSETMW",
"CSETW",
"CSINC",
"CSINCW",
"CSINV",
"CSINVW",
"CSNEG",
"CSNEGW",
"DC",
"DCPS1",
"DCPS2",
"DCPS3",
"DMB",
"DRPS",
"DSB",
"EON",
"EONW",
"EOR",
"EORW",
"ERET",
"EXTR",
"EXTRW",
"HINT",
"HLT",
"HVC",
"IC",
"ISB",
"LDADDAB",
"LDADDAD",
"LDADDAH",
"LDADDAW",
"LDADDALB",
"LDADDALD",
"LDADDALH",
"LDADDALW",
"LDADDB",
"LDADDD",
"LDADDH",
"LDADDW",
"LDADDLB",
"LDADDLD",
"LDADDLH",
"LDADDLW",
"LDANDAB",
"LDANDAD",
"LDANDAH",
"LDANDAW",
"LDANDALB",
"LDANDALD",
"LDANDALH",
"LDANDALW",
"LDANDB",
"LDANDD",
"LDANDH",
"LDANDW",
"LDANDLB",
"LDANDLD",
"LDANDLH",
"LDANDLW",
"LDAR",
"LDARB",
"LDARH",
"LDARW",
"LDAXP",
"LDAXPW",
"LDAXR",
"LDAXRB",
"LDAXRH",
"LDAXRW",
"LDEORAB",
"LDEORAD",
"LDEORAH",
"LDEORAW",
"LDEORALB",
"LDEORALD",
"LDEORALH",
"LDEORALW",
"LDEORB",
"LDEORD",
"LDEORH",
"LDEORW",
"LDEORLB",
"LDEORLD",
"LDEORLH",
"LDEORLW",
"LDORAB",
"LDORAD",
"LDORAH",
"LDORAW",
"LDORALB",
"LDORALD",
"LDORALH",
"LDORALW",
"LDORB",
"LDORD",
"LDORH",
"LDORW",
"LDORLB",
"LDORLD",
"LDORLH",
"LDORLW",
"LDP",
"LDPW",
"LDPSW",
"LDXR",
"LDXRB",
"LDXRH",
"LDXRW",
"LDXP",
"LDXPW",
"LSL",
"LSLW",
"LSR",
"LSRW",
"MADD",
"MADDW",
"MNEG",
"MNEGW",
"MOVK",
"MOVKW",
"MOVN",
"MOVNW",
"MOVZ",
"MOVZW",
"MRS",
"MSR",
"MSUB",
"MSUBW",
"MUL",
"MULW",
"MVN",
"MVNW",
"NEG",
"NEGS",
"NEGSW",
"NEGW",
"NGC",
"NGCS",
"NGCSW",
"NGCW",
"NOOP",
"ORN",
"ORNW",
"ORR",
"ORRW",
"PRFM",
"PRFUM",
"RBIT",
"RBITW",
"REM",
"REMW",
"REV",
"REV16",
"REV16W",
"REV32",
"REVW",
"ROR",
"RORW",
"SBC",
"SBCS",
"SBCSW",
"SBCW",
"SBFIZ",
"SBFIZW",
"SBFM",
"SBFMW",
"SBFX",
"SBFXW",
"SDIV",
"SDIVW",
"SEV",
"SEVL",
"SMADDL",
"SMC",
"SMNEGL",
"SMSUBL",
"SMULH",
"SMULL",
"STXR",
"STXRB",
"STXRH",
"STXP",
"STXPW",
"STXRW",
"STLP",
"STLPW",
"STLR",
"STLRB",
"STLRH",
"STLRW",
"STLXP",
"STLXPW",
"STLXR",
"STLXRB",
"STLXRH",
"STLXRW",
"STP",
"STPW",
"SUB",
"SUBS",
"SUBSW",
"SUBW",
"SVC",
"SXTB",
"SXTBW",
"SXTH",
"SXTHW",
"SXTW",
"SYS",
"SYSL",
"TBNZ",
"TBZ",
"TLBI",
"TST",
"TSTW",
"UBFIZ",
"UBFIZW",
"UBFM",
"UBFMW",
"UBFX",
"UBFXW",
"UDIV",
"UDIVW",
"UMADDL",
"UMNEGL",
"UMSUBL",
"UMULH",
"UMULL",
"UREM",
"UREMW",
"UXTB",
"UXTH",
"UXTW",
"UXTBW",
"UXTHW",
"WFE",
"WFI",
"YIELD",
"MOVB",
"MOVBU",
"MOVH",
"MOVHU",
"MOVW",
"MOVWU",
"MOVD",
"MOVNP",
"MOVNPW",
"MOVP",
"MOVPD",
"MOVPQ",
"MOVPS",
"MOVPSW",
"MOVPW",
"SWPAD",
"SWPAW",
"SWPAH",
"SWPAB",
"SWPALD",
"SWPALW",
"SWPALH",
"SWPALB",
"SWPD",
"SWPW",
"SWPH",
"SWPB",
"SWPLD",
"SWPLW",
"SWPLH",
"SWPLB",
"BEQ",
"BNE",
"BCS",
"BHS",
"BCC",
"BLO",
"BMI",
"BPL",
"BVS",
"BVC",
"BHI",
"BLS",
"BGE",
"BLT",
"BGT",
"BLE",
"FABSD",
"FABSS",
"FADDD",
"FADDS",
"FCCMPD",
"FCCMPED",
"FCCMPS",
"FCCMPES",
"FCMPD",
"FCMPED",
"FCMPES",
"FCMPS",
"FCVTSD",
"FCVTDS",
"FCVTZSD",
"FCVTZSDW",
"FCVTZSS",
"FCVTZSSW",
"FCVTZUD",
"FCVTZUDW",
"FCVTZUS",
"FCVTZUSW",
"FDIVD",
"FDIVS",
"FLDPD",
"FLDPS",
"FMOVD",
"FMOVS",
"FMOVQ",
"FMULD",
"FMULS",
"FNEGD",
"FNEGS",
"FSQRTD",
"FSQRTS",
"FSTPD",
"FSTPS",
"FSUBD",
"FSUBS",
"SCVTFD",
"SCVTFS",
"SCVTFWD",
"SCVTFWS",
"UCVTFD",
"UCVTFS",
"UCVTFWD",
"UCVTFWS",
"WORD",
"DWORD",
"FCSELS",
"FCSELD",
"FMAXS",
"FMINS",
"FMAXD",
"FMIND",
"FMAXNMS",
"FMAXNMD",
"FNMULS",
"FNMULD",
"FRINTNS",
"FRINTND",
"FRINTPS",
"FRINTPD",
"FRINTMS",
"FRINTMD",
"FRINTZS",
"FRINTZD",
"FRINTAS",
"FRINTAD",
"FRINTXS",
"FRINTXD",
"FRINTIS",
"FRINTID",
"FMADDS",
"FMADDD",
"FMSUBS",
"FMSUBD",
"FNMADDS",
"FNMADDD",
"FNMSUBS",
"FNMSUBD",
"FMINNMS",
"FMINNMD",
"FCVTDH",
"FCVTHS",
"FCVTHD",
"FCVTSH",
"AESD",
"AESE",
"AESIMC",
"AESMC",
"SHA1C",
"SHA1H",
"SHA1M",
"SHA1P",
"SHA1SU0",
"SHA1SU1",
"SHA256H",
"SHA256H2",
"SHA256SU0",
"SHA256SU1",
"SHA512H",
"SHA512H2",
"SHA512SU0",
"SHA512SU1",
"VADD",
"VADDP",
"VAND",
"VBIF",
"VCMEQ",
"VCNT",
"VEOR",
"VMOV",
"VLD1",
"VLD2",
"VLD3",
"VLD4",
"VLD1R",
"VLD2R",
"VLD3R",
"VLD4R",
"VORR",
"VREV16",
"VREV32",
"VREV64",
"VST1",
"VST2",
"VST3",
"VST4",
"VDUP",
"VADDV",
"VMOVI",
"VUADDLV",
"VSUB",
"VFMLA",
"VFMLS",
"VPMULL",
"VPMULL2",
"VEXT",
"VRBIT",
"VUSHR",
"VUSHLL",
"VUSHLL2",
"VUXTL",
"VUXTL2",
"VUZP1",
"VUZP2",
"VSHL",
"VSRI",
"VBSL",
"VBIT",
"VTBL",
"VZIP1",
"VZIP2",
"VCMTST",
"LAST",
}

View File

@ -0,0 +1,100 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package arm64
// This order should be strictly consistent to that in a.out.go
var cnames7 = []string{
"NONE",
"REG",
"RSP",
"FREG",
"VREG",
"PAIR",
"SHIFT",
"EXTREG",
"SPR",
"COND",
"ARNG",
"ELEM",
"LIST",
"ZCON",
"ABCON0",
"ADDCON0",
"ABCON",
"AMCON",
"ADDCON",
"MBCON",
"MOVCON",
"BITCON",
"ADDCON2",
"LCON",
"MOVCON2",
"MOVCON3",
"VCON",
"FCON",
"VCONADDR",
"AACON",
"AACON2",
"LACON",
"AECON",
"SBRA",
"LBRA",
"ZAUTO",
"NSAUTO_8",
"NSAUTO_4",
"NSAUTO",
"NPAUTO",
"NAUTO4K",
"PSAUTO_8",
"PSAUTO_4",
"PSAUTO",
"PPAUTO",
"UAUTO4K_8",
"UAUTO4K_4",
"UAUTO4K_2",
"UAUTO4K",
"UAUTO8K_8",
"UAUTO8K_4",
"UAUTO8K",
"UAUTO16K_8",
"UAUTO16K",
"UAUTO32K",
"LAUTO",
"SEXT1",
"SEXT2",
"SEXT4",
"SEXT8",
"SEXT16",
"LEXT",
"ZOREG",
"NSOREG_8",
"NSOREG_4",
"NSOREG",
"NPOREG",
"NOREG4K",
"PSOREG_8",
"PSOREG_4",
"PSOREG",
"PPOREG",
"UOREG4K_8",
"UOREG4K_4",
"UOREG4K_2",
"UOREG4K",
"UOREG8K_8",
"UOREG8K_4",
"UOREG8K",
"UOREG16K_8",
"UOREG16K",
"UOREG32K",
"LOREG",
"ADDR",
"GOTADDR",
"TLS_LE",
"TLS_IE",
"ROFF",
"GOK",
"TEXTSIZE",
"NCLASS",
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,249 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package arm64 implements an ARM64 assembler. Go assembly syntax is different from GNU ARM64
syntax, but we can still follow the general rules to map between them.
Instructions mnemonics mapping rules
1. Most instructions use width suffixes of instruction names to indicate operand width rather than
using different register names.
Examples:
ADC R24, R14, R12 <=> adc x12, x24
ADDW R26->24, R21, R15 <=> add w15, w21, w26, asr #24
FCMPS F2, F3 <=> fcmp s3, s2
FCMPD F2, F3 <=> fcmp d3, d2
FCVTDH F2, F3 <=> fcvt h3, d2
2. Go uses .P and .W suffixes to indicate post-increment and pre-increment.
Examples:
MOVD.P -8(R10), R8 <=> ldr x8, [x10],#-8
MOVB.W 16(R16), R10 <=> ldrsb x10, [x16,#16]!
MOVBU.W 16(R16), R10 <=> ldrb x10, [x16,#16]!
3. Go uses a series of MOV instructions as load and store.
64-bit variant ldr, str, stur => MOVD;
32-bit variant str, stur, ldrsw => MOVW;
32-bit variant ldr => MOVWU;
ldrb => MOVBU; ldrh => MOVHU;
ldrsb, sturb, strb => MOVB;
ldrsh, sturh, strh => MOVH.
4. Go moves conditions into opcode suffix, like BLT.
5. Go adds a V prefix for most floating-point and SIMD instructions, except cryptographic extension
instructions and floating-point(scalar) instructions.
Examples:
VADD V5.H8, V18.H8, V9.H8 <=> add v9.8h, v18.8h, v5.8h
VLD1.P (R6)(R11), [V31.D1] <=> ld1 {v31.1d}, [x6], x11
VFMLA V29.S2, V20.S2, V14.S2 <=> fmla v14.2s, v20.2s, v29.2s
AESD V22.B16, V19.B16 <=> aesd v19.16b, v22.16b
SCVTFWS R3, F16 <=> scvtf s17, w6
6. Align directive
Go asm supports the PCALIGN directive, which indicates that the next instruction should be aligned
to a specified boundary by padding with NOOP instruction. The alignment value supported on arm64
must be a power of 2 and in the range of [8, 2048].
Examples:
PCALIGN $16
MOVD $2, R0 // This instruction is aligned with 16 bytes.
PCALIGN $1024
MOVD $3, R1 // This instruction is aligned with 1024 bytes.
PCALIGN also changes the function alignment. If a function has one or more PCALIGN directives,
its address will be aligned to the same or coarser boundary, which is the maximum of all the
alignment values.
In the following example, the function Add is aligned with 128 bytes.
Examples:
TEXT ·Add(SB),$40-16
MOVD $2, R0
PCALIGN $32
MOVD $4, R1
PCALIGN $128
MOVD $8, R2
RET
On arm64, functions in Go are aligned to 16 bytes by default, we can also use PCALGIN to set the
function alignment. The functions that need to be aligned are preferably using NOFRAME and NOSPLIT
to avoid the impact of the prologues inserted by the assembler, so that the function address will
have the same alignment as the first hand-written instruction.
In the following example, PCALIGN at the entry of the function Add will align its address to 2048 bytes.
Examples:
TEXT ·Add(SB),NOSPLIT|NOFRAME,$0
PCALIGN $2048
MOVD $1, R0
MOVD $1, R1
RET
Special Cases.
(1) umov is written as VMOV.
(2) br is renamed JMP, blr is renamed CALL.
(3) No need to add "W" suffix: LDARB, LDARH, LDAXRB, LDAXRH, LDTRH, LDXRB, LDXRH.
(4) In Go assembly syntax, NOP is a zero-width pseudo-instruction serves generic purpose, nothing
related to real ARM64 instruction. NOOP serves for the hardware nop instruction. NOOP is an alias of
HINT $0.
Examples:
VMOV V13.B[1], R20 <=> mov x20, v13.b[1]
VMOV V13.H[1], R20 <=> mov w20, v13.h[1]
JMP (R3) <=> br x3
CALL (R17) <=> blr x17
LDAXRB (R19), R16 <=> ldaxrb w16, [x19]
NOOP <=> nop
Register mapping rules
1. All basic register names are written as Rn.
2. Go uses ZR as the zero register and RSP as the stack pointer.
3. Bn, Hn, Dn, Sn and Qn instructions are written as Fn in floating-point instructions and as Vn
in SIMD instructions.
Argument mapping rules
1. The operands appear in left-to-right assignment order.
Go reverses the arguments of most instructions.
Examples:
ADD R11.SXTB<<1, RSP, R25 <=> add x25, sp, w11, sxtb #1
VADD V16, V19, V14 <=> add d14, d19, d16
Special Cases.
(1) Argument order is the same as in the GNU ARM64 syntax: cbz, cbnz and some store instructions,
such as str, stur, strb, sturb, strh, sturh stlr, stlrb. stlrh, st1.
Examples:
MOVD R29, 384(R19) <=> str x29, [x19,#384]
MOVB.P R30, 30(R4) <=> strb w30, [x4],#30
STLRH R21, (R19) <=> stlrh w21, [x19]
(2) MADD, MADDW, MSUB, MSUBW, SMADDL, SMSUBL, UMADDL, UMSUBL <Rm>, <Ra>, <Rn>, <Rd>
Examples:
MADD R2, R30, R22, R6 <=> madd x6, x22, x2, x30
SMSUBL R10, R3, R17, R27 <=> smsubl x27, w17, w10, x3
(3) FMADDD, FMADDS, FMSUBD, FMSUBS, FNMADDD, FNMADDS, FNMSUBD, FNMSUBS <Fm>, <Fa>, <Fn>, <Fd>
Examples:
FMADDD F30, F20, F3, F29 <=> fmadd d29, d3, d30, d20
FNMSUBS F7, F25, F7, F22 <=> fnmsub s22, s7, s7, s25
(4) BFI, BFXIL, SBFIZ, SBFX, UBFIZ, UBFX $<lsb>, <Rn>, $<width>, <Rd>
Examples:
BFIW $16, R20, $6, R0 <=> bfi w0, w20, #16, #6
UBFIZ $34, R26, $5, R20 <=> ubfiz x20, x26, #34, #5
(5) FCCMPD, FCCMPS, FCCMPED, FCCMPES <cond>, Fm. Fn, $<nzcv>
Examples:
FCCMPD AL, F8, F26, $0 <=> fccmp d26, d8, #0x0, al
FCCMPS VS, F29, F4, $4 <=> fccmp s4, s29, #0x4, vs
FCCMPED LE, F20, F5, $13 <=> fccmpe d5, d20, #0xd, le
FCCMPES NE, F26, F10, $0 <=> fccmpe s10, s26, #0x0, ne
(6) CCMN, CCMNW, CCMP, CCMPW <cond>, <Rn>, $<imm>, $<nzcv>
Examples:
CCMP MI, R22, $12, $13 <=> ccmp x22, #0xc, #0xd, mi
CCMNW AL, R1, $11, $8 <=> ccmn w1, #0xb, #0x8, al
(7) CCMN, CCMNW, CCMP, CCMPW <cond>, <Rn>, <Rm>, $<nzcv>
Examples:
CCMN VS, R13, R22, $10 <=> ccmn x13, x22, #0xa, vs
CCMPW HS, R19, R14, $11 <=> ccmp w19, w14, #0xb, cs
(9) CSEL, CSELW, CSNEG, CSNEGW, CSINC, CSINCW <cond>, <Rn>, <Rm>, <Rd> ;
FCSELD, FCSELS <cond>, <Fn>, <Fm>, <Fd>
Examples:
CSEL GT, R0, R19, R1 <=> csel x1, x0, x19, gt
CSNEGW GT, R7, R17, R8 <=> csneg w8, w7, w17, gt
FCSELD EQ, F15, F18, F16 <=> fcsel d16, d15, d18, eq
(10) TBNZ, TBZ $<imm>, <Rt>, <label>
(11) STLXR, STLXRW, STXR, STXRW, STLXRB, STLXRH, STXRB, STXRH <Rf>, (<Rn|RSP>), <Rs>
Examples:
STLXR ZR, (R15), R16 <=> stlxr w16, xzr, [x15]
STXRB R9, (R21), R19 <=> stxrb w19, w9, [x21]
(12) STLXP, STLXPW, STXP, STXPW (<Rf1>, <Rf2>), (<Rn|RSP>), <Rs>
Examples:
STLXP (R17, R19), (R4), R5 <=> stlxp w5, x17, x19, [x4]
STXPW (R30, R25), (R22), R13 <=> stxp w13, w30, w25, [x22]
2. Expressions for special arguments.
#<immediate> is written as $<immediate>.
Optionally-shifted immediate.
Examples:
ADD $(3151<<12), R14, R20 <=> add x20, x14, #0xc4f, lsl #12
ADDW $1864, R25, R6 <=> add w6, w25, #0x748
Optionally-shifted registers are written as <Rm>{<shift><amount>}.
The <shift> can be <<(lsl), >>(lsr), ->(asr), @>(ror).
Examples:
ADD R19>>30, R10, R24 <=> add x24, x10, x19, lsr #30
ADDW R26->24, R21, R15 <=> add w15, w21, w26, asr #24
Extended registers are written as <Rm>{.<extend>{<<<amount>}}.
<extend> can be UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW or SXTX.
Examples:
ADDS R19.UXTB<<4, R9, R26 <=> adds x26, x9, w19, uxtb #4
ADDSW R14.SXTX, R14, R6 <=> adds w6, w14, w14, sxtx
Memory references: [<Xn|SP>{,#0}] is written as (Rn|RSP), a base register and an immediate
offset is written as imm(Rn|RSP), a base register and an offset register is written as (Rn|RSP)(Rm).
Examples:
LDAR (R22), R9 <=> ldar x9, [x22]
LDP 28(R17), (R15, R23) <=> ldp x15, x23, [x17,#28]
MOVWU (R4)(R12<<2), R8 <=> ldr w8, [x4, x12, lsl #2]
MOVD (R7)(R11.UXTW<<3), R25 <=> ldr x25, [x7,w11,uxtw #3]
MOVBU (R27)(R23), R14 <=> ldrb w14, [x27,x23]
Register pairs are written as (Rt1, Rt2).
Examples:
LDP.P -240(R11), (R12, R26) <=> ldp x12, x26, [x11],#-240
Register with arrangement and register with arrangement and index.
Examples:
VADD V5.H8, V18.H8, V9.H8 <=> add v9.8h, v18.8h, v5.8h
VLD1 (R2), [V21.B16] <=> ld1 {v21.16b}, [x2]
VST1.P V9.S[1], (R16)(R21) <=> st1 {v9.s}[1], [x16], x28
VST1.P [V13.H8, V14.H8, V15.H8], (R3)(R14) <=> st1 {v13.8h-v15.8h}, [x3], x14
VST1.P [V14.D1, V15.D1], (R7)(R23) <=> st1 {v14.1d, v15.1d}, [x7], x23
*/
package arm64

View File

@ -0,0 +1,288 @@
// cmd/7l/list.c and cmd/7l/sub.c from Vita Nuova.
// https://code.google.com/p/ken-cc/source/browse/
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package arm64
import (
"github.com/twitchyliquid64/golang-asm/obj"
"fmt"
)
var strcond = [16]string{
"EQ",
"NE",
"HS",
"LO",
"MI",
"PL",
"VS",
"VC",
"HI",
"LS",
"GE",
"LT",
"GT",
"LE",
"AL",
"NV",
}
func init() {
obj.RegisterRegister(obj.RBaseARM64, REG_SPECIAL+1024, rconv)
obj.RegisterOpcode(obj.ABaseARM64, Anames)
obj.RegisterRegisterList(obj.RegListARM64Lo, obj.RegListARM64Hi, rlconv)
obj.RegisterOpSuffix("arm64", obj.CConvARM)
}
func arrange(a int) string {
switch a {
case ARNG_8B:
return "B8"
case ARNG_16B:
return "B16"
case ARNG_4H:
return "H4"
case ARNG_8H:
return "H8"
case ARNG_2S:
return "S2"
case ARNG_4S:
return "S4"
case ARNG_1D:
return "D1"
case ARNG_2D:
return "D2"
case ARNG_B:
return "B"
case ARNG_H:
return "H"
case ARNG_S:
return "S"
case ARNG_D:
return "D"
case ARNG_1Q:
return "Q1"
default:
return ""
}
}
func rconv(r int) string {
ext := (r >> 5) & 7
if r == REGG {
return "g"
}
switch {
case REG_R0 <= r && r <= REG_R30:
return fmt.Sprintf("R%d", r-REG_R0)
case r == REG_R31:
return "ZR"
case REG_F0 <= r && r <= REG_F31:
return fmt.Sprintf("F%d", r-REG_F0)
case REG_V0 <= r && r <= REG_V31:
return fmt.Sprintf("V%d", r-REG_V0)
case COND_EQ <= r && r <= COND_NV:
return strcond[r-COND_EQ]
case r == REGSP:
return "RSP"
case r == REG_DAIFSet:
return "DAIFSet"
case r == REG_DAIFClr:
return "DAIFClr"
case r == REG_PLDL1KEEP:
return "PLDL1KEEP"
case r == REG_PLDL1STRM:
return "PLDL1STRM"
case r == REG_PLDL2KEEP:
return "PLDL2KEEP"
case r == REG_PLDL2STRM:
return "PLDL2STRM"
case r == REG_PLDL3KEEP:
return "PLDL3KEEP"
case r == REG_PLDL3STRM:
return "PLDL3STRM"
case r == REG_PLIL1KEEP:
return "PLIL1KEEP"
case r == REG_PLIL1STRM:
return "PLIL1STRM"
case r == REG_PLIL2KEEP:
return "PLIL2KEEP"
case r == REG_PLIL2STRM:
return "PLIL2STRM"
case r == REG_PLIL3KEEP:
return "PLIL3KEEP"
case r == REG_PLIL3STRM:
return "PLIL3STRM"
case r == REG_PSTL1KEEP:
return "PSTL1KEEP"
case r == REG_PSTL1STRM:
return "PSTL1STRM"
case r == REG_PSTL2KEEP:
return "PSTL2KEEP"
case r == REG_PSTL2STRM:
return "PSTL2STRM"
case r == REG_PSTL3KEEP:
return "PSTL3KEEP"
case r == REG_PSTL3STRM:
return "PSTL3STRM"
case REG_UXTB <= r && r < REG_UXTH:
if ext != 0 {
return fmt.Sprintf("%s.UXTB<<%d", regname(r), ext)
} else {
return fmt.Sprintf("%s.UXTB", regname(r))
}
case REG_UXTH <= r && r < REG_UXTW:
if ext != 0 {
return fmt.Sprintf("%s.UXTH<<%d", regname(r), ext)
} else {
return fmt.Sprintf("%s.UXTH", regname(r))
}
case REG_UXTW <= r && r < REG_UXTX:
if ext != 0 {
return fmt.Sprintf("%s.UXTW<<%d", regname(r), ext)
} else {
return fmt.Sprintf("%s.UXTW", regname(r))
}
case REG_UXTX <= r && r < REG_SXTB:
if ext != 0 {
return fmt.Sprintf("%s.UXTX<<%d", regname(r), ext)
} else {
return fmt.Sprintf("%s.UXTX", regname(r))
}
case REG_SXTB <= r && r < REG_SXTH:
if ext != 0 {
return fmt.Sprintf("%s.SXTB<<%d", regname(r), ext)
} else {
return fmt.Sprintf("%s.SXTB", regname(r))
}
case REG_SXTH <= r && r < REG_SXTW:
if ext != 0 {
return fmt.Sprintf("%s.SXTH<<%d", regname(r), ext)
} else {
return fmt.Sprintf("%s.SXTH", regname(r))
}
case REG_SXTW <= r && r < REG_SXTX:
if ext != 0 {
return fmt.Sprintf("%s.SXTW<<%d", regname(r), ext)
} else {
return fmt.Sprintf("%s.SXTW", regname(r))
}
case REG_SXTX <= r && r < REG_SPECIAL:
if ext != 0 {
return fmt.Sprintf("%s.SXTX<<%d", regname(r), ext)
} else {
return fmt.Sprintf("%s.SXTX", regname(r))
}
// bits 0-4 indicate register, bits 5-7 indicate shift amount, bit 8 equals to 0.
case REG_LSL <= r && r < (REG_LSL+1<<8):
return fmt.Sprintf("R%d<<%d", r&31, (r>>5)&7)
case REG_ARNG <= r && r < REG_ELEM:
return fmt.Sprintf("V%d.%s", r&31, arrange((r>>5)&15))
case REG_ELEM <= r && r < REG_ELEM_END:
return fmt.Sprintf("V%d.%s", r&31, arrange((r>>5)&15))
}
// Return system register name.
name, _, _ := SysRegEnc(int16(r))
if name != "" {
return name
}
return fmt.Sprintf("badreg(%d)", r)
}
func DRconv(a int) string {
if a >= C_NONE && a <= C_NCLASS {
return cnames7[a]
}
return "C_??"
}
func rlconv(list int64) string {
str := ""
// ARM64 register list follows ARM64 instruction decode schema
// | 31 | 30 | ... | 15 - 12 | 11 - 10 | ... |
// +----+----+-----+---------+---------+-----+
// | | Q | ... | opcode | size | ... |
firstReg := int(list & 31)
opcode := (list >> 12) & 15
var regCnt int
var t string
switch opcode {
case 0x7:
regCnt = 1
case 0xa:
regCnt = 2
case 0x6:
regCnt = 3
case 0x2:
regCnt = 4
default:
regCnt = -1
}
// Q:size
arng := ((list>>30)&1)<<2 | (list>>10)&3
switch arng {
case 0:
t = "B8"
case 4:
t = "B16"
case 1:
t = "H4"
case 5:
t = "H8"
case 2:
t = "S2"
case 6:
t = "S4"
case 3:
t = "D1"
case 7:
t = "D2"
}
for i := 0; i < regCnt; i++ {
if str == "" {
str += "["
} else {
str += ","
}
str += fmt.Sprintf("V%d.", (firstReg+i)&31)
str += t
}
str += "]"
return str
}
func regname(r int) string {
if r&31 == 31 {
return "ZR"
}
return fmt.Sprintf("R%d", r&31)
}

View File

@ -0,0 +1,998 @@
// cmd/7l/noop.c, cmd/7l/obj.c, cmd/ld/pass.c from Vita Nuova.
// https://code.google.com/p/ken-cc/source/browse/
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package arm64
import (
"github.com/twitchyliquid64/golang-asm/obj"
"github.com/twitchyliquid64/golang-asm/objabi"
"github.com/twitchyliquid64/golang-asm/src"
"github.com/twitchyliquid64/golang-asm/sys"
"math"
)
var complements = []obj.As{
AADD: ASUB,
AADDW: ASUBW,
ASUB: AADD,
ASUBW: AADDW,
ACMP: ACMN,
ACMPW: ACMNW,
ACMN: ACMP,
ACMNW: ACMPW,
}
func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
// MOV g_stackguard(g), R1
p = obj.Appendp(p, c.newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
if c.cursym.CFunc() {
p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
// Mark the stack bound check and morestack call async nonpreemptible.
// If we get preempted here, when resumed the preemption request is
// cleared, but we'll still call morestack, which will double the stack
// unnecessarily. See issue #35470.
p = c.ctxt.StartUnsafePoint(p, c.newprog)
q := (*obj.Prog)(nil)
if framesize <= objabi.StackSmall {
// small stack: SP < stackguard
// MOV SP, R2
// CMP stackguard, R2
p = obj.Appendp(p, c.newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_REG
p.From.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(p, c.newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REG_R2
} else if framesize <= objabi.StackBig {
// large stack: SP-framesize < stackguard-StackSmall
// SUB $(framesize-StackSmall), SP, R2
// CMP stackguard, R2
p = obj.Appendp(p, c.newprog)
p.As = ASUB
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize) - objabi.StackSmall
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(p, c.newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.Reg = REG_R2
} else {
// Such a large stack we need to protect against wraparound
// if SP is close to zero.
// SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
// The +StackGuard on both sides is required to keep the left side positive:
// SP is allowed to be slightly below stackguard. See stack.h.
// CMP $StackPreempt, R1
// BEQ label_of_call_to_morestack
// ADD $StackGuard, SP, R2
// SUB R1, R2
// MOV $(framesize+(StackGuard-StackSmall)), R3
// CMP R3, R2
p = obj.Appendp(p, c.newprog)
p.As = ACMP
p.From.Type = obj.TYPE_CONST
p.From.Offset = objabi.StackPreempt
p.Reg = REG_R1
p = obj.Appendp(p, c.newprog)
q = p
p.As = ABEQ
p.To.Type = obj.TYPE_BRANCH
p = obj.Appendp(p, c.newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(objabi.StackGuard)
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(p, c.newprog)
p.As = ASUB
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
p = obj.Appendp(p, c.newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
p = obj.Appendp(p, c.newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.Reg = REG_R2
}
// BLS do-morestack
bls := obj.Appendp(p, c.newprog)
bls.As = ABLS
bls.To.Type = obj.TYPE_BRANCH
end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
var last *obj.Prog
for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
}
// Now we are at the end of the function, but logically
// we are still in function prologue. We need to fix the
// SP data and PCDATA.
spfix := obj.Appendp(last, c.newprog)
spfix.As = obj.ANOP
spfix.Spadj = -framesize
pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
// MOV LR, R3
movlr := obj.Appendp(pcdata, c.newprog)
movlr.As = AMOVD
movlr.From.Type = obj.TYPE_REG
movlr.From.Reg = REGLINK
movlr.To.Type = obj.TYPE_REG
movlr.To.Reg = REG_R3
if q != nil {
q.To.SetTarget(movlr)
}
bls.To.SetTarget(movlr)
debug := movlr
if false {
debug = obj.Appendp(debug, c.newprog)
debug.As = AMOVD
debug.From.Type = obj.TYPE_CONST
debug.From.Offset = int64(framesize)
debug.To.Type = obj.TYPE_REG
debug.To.Reg = REGTMP
}
// BL runtime.morestack(SB)
call := obj.Appendp(debug, c.newprog)
call.As = ABL
call.To.Type = obj.TYPE_BRANCH
morestack := "runtime.morestack"
switch {
case c.cursym.CFunc():
morestack = "runtime.morestackc"
case !c.cursym.Func.Text.From.Sym.NeedCtxt():
morestack = "runtime.morestack_noctxt"
}
call.To.Sym = c.ctxt.Lookup(morestack)
pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
// B start
jmp := obj.Appendp(pcdata, c.newprog)
jmp.As = AB
jmp.To.Type = obj.TYPE_BRANCH
jmp.To.SetTarget(c.cursym.Func.Text.Link)
jmp.Spadj = +framesize
return end
}
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
c := ctxt7{ctxt: ctxt, newprog: newprog}
p.From.Class = 0
p.To.Class = 0
// $0 results in C_ZCON, which matches both C_REG and various
// C_xCON, however the C_REG cases in asmout don't expect a
// constant, so they will use the register fields and assemble
// a R0. To prevent that, rewrite $0 as ZR.
if p.From.Type == obj.TYPE_CONST && p.From.Offset == 0 {
p.From.Type = obj.TYPE_REG
p.From.Reg = REGZERO
}
if p.To.Type == obj.TYPE_CONST && p.To.Offset == 0 {
p.To.Type = obj.TYPE_REG
p.To.Reg = REGZERO
}
// Rewrite BR/BL to symbol as TYPE_BRANCH.
switch p.As {
case AB,
ABL,
obj.ARET,
obj.ADUFFZERO,
obj.ADUFFCOPY:
if p.To.Sym != nil {
p.To.Type = obj.TYPE_BRANCH
}
break
}
// Rewrite float constants to values stored in memory.
switch p.As {
case AFMOVS:
if p.From.Type == obj.TYPE_FCONST {
f64 := p.From.Val.(float64)
f32 := float32(f64)
if c.chipfloat7(f64) > 0 {
break
}
if math.Float32bits(f32) == 0 {
p.From.Type = obj.TYPE_REG
p.From.Reg = REGZERO
break
}
p.From.Type = obj.TYPE_MEM
p.From.Sym = c.ctxt.Float32Sym(f32)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
case AFMOVD:
if p.From.Type == obj.TYPE_FCONST {
f64 := p.From.Val.(float64)
if c.chipfloat7(f64) > 0 {
break
}
if math.Float64bits(f64) == 0 {
p.From.Type = obj.TYPE_REG
p.From.Reg = REGZERO
break
}
p.From.Type = obj.TYPE_MEM
p.From.Sym = c.ctxt.Float64Sym(f64)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
break
}
// Rewrite negative immediates as positive immediates with
// complementary instruction.
switch p.As {
case AADD, ASUB, ACMP, ACMN:
if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && p.From.Offset != -1<<63 {
p.From.Offset = -p.From.Offset
p.As = complements[p.As]
}
case AADDW, ASUBW, ACMPW, ACMNW:
if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && int32(p.From.Offset) != -1<<31 {
p.From.Offset = -p.From.Offset
p.As = complements[p.As]
}
}
// For 32-bit logical instruction with constant,
// rewrite the high 32-bit to be a repetition of
// the low 32-bit, so that the BITCON test can be
// shared for both 32-bit and 64-bit. 32-bit ops
// will zero the high 32-bit of the destination
// register anyway.
if isANDWop(p.As) && p.From.Type == obj.TYPE_CONST {
v := p.From.Offset & 0xffffffff
p.From.Offset = v | v<<32
}
if c.ctxt.Flag_dynlink {
c.rewriteToUseGot(p)
}
}
// Rewrite p, if necessary, to access global data via the global offset table.
func (c *ctxt7) rewriteToUseGot(p *obj.Prog) {
if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
// ADUFFxxx $offset
// becomes
// MOVD runtime.duffxxx@GOT, REGTMP
// ADD $offset, REGTMP
// CALL REGTMP
var sym *obj.LSym
if p.As == obj.ADUFFZERO {
sym = c.ctxt.Lookup("runtime.duffzero")
} else {
sym = c.ctxt.Lookup("runtime.duffcopy")
}
offset := p.To.Offset
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
p.From.Sym = sym
p.To.Type = obj.TYPE_REG
p.To.Reg = REGTMP
p.To.Name = obj.NAME_NONE
p.To.Offset = 0
p.To.Sym = nil
p1 := obj.Appendp(p, c.newprog)
p1.As = AADD
p1.From.Type = obj.TYPE_CONST
p1.From.Offset = offset
p1.To.Type = obj.TYPE_REG
p1.To.Reg = REGTMP
p2 := obj.Appendp(p1, c.newprog)
p2.As = obj.ACALL
p2.To.Type = obj.TYPE_REG
p2.To.Reg = REGTMP
}
// We only care about global data: NAME_EXTERN means a global
// symbol in the Go sense, and p.Sym.Local is true for a few
// internally defined symbols.
if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
// MOVD $sym, Rx becomes MOVD sym@GOT, Rx
// MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx
if p.As != AMOVD {
c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
}
if p.To.Type != obj.TYPE_REG {
c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
}
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
if p.From.Offset != 0 {
q := obj.Appendp(p, c.newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = p.From.Offset
q.To = p.To
p.From.Offset = 0
}
}
if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
var source *obj.Addr
// MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry
// MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVD Ry, (REGTMP)
// An addition may be inserted between the two MOVs if there is an offset.
if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
}
source = &p.From
} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
source = &p.To
} else {
return
}
if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
return
}
if source.Sym.Type == objabi.STLSBSS {
return
}
if source.Type != obj.TYPE_MEM {
c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
p1 := obj.Appendp(p, c.newprog)
p2 := obj.Appendp(p1, c.newprog)
p1.As = AMOVD
p1.From.Type = obj.TYPE_MEM
p1.From.Sym = source.Sym
p1.From.Name = obj.NAME_GOTREF
p1.To.Type = obj.TYPE_REG
p1.To.Reg = REGTMP
p2.As = p.As
p2.From = p.From
p2.To = p.To
if p.From.Name == obj.NAME_EXTERN {
p2.From.Reg = REGTMP
p2.From.Name = obj.NAME_NONE
p2.From.Sym = nil
} else if p.To.Name == obj.NAME_EXTERN {
p2.To.Reg = REGTMP
p2.To.Name = obj.NAME_NONE
p2.To.Sym = nil
} else {
return
}
obj.Nopout(p)
}
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
return
}
c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym}
p := c.cursym.Func.Text
textstksiz := p.To.Offset
if textstksiz == -8 {
// Historical way to mark NOFRAME.
p.From.Sym.Set(obj.AttrNoFrame, true)
textstksiz = 0
}
if textstksiz < 0 {
c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
}
if p.From.Sym.NoFrame() {
if textstksiz != 0 {
c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
}
}
c.cursym.Func.Args = p.To.Val.(int32)
c.cursym.Func.Locals = int32(textstksiz)
/*
* find leaf subroutines
*/
for p := c.cursym.Func.Text; p != nil; p = p.Link {
switch p.As {
case obj.ATEXT:
p.Mark |= LEAF
case ABL,
obj.ADUFFZERO,
obj.ADUFFCOPY:
c.cursym.Func.Text.Mark &^= LEAF
}
}
var q *obj.Prog
var q1 *obj.Prog
var retjmp *obj.LSym
for p := c.cursym.Func.Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
c.cursym.Func.Text = p
c.autosize = int32(textstksiz)
if p.Mark&LEAF != 0 && c.autosize == 0 {
// A leaf function with no locals has no frame.
p.From.Sym.Set(obj.AttrNoFrame, true)
}
if !p.From.Sym.NoFrame() {
// If there is a stack frame at all, it includes
// space to save the LR.
c.autosize += 8
}
if c.autosize != 0 {
extrasize := int32(0)
if c.autosize%16 == 8 {
// Allocate extra 8 bytes on the frame top to save FP
extrasize = 8
} else if c.autosize&(16-1) == 0 {
// Allocate extra 16 bytes to save FP for the old frame whose size is 8 mod 16
extrasize = 16
} else {
c.ctxt.Diag("%v: unaligned frame size %d - must be 16 aligned", p, c.autosize-8)
}
c.autosize += extrasize
c.cursym.Func.Locals += extrasize
// low 32 bits for autosize
// high 32 bits for extrasize
p.To.Offset = int64(c.autosize) | int64(extrasize)<<32
} else {
// NOFRAME
p.To.Offset = 0
}
if c.autosize == 0 && c.cursym.Func.Text.Mark&LEAF == 0 {
if c.ctxt.Debugvlog {
c.ctxt.Logf("save suppressed in: %s\n", c.cursym.Func.Text.From.Sym.Name)
}
c.cursym.Func.Text.Mark |= LEAF
}
if cursym.Func.Text.Mark&LEAF != 0 {
cursym.Set(obj.AttrLeaf, true)
if p.From.Sym.NoFrame() {
break
}
}
if !p.From.Sym.NoSplit() {
p = c.stacksplit(p, c.autosize) // emit split check
}
var prologueEnd *obj.Prog
aoffset := c.autosize
if aoffset > 0xF0 {
aoffset = 0xF0
}
// Frame is non-empty. Make sure to save link register, even if
// it is a leaf function, so that traceback works.
q = p
if c.autosize > aoffset {
// Frame size is too large for a MOVD.W instruction.
// Store link register before decrementing SP, so if a signal comes
// during the execution of the function prologue, the traceback
// code will not see a half-updated stack frame.
// This sequence is not async preemptible, as if we open a frame
// at the current SP, it will clobber the saved LR.
q = c.ctxt.StartUnsafePoint(q, c.newprog)
q = obj.Appendp(q, c.newprog)
q.Pos = p.Pos
q.As = ASUB
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(c.autosize)
q.Reg = REGSP
q.To.Type = obj.TYPE_REG
q.To.Reg = REGTMP
prologueEnd = q
q = obj.Appendp(q, c.newprog)
q.Pos = p.Pos
q.As = AMOVD
q.From.Type = obj.TYPE_REG
q.From.Reg = REGLINK
q.To.Type = obj.TYPE_MEM
q.To.Reg = REGTMP
q1 = obj.Appendp(q, c.newprog)
q1.Pos = p.Pos
q1.As = AMOVD
q1.From.Type = obj.TYPE_REG
q1.From.Reg = REGTMP
q1.To.Type = obj.TYPE_REG
q1.To.Reg = REGSP
q1.Spadj = c.autosize
if c.ctxt.Headtype == objabi.Hdarwin {
// iOS does not support SA_ONSTACK. We will run the signal handler
// on the G stack. If we write below SP, it may be clobbered by
// the signal handler. So we save LR after decrementing SP.
q1 = obj.Appendp(q1, c.newprog)
q1.Pos = p.Pos
q1.As = AMOVD
q1.From.Type = obj.TYPE_REG
q1.From.Reg = REGLINK
q1.To.Type = obj.TYPE_MEM
q1.To.Reg = REGSP
}
q1 = c.ctxt.EndUnsafePoint(q1, c.newprog, -1)
} else {
// small frame, update SP and save LR in a single MOVD.W instruction
q1 = obj.Appendp(q, c.newprog)
q1.As = AMOVD
q1.Pos = p.Pos
q1.From.Type = obj.TYPE_REG
q1.From.Reg = REGLINK
q1.To.Type = obj.TYPE_MEM
q1.Scond = C_XPRE
q1.To.Offset = int64(-aoffset)
q1.To.Reg = REGSP
q1.Spadj = aoffset
prologueEnd = q1
}
prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
if objabi.Framepointer_enabled {
q1 = obj.Appendp(q1, c.newprog)
q1.Pos = p.Pos
q1.As = AMOVD
q1.From.Type = obj.TYPE_REG
q1.From.Reg = REGFP
q1.To.Type = obj.TYPE_MEM
q1.To.Reg = REGSP
q1.To.Offset = -8
q1 = obj.Appendp(q1, c.newprog)
q1.Pos = p.Pos
q1.As = ASUB
q1.From.Type = obj.TYPE_CONST
q1.From.Offset = 8
q1.Reg = REGSP
q1.To.Type = obj.TYPE_REG
q1.To.Reg = REGFP
}
if c.cursym.Func.Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOV g_panic(g), R1
// CBNZ checkargp
// end:
// NOP
// ... function body ...
// checkargp:
// MOV panic_argp(R1), R2
// ADD $(autosize+8), RSP, R3
// CMP R2, R3
// BNE end
// ADD $8, RSP, R4
// MOVD R4, panic_argp(R1)
// B end
//
// The NOP is needed to give the jumps somewhere to land.
// It is a liblink NOP, not an ARM64 NOP: it encodes to 0 instruction bytes.
q = q1
// MOV g_panic(g), R1
q = obj.Appendp(q, c.newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REGG
q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R1
// CBNZ R1, checkargp
cbnz := obj.Appendp(q, c.newprog)
cbnz.As = ACBNZ
cbnz.From.Type = obj.TYPE_REG
cbnz.From.Reg = REG_R1
cbnz.To.Type = obj.TYPE_BRANCH
// Empty branch target at the top of the function body
end := obj.Appendp(cbnz, c.newprog)
end.As = obj.ANOP
// find the end of the function
var last *obj.Prog
for last = end; last.Link != nil; last = last.Link {
}
// MOV panic_argp(R1), R2
mov := obj.Appendp(last, c.newprog)
mov.As = AMOVD
mov.From.Type = obj.TYPE_MEM
mov.From.Reg = REG_R1
mov.From.Offset = 0 // Panic.argp
mov.To.Type = obj.TYPE_REG
mov.To.Reg = REG_R2
// CBNZ branches to the MOV above
cbnz.To.SetTarget(mov)
// ADD $(autosize+8), SP, R3
q = obj.Appendp(mov, c.newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(c.autosize) + 8
q.Reg = REGSP
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R3
// CMP R2, R3
q = obj.Appendp(q, c.newprog)
q.As = ACMP
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R2
q.Reg = REG_R3
// BNE end
q = obj.Appendp(q, c.newprog)
q.As = ABNE
q.To.Type = obj.TYPE_BRANCH
q.To.SetTarget(end)
// ADD $8, SP, R4
q = obj.Appendp(q, c.newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = 8
q.Reg = REGSP
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R4
// MOV R4, panic_argp(R1)
q = obj.Appendp(q, c.newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R4
q.To.Type = obj.TYPE_MEM
q.To.Reg = REG_R1
q.To.Offset = 0 // Panic.argp
// B end
q = obj.Appendp(q, c.newprog)
q.As = AB
q.To.Type = obj.TYPE_BRANCH
q.To.SetTarget(end)
}
case obj.ARET:
nocache(p)
if p.From.Type == obj.TYPE_CONST {
c.ctxt.Diag("using BECOME (%v) is not supported!", p)
break
}
retjmp = p.To.Sym
p.To = obj.Addr{}
if c.cursym.Func.Text.Mark&LEAF != 0 {
if c.autosize != 0 {
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(c.autosize)
p.To.Type = obj.TYPE_REG
p.To.Reg = REGSP
p.Spadj = -c.autosize
if objabi.Framepointer_enabled {
p = obj.Appendp(p, c.newprog)
p.As = ASUB
p.From.Type = obj.TYPE_CONST
p.From.Offset = 8
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REGFP
}
}
} else {
/* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/
if objabi.Framepointer_enabled {
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGSP
p.From.Offset = -8
p.To.Type = obj.TYPE_REG
p.To.Reg = REGFP
p = obj.Appendp(p, c.newprog)
}
aoffset := c.autosize
if aoffset <= 0xF0 {
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.Scond = C_XPOST
p.From.Offset = int64(aoffset)
p.From.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REGLINK
p.Spadj = -aoffset
} else {
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Offset = 0
p.From.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REGLINK
q = newprog()
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(aoffset)
q.To.Type = obj.TYPE_REG
q.To.Reg = REGSP
q.Link = p.Link
q.Spadj = int32(-q.From.Offset)
q.Pos = p.Pos
p.Link = q
p = q
}
}
if p.As != obj.ARET {
q = newprog()
q.Pos = p.Pos
q.Link = p.Link
p.Link = q
p = q
}
if retjmp != nil { // retjmp
p.As = AB
p.To.Type = obj.TYPE_BRANCH
p.To.Sym = retjmp
p.Spadj = +c.autosize
break
}
p.As = obj.ARET
p.To.Type = obj.TYPE_MEM
p.To.Offset = 0
p.To.Reg = REGLINK
p.Spadj = +c.autosize
case AADD, ASUB:
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
if p.As == AADD {
p.Spadj = int32(-p.From.Offset)
} else {
p.Spadj = int32(+p.From.Offset)
}
}
case obj.AGETCALLERPC:
if cursym.Leaf() {
/* MOVD LR, Rd */
p.As = AMOVD
p.From.Type = obj.TYPE_REG
p.From.Reg = REGLINK
} else {
/* MOVD (RSP), Rd */
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGSP
}
case obj.ADUFFCOPY:
if objabi.Framepointer_enabled {
// ADR ret_addr, R27
// STP (FP, R27), -24(SP)
// SUB 24, SP, FP
// DUFFCOPY
// ret_addr:
// SUB 8, SP, FP
q1 := p
// copy DUFFCOPY from q1 to q4
q4 := obj.Appendp(p, c.newprog)
q4.Pos = p.Pos
q4.As = obj.ADUFFCOPY
q4.To = p.To
q1.As = AADR
q1.From.Type = obj.TYPE_BRANCH
q1.To.Type = obj.TYPE_REG
q1.To.Reg = REG_R27
q2 := obj.Appendp(q1, c.newprog)
q2.Pos = p.Pos
q2.As = ASTP
q2.From.Type = obj.TYPE_REGREG
q2.From.Reg = REGFP
q2.From.Offset = int64(REG_R27)
q2.To.Type = obj.TYPE_MEM
q2.To.Reg = REGSP
q2.To.Offset = -24
// maintaine FP for DUFFCOPY
q3 := obj.Appendp(q2, c.newprog)
q3.Pos = p.Pos
q3.As = ASUB
q3.From.Type = obj.TYPE_CONST
q3.From.Offset = 24
q3.Reg = REGSP
q3.To.Type = obj.TYPE_REG
q3.To.Reg = REGFP
q5 := obj.Appendp(q4, c.newprog)
q5.Pos = p.Pos
q5.As = ASUB
q5.From.Type = obj.TYPE_CONST
q5.From.Offset = 8
q5.Reg = REGSP
q5.To.Type = obj.TYPE_REG
q5.To.Reg = REGFP
q1.From.SetTarget(q5)
p = q5
}
case obj.ADUFFZERO:
if objabi.Framepointer_enabled {
// ADR ret_addr, R27
// STP (FP, R27), -24(SP)
// SUB 24, SP, FP
// DUFFZERO
// ret_addr:
// SUB 8, SP, FP
q1 := p
// copy DUFFZERO from q1 to q4
q4 := obj.Appendp(p, c.newprog)
q4.Pos = p.Pos
q4.As = obj.ADUFFZERO
q4.To = p.To
q1.As = AADR
q1.From.Type = obj.TYPE_BRANCH
q1.To.Type = obj.TYPE_REG
q1.To.Reg = REG_R27
q2 := obj.Appendp(q1, c.newprog)
q2.Pos = p.Pos
q2.As = ASTP
q2.From.Type = obj.TYPE_REGREG
q2.From.Reg = REGFP
q2.From.Offset = int64(REG_R27)
q2.To.Type = obj.TYPE_MEM
q2.To.Reg = REGSP
q2.To.Offset = -24
// maintaine FP for DUFFZERO
q3 := obj.Appendp(q2, c.newprog)
q3.Pos = p.Pos
q3.As = ASUB
q3.From.Type = obj.TYPE_CONST
q3.From.Offset = 24
q3.Reg = REGSP
q3.To.Type = obj.TYPE_REG
q3.To.Reg = REGFP
q5 := obj.Appendp(q4, c.newprog)
q5.Pos = p.Pos
q5.As = ASUB
q5.From.Type = obj.TYPE_CONST
q5.From.Offset = 8
q5.Reg = REGSP
q5.To.Type = obj.TYPE_REG
q5.To.Reg = REGFP
q1.From.SetTarget(q5)
p = q5
}
}
}
}
func nocache(p *obj.Prog) {
p.Optab = 0
p.From.Class = 0
p.To.Class = 0
}
var unaryDst = map[obj.As]bool{
AWORD: true,
ADWORD: true,
ABL: true,
AB: true,
ACLREX: true,
}
var Linkarm64 = obj.LinkArch{
Arch: sys.ArchARM64,
Init: buildop,
Preprocess: preprocess,
Assemble: span7,
Progedit: progedit,
UnaryDst: unaryDst,
DWARFRegisters: ARM64DWARFRegisters,
}

View File

@ -0,0 +1,895 @@
// Code generated by arm64gen -i ./files -o sysRegEnc.go. DO NOT EDIT.
package arm64
const (
SYSREG_BEGIN = REG_SPECIAL + iota
REG_ACTLR_EL1
REG_AFSR0_EL1
REG_AFSR1_EL1
REG_AIDR_EL1
REG_AMAIR_EL1
REG_AMCFGR_EL0
REG_AMCGCR_EL0
REG_AMCNTENCLR0_EL0
REG_AMCNTENCLR1_EL0
REG_AMCNTENSET0_EL0
REG_AMCNTENSET1_EL0
REG_AMCR_EL0
REG_AMEVCNTR00_EL0
REG_AMEVCNTR01_EL0
REG_AMEVCNTR02_EL0
REG_AMEVCNTR03_EL0
REG_AMEVCNTR04_EL0
REG_AMEVCNTR05_EL0
REG_AMEVCNTR06_EL0
REG_AMEVCNTR07_EL0
REG_AMEVCNTR08_EL0
REG_AMEVCNTR09_EL0
REG_AMEVCNTR010_EL0
REG_AMEVCNTR011_EL0
REG_AMEVCNTR012_EL0
REG_AMEVCNTR013_EL0
REG_AMEVCNTR014_EL0
REG_AMEVCNTR015_EL0
REG_AMEVCNTR10_EL0
REG_AMEVCNTR11_EL0
REG_AMEVCNTR12_EL0
REG_AMEVCNTR13_EL0
REG_AMEVCNTR14_EL0
REG_AMEVCNTR15_EL0
REG_AMEVCNTR16_EL0
REG_AMEVCNTR17_EL0
REG_AMEVCNTR18_EL0
REG_AMEVCNTR19_EL0
REG_AMEVCNTR110_EL0
REG_AMEVCNTR111_EL0
REG_AMEVCNTR112_EL0
REG_AMEVCNTR113_EL0
REG_AMEVCNTR114_EL0
REG_AMEVCNTR115_EL0
REG_AMEVTYPER00_EL0
REG_AMEVTYPER01_EL0
REG_AMEVTYPER02_EL0
REG_AMEVTYPER03_EL0
REG_AMEVTYPER04_EL0
REG_AMEVTYPER05_EL0
REG_AMEVTYPER06_EL0
REG_AMEVTYPER07_EL0
REG_AMEVTYPER08_EL0
REG_AMEVTYPER09_EL0
REG_AMEVTYPER010_EL0
REG_AMEVTYPER011_EL0
REG_AMEVTYPER012_EL0
REG_AMEVTYPER013_EL0
REG_AMEVTYPER014_EL0
REG_AMEVTYPER015_EL0
REG_AMEVTYPER10_EL0
REG_AMEVTYPER11_EL0
REG_AMEVTYPER12_EL0
REG_AMEVTYPER13_EL0
REG_AMEVTYPER14_EL0
REG_AMEVTYPER15_EL0
REG_AMEVTYPER16_EL0
REG_AMEVTYPER17_EL0
REG_AMEVTYPER18_EL0
REG_AMEVTYPER19_EL0
REG_AMEVTYPER110_EL0
REG_AMEVTYPER111_EL0
REG_AMEVTYPER112_EL0
REG_AMEVTYPER113_EL0
REG_AMEVTYPER114_EL0
REG_AMEVTYPER115_EL0
REG_AMUSERENR_EL0
REG_APDAKeyHi_EL1
REG_APDAKeyLo_EL1
REG_APDBKeyHi_EL1
REG_APDBKeyLo_EL1
REG_APGAKeyHi_EL1
REG_APGAKeyLo_EL1
REG_APIAKeyHi_EL1
REG_APIAKeyLo_EL1
REG_APIBKeyHi_EL1
REG_APIBKeyLo_EL1
REG_CCSIDR2_EL1
REG_CCSIDR_EL1
REG_CLIDR_EL1
REG_CNTFRQ_EL0
REG_CNTKCTL_EL1
REG_CNTP_CTL_EL0
REG_CNTP_CVAL_EL0
REG_CNTP_TVAL_EL0
REG_CNTPCT_EL0
REG_CNTPS_CTL_EL1
REG_CNTPS_CVAL_EL1
REG_CNTPS_TVAL_EL1
REG_CNTV_CTL_EL0
REG_CNTV_CVAL_EL0
REG_CNTV_TVAL_EL0
REG_CNTVCT_EL0
REG_CONTEXTIDR_EL1
REG_CPACR_EL1
REG_CSSELR_EL1
REG_CTR_EL0
REG_CurrentEL
REG_DAIF
REG_DBGAUTHSTATUS_EL1
REG_DBGBCR0_EL1
REG_DBGBCR1_EL1
REG_DBGBCR2_EL1
REG_DBGBCR3_EL1
REG_DBGBCR4_EL1
REG_DBGBCR5_EL1
REG_DBGBCR6_EL1
REG_DBGBCR7_EL1
REG_DBGBCR8_EL1
REG_DBGBCR9_EL1
REG_DBGBCR10_EL1
REG_DBGBCR11_EL1
REG_DBGBCR12_EL1
REG_DBGBCR13_EL1
REG_DBGBCR14_EL1
REG_DBGBCR15_EL1
REG_DBGBVR0_EL1
REG_DBGBVR1_EL1
REG_DBGBVR2_EL1
REG_DBGBVR3_EL1
REG_DBGBVR4_EL1
REG_DBGBVR5_EL1
REG_DBGBVR6_EL1
REG_DBGBVR7_EL1
REG_DBGBVR8_EL1
REG_DBGBVR9_EL1
REG_DBGBVR10_EL1
REG_DBGBVR11_EL1
REG_DBGBVR12_EL1
REG_DBGBVR13_EL1
REG_DBGBVR14_EL1
REG_DBGBVR15_EL1
REG_DBGCLAIMCLR_EL1
REG_DBGCLAIMSET_EL1
REG_DBGDTR_EL0
REG_DBGDTRRX_EL0
REG_DBGDTRTX_EL0
REG_DBGPRCR_EL1
REG_DBGWCR0_EL1
REG_DBGWCR1_EL1
REG_DBGWCR2_EL1
REG_DBGWCR3_EL1
REG_DBGWCR4_EL1
REG_DBGWCR5_EL1
REG_DBGWCR6_EL1
REG_DBGWCR7_EL1
REG_DBGWCR8_EL1
REG_DBGWCR9_EL1
REG_DBGWCR10_EL1
REG_DBGWCR11_EL1
REG_DBGWCR12_EL1
REG_DBGWCR13_EL1
REG_DBGWCR14_EL1
REG_DBGWCR15_EL1
REG_DBGWVR0_EL1
REG_DBGWVR1_EL1
REG_DBGWVR2_EL1
REG_DBGWVR3_EL1
REG_DBGWVR4_EL1
REG_DBGWVR5_EL1
REG_DBGWVR6_EL1
REG_DBGWVR7_EL1
REG_DBGWVR8_EL1
REG_DBGWVR9_EL1
REG_DBGWVR10_EL1
REG_DBGWVR11_EL1
REG_DBGWVR12_EL1
REG_DBGWVR13_EL1
REG_DBGWVR14_EL1
REG_DBGWVR15_EL1
REG_DCZID_EL0
REG_DISR_EL1
REG_DIT
REG_DLR_EL0
REG_DSPSR_EL0
REG_ELR_EL1
REG_ERRIDR_EL1
REG_ERRSELR_EL1
REG_ERXADDR_EL1
REG_ERXCTLR_EL1
REG_ERXFR_EL1
REG_ERXMISC0_EL1
REG_ERXMISC1_EL1
REG_ERXMISC2_EL1
REG_ERXMISC3_EL1
REG_ERXPFGCDN_EL1
REG_ERXPFGCTL_EL1
REG_ERXPFGF_EL1
REG_ERXSTATUS_EL1
REG_ESR_EL1
REG_FAR_EL1
REG_FPCR
REG_FPSR
REG_GCR_EL1
REG_GMID_EL1
REG_ICC_AP0R0_EL1
REG_ICC_AP0R1_EL1
REG_ICC_AP0R2_EL1
REG_ICC_AP0R3_EL1
REG_ICC_AP1R0_EL1
REG_ICC_AP1R1_EL1
REG_ICC_AP1R2_EL1
REG_ICC_AP1R3_EL1
REG_ICC_ASGI1R_EL1
REG_ICC_BPR0_EL1
REG_ICC_BPR1_EL1
REG_ICC_CTLR_EL1
REG_ICC_DIR_EL1
REG_ICC_EOIR0_EL1
REG_ICC_EOIR1_EL1
REG_ICC_HPPIR0_EL1
REG_ICC_HPPIR1_EL1
REG_ICC_IAR0_EL1
REG_ICC_IAR1_EL1
REG_ICC_IGRPEN0_EL1
REG_ICC_IGRPEN1_EL1
REG_ICC_PMR_EL1
REG_ICC_RPR_EL1
REG_ICC_SGI0R_EL1
REG_ICC_SGI1R_EL1
REG_ICC_SRE_EL1
REG_ICV_AP0R0_EL1
REG_ICV_AP0R1_EL1
REG_ICV_AP0R2_EL1
REG_ICV_AP0R3_EL1
REG_ICV_AP1R0_EL1
REG_ICV_AP1R1_EL1
REG_ICV_AP1R2_EL1
REG_ICV_AP1R3_EL1
REG_ICV_BPR0_EL1
REG_ICV_BPR1_EL1
REG_ICV_CTLR_EL1
REG_ICV_DIR_EL1
REG_ICV_EOIR0_EL1
REG_ICV_EOIR1_EL1
REG_ICV_HPPIR0_EL1
REG_ICV_HPPIR1_EL1
REG_ICV_IAR0_EL1
REG_ICV_IAR1_EL1
REG_ICV_IGRPEN0_EL1
REG_ICV_IGRPEN1_EL1
REG_ICV_PMR_EL1
REG_ICV_RPR_EL1
REG_ID_AA64AFR0_EL1
REG_ID_AA64AFR1_EL1
REG_ID_AA64DFR0_EL1
REG_ID_AA64DFR1_EL1
REG_ID_AA64ISAR0_EL1
REG_ID_AA64ISAR1_EL1
REG_ID_AA64MMFR0_EL1
REG_ID_AA64MMFR1_EL1
REG_ID_AA64MMFR2_EL1
REG_ID_AA64PFR0_EL1
REG_ID_AA64PFR1_EL1
REG_ID_AA64ZFR0_EL1
REG_ID_AFR0_EL1
REG_ID_DFR0_EL1
REG_ID_ISAR0_EL1
REG_ID_ISAR1_EL1
REG_ID_ISAR2_EL1
REG_ID_ISAR3_EL1
REG_ID_ISAR4_EL1
REG_ID_ISAR5_EL1
REG_ID_ISAR6_EL1
REG_ID_MMFR0_EL1
REG_ID_MMFR1_EL1
REG_ID_MMFR2_EL1
REG_ID_MMFR3_EL1
REG_ID_MMFR4_EL1
REG_ID_PFR0_EL1
REG_ID_PFR1_EL1
REG_ID_PFR2_EL1
REG_ISR_EL1
REG_LORC_EL1
REG_LOREA_EL1
REG_LORID_EL1
REG_LORN_EL1
REG_LORSA_EL1
REG_MAIR_EL1
REG_MDCCINT_EL1
REG_MDCCSR_EL0
REG_MDRAR_EL1
REG_MDSCR_EL1
REG_MIDR_EL1
REG_MPAM0_EL1
REG_MPAM1_EL1
REG_MPAMIDR_EL1
REG_MPIDR_EL1
REG_MVFR0_EL1
REG_MVFR1_EL1
REG_MVFR2_EL1
REG_NZCV
REG_OSDLR_EL1
REG_OSDTRRX_EL1
REG_OSDTRTX_EL1
REG_OSECCR_EL1
REG_OSLAR_EL1
REG_OSLSR_EL1
REG_PAN
REG_PAR_EL1
REG_PMBIDR_EL1
REG_PMBLIMITR_EL1
REG_PMBPTR_EL1
REG_PMBSR_EL1
REG_PMCCFILTR_EL0
REG_PMCCNTR_EL0
REG_PMCEID0_EL0
REG_PMCEID1_EL0
REG_PMCNTENCLR_EL0
REG_PMCNTENSET_EL0
REG_PMCR_EL0
REG_PMEVCNTR0_EL0
REG_PMEVCNTR1_EL0
REG_PMEVCNTR2_EL0
REG_PMEVCNTR3_EL0
REG_PMEVCNTR4_EL0
REG_PMEVCNTR5_EL0
REG_PMEVCNTR6_EL0
REG_PMEVCNTR7_EL0
REG_PMEVCNTR8_EL0
REG_PMEVCNTR9_EL0
REG_PMEVCNTR10_EL0
REG_PMEVCNTR11_EL0
REG_PMEVCNTR12_EL0
REG_PMEVCNTR13_EL0
REG_PMEVCNTR14_EL0
REG_PMEVCNTR15_EL0
REG_PMEVCNTR16_EL0
REG_PMEVCNTR17_EL0
REG_PMEVCNTR18_EL0
REG_PMEVCNTR19_EL0
REG_PMEVCNTR20_EL0
REG_PMEVCNTR21_EL0
REG_PMEVCNTR22_EL0
REG_PMEVCNTR23_EL0
REG_PMEVCNTR24_EL0
REG_PMEVCNTR25_EL0
REG_PMEVCNTR26_EL0
REG_PMEVCNTR27_EL0
REG_PMEVCNTR28_EL0
REG_PMEVCNTR29_EL0
REG_PMEVCNTR30_EL0
REG_PMEVTYPER0_EL0
REG_PMEVTYPER1_EL0
REG_PMEVTYPER2_EL0
REG_PMEVTYPER3_EL0
REG_PMEVTYPER4_EL0
REG_PMEVTYPER5_EL0
REG_PMEVTYPER6_EL0
REG_PMEVTYPER7_EL0
REG_PMEVTYPER8_EL0
REG_PMEVTYPER9_EL0
REG_PMEVTYPER10_EL0
REG_PMEVTYPER11_EL0
REG_PMEVTYPER12_EL0
REG_PMEVTYPER13_EL0
REG_PMEVTYPER14_EL0
REG_PMEVTYPER15_EL0
REG_PMEVTYPER16_EL0
REG_PMEVTYPER17_EL0
REG_PMEVTYPER18_EL0
REG_PMEVTYPER19_EL0
REG_PMEVTYPER20_EL0
REG_PMEVTYPER21_EL0
REG_PMEVTYPER22_EL0
REG_PMEVTYPER23_EL0
REG_PMEVTYPER24_EL0
REG_PMEVTYPER25_EL0
REG_PMEVTYPER26_EL0
REG_PMEVTYPER27_EL0
REG_PMEVTYPER28_EL0
REG_PMEVTYPER29_EL0
REG_PMEVTYPER30_EL0
REG_PMINTENCLR_EL1
REG_PMINTENSET_EL1
REG_PMMIR_EL1
REG_PMOVSCLR_EL0
REG_PMOVSSET_EL0
REG_PMSCR_EL1
REG_PMSELR_EL0
REG_PMSEVFR_EL1
REG_PMSFCR_EL1
REG_PMSICR_EL1
REG_PMSIDR_EL1
REG_PMSIRR_EL1
REG_PMSLATFR_EL1
REG_PMSWINC_EL0
REG_PMUSERENR_EL0
REG_PMXEVCNTR_EL0
REG_PMXEVTYPER_EL0
REG_REVIDR_EL1
REG_RGSR_EL1
REG_RMR_EL1
REG_RNDR
REG_RNDRRS
REG_RVBAR_EL1
REG_SCTLR_EL1
REG_SCXTNUM_EL0
REG_SCXTNUM_EL1
REG_SP_EL0
REG_SP_EL1
REG_SPSel
REG_SPSR_abt
REG_SPSR_EL1
REG_SPSR_fiq
REG_SPSR_irq
REG_SPSR_und
REG_SSBS
REG_TCO
REG_TCR_EL1
REG_TFSR_EL1
REG_TFSRE0_EL1
REG_TPIDR_EL0
REG_TPIDR_EL1
REG_TPIDRRO_EL0
REG_TRFCR_EL1
REG_TTBR0_EL1
REG_TTBR1_EL1
REG_UAO
REG_VBAR_EL1
REG_ZCR_EL1
SYSREG_END
)
const (
SR_READ = 1 << iota
SR_WRITE
)
var SystemReg = []struct {
Name string
Reg int16
Enc uint32
// AccessFlags is the readable and writeable property of system register.
AccessFlags uint8
}{
{"ACTLR_EL1", REG_ACTLR_EL1, 0x181020, SR_READ | SR_WRITE},
{"AFSR0_EL1", REG_AFSR0_EL1, 0x185100, SR_READ | SR_WRITE},
{"AFSR1_EL1", REG_AFSR1_EL1, 0x185120, SR_READ | SR_WRITE},
{"AIDR_EL1", REG_AIDR_EL1, 0x1900e0, SR_READ},
{"AMAIR_EL1", REG_AMAIR_EL1, 0x18a300, SR_READ | SR_WRITE},
{"AMCFGR_EL0", REG_AMCFGR_EL0, 0x1bd220, SR_READ},
{"AMCGCR_EL0", REG_AMCGCR_EL0, 0x1bd240, SR_READ},
{"AMCNTENCLR0_EL0", REG_AMCNTENCLR0_EL0, 0x1bd280, SR_READ | SR_WRITE},
{"AMCNTENCLR1_EL0", REG_AMCNTENCLR1_EL0, 0x1bd300, SR_READ | SR_WRITE},
{"AMCNTENSET0_EL0", REG_AMCNTENSET0_EL0, 0x1bd2a0, SR_READ | SR_WRITE},
{"AMCNTENSET1_EL0", REG_AMCNTENSET1_EL0, 0x1bd320, SR_READ | SR_WRITE},
{"AMCR_EL0", REG_AMCR_EL0, 0x1bd200, SR_READ | SR_WRITE},
{"AMEVCNTR00_EL0", REG_AMEVCNTR00_EL0, 0x1bd400, SR_READ | SR_WRITE},
{"AMEVCNTR01_EL0", REG_AMEVCNTR01_EL0, 0x1bd420, SR_READ | SR_WRITE},
{"AMEVCNTR02_EL0", REG_AMEVCNTR02_EL0, 0x1bd440, SR_READ | SR_WRITE},
{"AMEVCNTR03_EL0", REG_AMEVCNTR03_EL0, 0x1bd460, SR_READ | SR_WRITE},
{"AMEVCNTR04_EL0", REG_AMEVCNTR04_EL0, 0x1bd480, SR_READ | SR_WRITE},
{"AMEVCNTR05_EL0", REG_AMEVCNTR05_EL0, 0x1bd4a0, SR_READ | SR_WRITE},
{"AMEVCNTR06_EL0", REG_AMEVCNTR06_EL0, 0x1bd4c0, SR_READ | SR_WRITE},
{"AMEVCNTR07_EL0", REG_AMEVCNTR07_EL0, 0x1bd4e0, SR_READ | SR_WRITE},
{"AMEVCNTR08_EL0", REG_AMEVCNTR08_EL0, 0x1bd500, SR_READ | SR_WRITE},
{"AMEVCNTR09_EL0", REG_AMEVCNTR09_EL0, 0x1bd520, SR_READ | SR_WRITE},
{"AMEVCNTR010_EL0", REG_AMEVCNTR010_EL0, 0x1bd540, SR_READ | SR_WRITE},
{"AMEVCNTR011_EL0", REG_AMEVCNTR011_EL0, 0x1bd560, SR_READ | SR_WRITE},
{"AMEVCNTR012_EL0", REG_AMEVCNTR012_EL0, 0x1bd580, SR_READ | SR_WRITE},
{"AMEVCNTR013_EL0", REG_AMEVCNTR013_EL0, 0x1bd5a0, SR_READ | SR_WRITE},
{"AMEVCNTR014_EL0", REG_AMEVCNTR014_EL0, 0x1bd5c0, SR_READ | SR_WRITE},
{"AMEVCNTR015_EL0", REG_AMEVCNTR015_EL0, 0x1bd5e0, SR_READ | SR_WRITE},
{"AMEVCNTR10_EL0", REG_AMEVCNTR10_EL0, 0x1bdc00, SR_READ | SR_WRITE},
{"AMEVCNTR11_EL0", REG_AMEVCNTR11_EL0, 0x1bdc20, SR_READ | SR_WRITE},
{"AMEVCNTR12_EL0", REG_AMEVCNTR12_EL0, 0x1bdc40, SR_READ | SR_WRITE},
{"AMEVCNTR13_EL0", REG_AMEVCNTR13_EL0, 0x1bdc60, SR_READ | SR_WRITE},
{"AMEVCNTR14_EL0", REG_AMEVCNTR14_EL0, 0x1bdc80, SR_READ | SR_WRITE},
{"AMEVCNTR15_EL0", REG_AMEVCNTR15_EL0, 0x1bdca0, SR_READ | SR_WRITE},
{"AMEVCNTR16_EL0", REG_AMEVCNTR16_EL0, 0x1bdcc0, SR_READ | SR_WRITE},
{"AMEVCNTR17_EL0", REG_AMEVCNTR17_EL0, 0x1bdce0, SR_READ | SR_WRITE},
{"AMEVCNTR18_EL0", REG_AMEVCNTR18_EL0, 0x1bdd00, SR_READ | SR_WRITE},
{"AMEVCNTR19_EL0", REG_AMEVCNTR19_EL0, 0x1bdd20, SR_READ | SR_WRITE},
{"AMEVCNTR110_EL0", REG_AMEVCNTR110_EL0, 0x1bdd40, SR_READ | SR_WRITE},
{"AMEVCNTR111_EL0", REG_AMEVCNTR111_EL0, 0x1bdd60, SR_READ | SR_WRITE},
{"AMEVCNTR112_EL0", REG_AMEVCNTR112_EL0, 0x1bdd80, SR_READ | SR_WRITE},
{"AMEVCNTR113_EL0", REG_AMEVCNTR113_EL0, 0x1bdda0, SR_READ | SR_WRITE},
{"AMEVCNTR114_EL0", REG_AMEVCNTR114_EL0, 0x1bddc0, SR_READ | SR_WRITE},
{"AMEVCNTR115_EL0", REG_AMEVCNTR115_EL0, 0x1bdde0, SR_READ | SR_WRITE},
{"AMEVTYPER00_EL0", REG_AMEVTYPER00_EL0, 0x1bd600, SR_READ},
{"AMEVTYPER01_EL0", REG_AMEVTYPER01_EL0, 0x1bd620, SR_READ},
{"AMEVTYPER02_EL0", REG_AMEVTYPER02_EL0, 0x1bd640, SR_READ},
{"AMEVTYPER03_EL0", REG_AMEVTYPER03_EL0, 0x1bd660, SR_READ},
{"AMEVTYPER04_EL0", REG_AMEVTYPER04_EL0, 0x1bd680, SR_READ},
{"AMEVTYPER05_EL0", REG_AMEVTYPER05_EL0, 0x1bd6a0, SR_READ},
{"AMEVTYPER06_EL0", REG_AMEVTYPER06_EL0, 0x1bd6c0, SR_READ},
{"AMEVTYPER07_EL0", REG_AMEVTYPER07_EL0, 0x1bd6e0, SR_READ},
{"AMEVTYPER08_EL0", REG_AMEVTYPER08_EL0, 0x1bd700, SR_READ},
{"AMEVTYPER09_EL0", REG_AMEVTYPER09_EL0, 0x1bd720, SR_READ},
{"AMEVTYPER010_EL0", REG_AMEVTYPER010_EL0, 0x1bd740, SR_READ},
{"AMEVTYPER011_EL0", REG_AMEVTYPER011_EL0, 0x1bd760, SR_READ},
{"AMEVTYPER012_EL0", REG_AMEVTYPER012_EL0, 0x1bd780, SR_READ},
{"AMEVTYPER013_EL0", REG_AMEVTYPER013_EL0, 0x1bd7a0, SR_READ},
{"AMEVTYPER014_EL0", REG_AMEVTYPER014_EL0, 0x1bd7c0, SR_READ},
{"AMEVTYPER015_EL0", REG_AMEVTYPER015_EL0, 0x1bd7e0, SR_READ},
{"AMEVTYPER10_EL0", REG_AMEVTYPER10_EL0, 0x1bde00, SR_READ | SR_WRITE},
{"AMEVTYPER11_EL0", REG_AMEVTYPER11_EL0, 0x1bde20, SR_READ | SR_WRITE},
{"AMEVTYPER12_EL0", REG_AMEVTYPER12_EL0, 0x1bde40, SR_READ | SR_WRITE},
{"AMEVTYPER13_EL0", REG_AMEVTYPER13_EL0, 0x1bde60, SR_READ | SR_WRITE},
{"AMEVTYPER14_EL0", REG_AMEVTYPER14_EL0, 0x1bde80, SR_READ | SR_WRITE},
{"AMEVTYPER15_EL0", REG_AMEVTYPER15_EL0, 0x1bdea0, SR_READ | SR_WRITE},
{"AMEVTYPER16_EL0", REG_AMEVTYPER16_EL0, 0x1bdec0, SR_READ | SR_WRITE},
{"AMEVTYPER17_EL0", REG_AMEVTYPER17_EL0, 0x1bdee0, SR_READ | SR_WRITE},
{"AMEVTYPER18_EL0", REG_AMEVTYPER18_EL0, 0x1bdf00, SR_READ | SR_WRITE},
{"AMEVTYPER19_EL0", REG_AMEVTYPER19_EL0, 0x1bdf20, SR_READ | SR_WRITE},
{"AMEVTYPER110_EL0", REG_AMEVTYPER110_EL0, 0x1bdf40, SR_READ | SR_WRITE},
{"AMEVTYPER111_EL0", REG_AMEVTYPER111_EL0, 0x1bdf60, SR_READ | SR_WRITE},
{"AMEVTYPER112_EL0", REG_AMEVTYPER112_EL0, 0x1bdf80, SR_READ | SR_WRITE},
{"AMEVTYPER113_EL0", REG_AMEVTYPER113_EL0, 0x1bdfa0, SR_READ | SR_WRITE},
{"AMEVTYPER114_EL0", REG_AMEVTYPER114_EL0, 0x1bdfc0, SR_READ | SR_WRITE},
{"AMEVTYPER115_EL0", REG_AMEVTYPER115_EL0, 0x1bdfe0, SR_READ | SR_WRITE},
{"AMUSERENR_EL0", REG_AMUSERENR_EL0, 0x1bd260, SR_READ | SR_WRITE},
{"APDAKeyHi_EL1", REG_APDAKeyHi_EL1, 0x182220, SR_READ | SR_WRITE},
{"APDAKeyLo_EL1", REG_APDAKeyLo_EL1, 0x182200, SR_READ | SR_WRITE},
{"APDBKeyHi_EL1", REG_APDBKeyHi_EL1, 0x182260, SR_READ | SR_WRITE},
{"APDBKeyLo_EL1", REG_APDBKeyLo_EL1, 0x182240, SR_READ | SR_WRITE},
{"APGAKeyHi_EL1", REG_APGAKeyHi_EL1, 0x182320, SR_READ | SR_WRITE},
{"APGAKeyLo_EL1", REG_APGAKeyLo_EL1, 0x182300, SR_READ | SR_WRITE},
{"APIAKeyHi_EL1", REG_APIAKeyHi_EL1, 0x182120, SR_READ | SR_WRITE},
{"APIAKeyLo_EL1", REG_APIAKeyLo_EL1, 0x182100, SR_READ | SR_WRITE},
{"APIBKeyHi_EL1", REG_APIBKeyHi_EL1, 0x182160, SR_READ | SR_WRITE},
{"APIBKeyLo_EL1", REG_APIBKeyLo_EL1, 0x182140, SR_READ | SR_WRITE},
{"CCSIDR2_EL1", REG_CCSIDR2_EL1, 0x190040, SR_READ},
{"CCSIDR_EL1", REG_CCSIDR_EL1, 0x190000, SR_READ},
{"CLIDR_EL1", REG_CLIDR_EL1, 0x190020, SR_READ},
{"CNTFRQ_EL0", REG_CNTFRQ_EL0, 0x1be000, SR_READ | SR_WRITE},
{"CNTKCTL_EL1", REG_CNTKCTL_EL1, 0x18e100, SR_READ | SR_WRITE},
{"CNTP_CTL_EL0", REG_CNTP_CTL_EL0, 0x1be220, SR_READ | SR_WRITE},
{"CNTP_CVAL_EL0", REG_CNTP_CVAL_EL0, 0x1be240, SR_READ | SR_WRITE},
{"CNTP_TVAL_EL0", REG_CNTP_TVAL_EL0, 0x1be200, SR_READ | SR_WRITE},
{"CNTPCT_EL0", REG_CNTPCT_EL0, 0x1be020, SR_READ},
{"CNTPS_CTL_EL1", REG_CNTPS_CTL_EL1, 0x1fe220, SR_READ | SR_WRITE},
{"CNTPS_CVAL_EL1", REG_CNTPS_CVAL_EL1, 0x1fe240, SR_READ | SR_WRITE},
{"CNTPS_TVAL_EL1", REG_CNTPS_TVAL_EL1, 0x1fe200, SR_READ | SR_WRITE},
{"CNTV_CTL_EL0", REG_CNTV_CTL_EL0, 0x1be320, SR_READ | SR_WRITE},
{"CNTV_CVAL_EL0", REG_CNTV_CVAL_EL0, 0x1be340, SR_READ | SR_WRITE},
{"CNTV_TVAL_EL0", REG_CNTV_TVAL_EL0, 0x1be300, SR_READ | SR_WRITE},
{"CNTVCT_EL0", REG_CNTVCT_EL0, 0x1be040, SR_READ},
{"CONTEXTIDR_EL1", REG_CONTEXTIDR_EL1, 0x18d020, SR_READ | SR_WRITE},
{"CPACR_EL1", REG_CPACR_EL1, 0x181040, SR_READ | SR_WRITE},
{"CSSELR_EL1", REG_CSSELR_EL1, 0x1a0000, SR_READ | SR_WRITE},
{"CTR_EL0", REG_CTR_EL0, 0x1b0020, SR_READ},
{"CurrentEL", REG_CurrentEL, 0x184240, SR_READ},
{"DAIF", REG_DAIF, 0x1b4220, SR_READ | SR_WRITE},
{"DBGAUTHSTATUS_EL1", REG_DBGAUTHSTATUS_EL1, 0x107ec0, SR_READ},
{"DBGBCR0_EL1", REG_DBGBCR0_EL1, 0x1000a0, SR_READ | SR_WRITE},
{"DBGBCR1_EL1", REG_DBGBCR1_EL1, 0x1001a0, SR_READ | SR_WRITE},
{"DBGBCR2_EL1", REG_DBGBCR2_EL1, 0x1002a0, SR_READ | SR_WRITE},
{"DBGBCR3_EL1", REG_DBGBCR3_EL1, 0x1003a0, SR_READ | SR_WRITE},
{"DBGBCR4_EL1", REG_DBGBCR4_EL1, 0x1004a0, SR_READ | SR_WRITE},
{"DBGBCR5_EL1", REG_DBGBCR5_EL1, 0x1005a0, SR_READ | SR_WRITE},
{"DBGBCR6_EL1", REG_DBGBCR6_EL1, 0x1006a0, SR_READ | SR_WRITE},
{"DBGBCR7_EL1", REG_DBGBCR7_EL1, 0x1007a0, SR_READ | SR_WRITE},
{"DBGBCR8_EL1", REG_DBGBCR8_EL1, 0x1008a0, SR_READ | SR_WRITE},
{"DBGBCR9_EL1", REG_DBGBCR9_EL1, 0x1009a0, SR_READ | SR_WRITE},
{"DBGBCR10_EL1", REG_DBGBCR10_EL1, 0x100aa0, SR_READ | SR_WRITE},
{"DBGBCR11_EL1", REG_DBGBCR11_EL1, 0x100ba0, SR_READ | SR_WRITE},
{"DBGBCR12_EL1", REG_DBGBCR12_EL1, 0x100ca0, SR_READ | SR_WRITE},
{"DBGBCR13_EL1", REG_DBGBCR13_EL1, 0x100da0, SR_READ | SR_WRITE},
{"DBGBCR14_EL1", REG_DBGBCR14_EL1, 0x100ea0, SR_READ | SR_WRITE},
{"DBGBCR15_EL1", REG_DBGBCR15_EL1, 0x100fa0, SR_READ | SR_WRITE},
{"DBGBVR0_EL1", REG_DBGBVR0_EL1, 0x100080, SR_READ | SR_WRITE},
{"DBGBVR1_EL1", REG_DBGBVR1_EL1, 0x100180, SR_READ | SR_WRITE},
{"DBGBVR2_EL1", REG_DBGBVR2_EL1, 0x100280, SR_READ | SR_WRITE},
{"DBGBVR3_EL1", REG_DBGBVR3_EL1, 0x100380, SR_READ | SR_WRITE},
{"DBGBVR4_EL1", REG_DBGBVR4_EL1, 0x100480, SR_READ | SR_WRITE},
{"DBGBVR5_EL1", REG_DBGBVR5_EL1, 0x100580, SR_READ | SR_WRITE},
{"DBGBVR6_EL1", REG_DBGBVR6_EL1, 0x100680, SR_READ | SR_WRITE},
{"DBGBVR7_EL1", REG_DBGBVR7_EL1, 0x100780, SR_READ | SR_WRITE},
{"DBGBVR8_EL1", REG_DBGBVR8_EL1, 0x100880, SR_READ | SR_WRITE},
{"DBGBVR9_EL1", REG_DBGBVR9_EL1, 0x100980, SR_READ | SR_WRITE},
{"DBGBVR10_EL1", REG_DBGBVR10_EL1, 0x100a80, SR_READ | SR_WRITE},
{"DBGBVR11_EL1", REG_DBGBVR11_EL1, 0x100b80, SR_READ | SR_WRITE},
{"DBGBVR12_EL1", REG_DBGBVR12_EL1, 0x100c80, SR_READ | SR_WRITE},
{"DBGBVR13_EL1", REG_DBGBVR13_EL1, 0x100d80, SR_READ | SR_WRITE},
{"DBGBVR14_EL1", REG_DBGBVR14_EL1, 0x100e80, SR_READ | SR_WRITE},
{"DBGBVR15_EL1", REG_DBGBVR15_EL1, 0x100f80, SR_READ | SR_WRITE},
{"DBGCLAIMCLR_EL1", REG_DBGCLAIMCLR_EL1, 0x1079c0, SR_READ | SR_WRITE},
{"DBGCLAIMSET_EL1", REG_DBGCLAIMSET_EL1, 0x1078c0, SR_READ | SR_WRITE},
{"DBGDTR_EL0", REG_DBGDTR_EL0, 0x130400, SR_READ | SR_WRITE},
{"DBGDTRRX_EL0", REG_DBGDTRRX_EL0, 0x130500, SR_READ},
{"DBGDTRTX_EL0", REG_DBGDTRTX_EL0, 0x130500, SR_WRITE},
{"DBGPRCR_EL1", REG_DBGPRCR_EL1, 0x101480, SR_READ | SR_WRITE},
{"DBGWCR0_EL1", REG_DBGWCR0_EL1, 0x1000e0, SR_READ | SR_WRITE},
{"DBGWCR1_EL1", REG_DBGWCR1_EL1, 0x1001e0, SR_READ | SR_WRITE},
{"DBGWCR2_EL1", REG_DBGWCR2_EL1, 0x1002e0, SR_READ | SR_WRITE},
{"DBGWCR3_EL1", REG_DBGWCR3_EL1, 0x1003e0, SR_READ | SR_WRITE},
{"DBGWCR4_EL1", REG_DBGWCR4_EL1, 0x1004e0, SR_READ | SR_WRITE},
{"DBGWCR5_EL1", REG_DBGWCR5_EL1, 0x1005e0, SR_READ | SR_WRITE},
{"DBGWCR6_EL1", REG_DBGWCR6_EL1, 0x1006e0, SR_READ | SR_WRITE},
{"DBGWCR7_EL1", REG_DBGWCR7_EL1, 0x1007e0, SR_READ | SR_WRITE},
{"DBGWCR8_EL1", REG_DBGWCR8_EL1, 0x1008e0, SR_READ | SR_WRITE},
{"DBGWCR9_EL1", REG_DBGWCR9_EL1, 0x1009e0, SR_READ | SR_WRITE},
{"DBGWCR10_EL1", REG_DBGWCR10_EL1, 0x100ae0, SR_READ | SR_WRITE},
{"DBGWCR11_EL1", REG_DBGWCR11_EL1, 0x100be0, SR_READ | SR_WRITE},
{"DBGWCR12_EL1", REG_DBGWCR12_EL1, 0x100ce0, SR_READ | SR_WRITE},
{"DBGWCR13_EL1", REG_DBGWCR13_EL1, 0x100de0, SR_READ | SR_WRITE},
{"DBGWCR14_EL1", REG_DBGWCR14_EL1, 0x100ee0, SR_READ | SR_WRITE},
{"DBGWCR15_EL1", REG_DBGWCR15_EL1, 0x100fe0, SR_READ | SR_WRITE},
{"DBGWVR0_EL1", REG_DBGWVR0_EL1, 0x1000c0, SR_READ | SR_WRITE},
{"DBGWVR1_EL1", REG_DBGWVR1_EL1, 0x1001c0, SR_READ | SR_WRITE},
{"DBGWVR2_EL1", REG_DBGWVR2_EL1, 0x1002c0, SR_READ | SR_WRITE},
{"DBGWVR3_EL1", REG_DBGWVR3_EL1, 0x1003c0, SR_READ | SR_WRITE},
{"DBGWVR4_EL1", REG_DBGWVR4_EL1, 0x1004c0, SR_READ | SR_WRITE},
{"DBGWVR5_EL1", REG_DBGWVR5_EL1, 0x1005c0, SR_READ | SR_WRITE},
{"DBGWVR6_EL1", REG_DBGWVR6_EL1, 0x1006c0, SR_READ | SR_WRITE},
{"DBGWVR7_EL1", REG_DBGWVR7_EL1, 0x1007c0, SR_READ | SR_WRITE},
{"DBGWVR8_EL1", REG_DBGWVR8_EL1, 0x1008c0, SR_READ | SR_WRITE},
{"DBGWVR9_EL1", REG_DBGWVR9_EL1, 0x1009c0, SR_READ | SR_WRITE},
{"DBGWVR10_EL1", REG_DBGWVR10_EL1, 0x100ac0, SR_READ | SR_WRITE},
{"DBGWVR11_EL1", REG_DBGWVR11_EL1, 0x100bc0, SR_READ | SR_WRITE},
{"DBGWVR12_EL1", REG_DBGWVR12_EL1, 0x100cc0, SR_READ | SR_WRITE},
{"DBGWVR13_EL1", REG_DBGWVR13_EL1, 0x100dc0, SR_READ | SR_WRITE},
{"DBGWVR14_EL1", REG_DBGWVR14_EL1, 0x100ec0, SR_READ | SR_WRITE},
{"DBGWVR15_EL1", REG_DBGWVR15_EL1, 0x100fc0, SR_READ | SR_WRITE},
{"DCZID_EL0", REG_DCZID_EL0, 0x1b00e0, SR_READ},
{"DISR_EL1", REG_DISR_EL1, 0x18c120, SR_READ | SR_WRITE},
{"DIT", REG_DIT, 0x1b42a0, SR_READ | SR_WRITE},
{"DLR_EL0", REG_DLR_EL0, 0x1b4520, SR_READ | SR_WRITE},
{"DSPSR_EL0", REG_DSPSR_EL0, 0x1b4500, SR_READ | SR_WRITE},
{"ELR_EL1", REG_ELR_EL1, 0x184020, SR_READ | SR_WRITE},
{"ERRIDR_EL1", REG_ERRIDR_EL1, 0x185300, SR_READ},
{"ERRSELR_EL1", REG_ERRSELR_EL1, 0x185320, SR_READ | SR_WRITE},
{"ERXADDR_EL1", REG_ERXADDR_EL1, 0x185460, SR_READ | SR_WRITE},
{"ERXCTLR_EL1", REG_ERXCTLR_EL1, 0x185420, SR_READ | SR_WRITE},
{"ERXFR_EL1", REG_ERXFR_EL1, 0x185400, SR_READ},
{"ERXMISC0_EL1", REG_ERXMISC0_EL1, 0x185500, SR_READ | SR_WRITE},
{"ERXMISC1_EL1", REG_ERXMISC1_EL1, 0x185520, SR_READ | SR_WRITE},
{"ERXMISC2_EL1", REG_ERXMISC2_EL1, 0x185540, SR_READ | SR_WRITE},
{"ERXMISC3_EL1", REG_ERXMISC3_EL1, 0x185560, SR_READ | SR_WRITE},
{"ERXPFGCDN_EL1", REG_ERXPFGCDN_EL1, 0x1854c0, SR_READ | SR_WRITE},
{"ERXPFGCTL_EL1", REG_ERXPFGCTL_EL1, 0x1854a0, SR_READ | SR_WRITE},
{"ERXPFGF_EL1", REG_ERXPFGF_EL1, 0x185480, SR_READ},
{"ERXSTATUS_EL1", REG_ERXSTATUS_EL1, 0x185440, SR_READ | SR_WRITE},
{"ESR_EL1", REG_ESR_EL1, 0x185200, SR_READ | SR_WRITE},
{"FAR_EL1", REG_FAR_EL1, 0x186000, SR_READ | SR_WRITE},
{"FPCR", REG_FPCR, 0x1b4400, SR_READ | SR_WRITE},
{"FPSR", REG_FPSR, 0x1b4420, SR_READ | SR_WRITE},
{"GCR_EL1", REG_GCR_EL1, 0x1810c0, SR_READ | SR_WRITE},
{"GMID_EL1", REG_GMID_EL1, 0x31400, SR_READ},
{"ICC_AP0R0_EL1", REG_ICC_AP0R0_EL1, 0x18c880, SR_READ | SR_WRITE},
{"ICC_AP0R1_EL1", REG_ICC_AP0R1_EL1, 0x18c8a0, SR_READ | SR_WRITE},
{"ICC_AP0R2_EL1", REG_ICC_AP0R2_EL1, 0x18c8c0, SR_READ | SR_WRITE},
{"ICC_AP0R3_EL1", REG_ICC_AP0R3_EL1, 0x18c8e0, SR_READ | SR_WRITE},
{"ICC_AP1R0_EL1", REG_ICC_AP1R0_EL1, 0x18c900, SR_READ | SR_WRITE},
{"ICC_AP1R1_EL1", REG_ICC_AP1R1_EL1, 0x18c920, SR_READ | SR_WRITE},
{"ICC_AP1R2_EL1", REG_ICC_AP1R2_EL1, 0x18c940, SR_READ | SR_WRITE},
{"ICC_AP1R3_EL1", REG_ICC_AP1R3_EL1, 0x18c960, SR_READ | SR_WRITE},
{"ICC_ASGI1R_EL1", REG_ICC_ASGI1R_EL1, 0x18cbc0, SR_WRITE},
{"ICC_BPR0_EL1", REG_ICC_BPR0_EL1, 0x18c860, SR_READ | SR_WRITE},
{"ICC_BPR1_EL1", REG_ICC_BPR1_EL1, 0x18cc60, SR_READ | SR_WRITE},
{"ICC_CTLR_EL1", REG_ICC_CTLR_EL1, 0x18cc80, SR_READ | SR_WRITE},
{"ICC_DIR_EL1", REG_ICC_DIR_EL1, 0x18cb20, SR_WRITE},
{"ICC_EOIR0_EL1", REG_ICC_EOIR0_EL1, 0x18c820, SR_WRITE},
{"ICC_EOIR1_EL1", REG_ICC_EOIR1_EL1, 0x18cc20, SR_WRITE},
{"ICC_HPPIR0_EL1", REG_ICC_HPPIR0_EL1, 0x18c840, SR_READ},
{"ICC_HPPIR1_EL1", REG_ICC_HPPIR1_EL1, 0x18cc40, SR_READ},
{"ICC_IAR0_EL1", REG_ICC_IAR0_EL1, 0x18c800, SR_READ},
{"ICC_IAR1_EL1", REG_ICC_IAR1_EL1, 0x18cc00, SR_READ},
{"ICC_IGRPEN0_EL1", REG_ICC_IGRPEN0_EL1, 0x18ccc0, SR_READ | SR_WRITE},
{"ICC_IGRPEN1_EL1", REG_ICC_IGRPEN1_EL1, 0x18cce0, SR_READ | SR_WRITE},
{"ICC_PMR_EL1", REG_ICC_PMR_EL1, 0x184600, SR_READ | SR_WRITE},
{"ICC_RPR_EL1", REG_ICC_RPR_EL1, 0x18cb60, SR_READ},
{"ICC_SGI0R_EL1", REG_ICC_SGI0R_EL1, 0x18cbe0, SR_WRITE},
{"ICC_SGI1R_EL1", REG_ICC_SGI1R_EL1, 0x18cba0, SR_WRITE},
{"ICC_SRE_EL1", REG_ICC_SRE_EL1, 0x18cca0, SR_READ | SR_WRITE},
{"ICV_AP0R0_EL1", REG_ICV_AP0R0_EL1, 0x18c880, SR_READ | SR_WRITE},
{"ICV_AP0R1_EL1", REG_ICV_AP0R1_EL1, 0x18c8a0, SR_READ | SR_WRITE},
{"ICV_AP0R2_EL1", REG_ICV_AP0R2_EL1, 0x18c8c0, SR_READ | SR_WRITE},
{"ICV_AP0R3_EL1", REG_ICV_AP0R3_EL1, 0x18c8e0, SR_READ | SR_WRITE},
{"ICV_AP1R0_EL1", REG_ICV_AP1R0_EL1, 0x18c900, SR_READ | SR_WRITE},
{"ICV_AP1R1_EL1", REG_ICV_AP1R1_EL1, 0x18c920, SR_READ | SR_WRITE},
{"ICV_AP1R2_EL1", REG_ICV_AP1R2_EL1, 0x18c940, SR_READ | SR_WRITE},
{"ICV_AP1R3_EL1", REG_ICV_AP1R3_EL1, 0x18c960, SR_READ | SR_WRITE},
{"ICV_BPR0_EL1", REG_ICV_BPR0_EL1, 0x18c860, SR_READ | SR_WRITE},
{"ICV_BPR1_EL1", REG_ICV_BPR1_EL1, 0x18cc60, SR_READ | SR_WRITE},
{"ICV_CTLR_EL1", REG_ICV_CTLR_EL1, 0x18cc80, SR_READ | SR_WRITE},
{"ICV_DIR_EL1", REG_ICV_DIR_EL1, 0x18cb20, SR_WRITE},
{"ICV_EOIR0_EL1", REG_ICV_EOIR0_EL1, 0x18c820, SR_WRITE},
{"ICV_EOIR1_EL1", REG_ICV_EOIR1_EL1, 0x18cc20, SR_WRITE},
{"ICV_HPPIR0_EL1", REG_ICV_HPPIR0_EL1, 0x18c840, SR_READ},
{"ICV_HPPIR1_EL1", REG_ICV_HPPIR1_EL1, 0x18cc40, SR_READ},
{"ICV_IAR0_EL1", REG_ICV_IAR0_EL1, 0x18c800, SR_READ},
{"ICV_IAR1_EL1", REG_ICV_IAR1_EL1, 0x18cc00, SR_READ},
{"ICV_IGRPEN0_EL1", REG_ICV_IGRPEN0_EL1, 0x18ccc0, SR_READ | SR_WRITE},
{"ICV_IGRPEN1_EL1", REG_ICV_IGRPEN1_EL1, 0x18cce0, SR_READ | SR_WRITE},
{"ICV_PMR_EL1", REG_ICV_PMR_EL1, 0x184600, SR_READ | SR_WRITE},
{"ICV_RPR_EL1", REG_ICV_RPR_EL1, 0x18cb60, SR_READ},
{"ID_AA64AFR0_EL1", REG_ID_AA64AFR0_EL1, 0x180580, SR_READ},
{"ID_AA64AFR1_EL1", REG_ID_AA64AFR1_EL1, 0x1805a0, SR_READ},
{"ID_AA64DFR0_EL1", REG_ID_AA64DFR0_EL1, 0x180500, SR_READ},
{"ID_AA64DFR1_EL1", REG_ID_AA64DFR1_EL1, 0x180520, SR_READ},
{"ID_AA64ISAR0_EL1", REG_ID_AA64ISAR0_EL1, 0x180600, SR_READ},
{"ID_AA64ISAR1_EL1", REG_ID_AA64ISAR1_EL1, 0x180620, SR_READ},
{"ID_AA64MMFR0_EL1", REG_ID_AA64MMFR0_EL1, 0x180700, SR_READ},
{"ID_AA64MMFR1_EL1", REG_ID_AA64MMFR1_EL1, 0x180720, SR_READ},
{"ID_AA64MMFR2_EL1", REG_ID_AA64MMFR2_EL1, 0x180740, SR_READ},
{"ID_AA64PFR0_EL1", REG_ID_AA64PFR0_EL1, 0x180400, SR_READ},
{"ID_AA64PFR1_EL1", REG_ID_AA64PFR1_EL1, 0x180420, SR_READ},
{"ID_AA64ZFR0_EL1", REG_ID_AA64ZFR0_EL1, 0x180480, SR_READ},
{"ID_AFR0_EL1", REG_ID_AFR0_EL1, 0x180160, SR_READ},
{"ID_DFR0_EL1", REG_ID_DFR0_EL1, 0x180140, SR_READ},
{"ID_ISAR0_EL1", REG_ID_ISAR0_EL1, 0x180200, SR_READ},
{"ID_ISAR1_EL1", REG_ID_ISAR1_EL1, 0x180220, SR_READ},
{"ID_ISAR2_EL1", REG_ID_ISAR2_EL1, 0x180240, SR_READ},
{"ID_ISAR3_EL1", REG_ID_ISAR3_EL1, 0x180260, SR_READ},
{"ID_ISAR4_EL1", REG_ID_ISAR4_EL1, 0x180280, SR_READ},
{"ID_ISAR5_EL1", REG_ID_ISAR5_EL1, 0x1802a0, SR_READ},
{"ID_ISAR6_EL1", REG_ID_ISAR6_EL1, 0x1802e0, SR_READ},
{"ID_MMFR0_EL1", REG_ID_MMFR0_EL1, 0x180180, SR_READ},
{"ID_MMFR1_EL1", REG_ID_MMFR1_EL1, 0x1801a0, SR_READ},
{"ID_MMFR2_EL1", REG_ID_MMFR2_EL1, 0x1801c0, SR_READ},
{"ID_MMFR3_EL1", REG_ID_MMFR3_EL1, 0x1801e0, SR_READ},
{"ID_MMFR4_EL1", REG_ID_MMFR4_EL1, 0x1802c0, SR_READ},
{"ID_PFR0_EL1", REG_ID_PFR0_EL1, 0x180100, SR_READ},
{"ID_PFR1_EL1", REG_ID_PFR1_EL1, 0x180120, SR_READ},
{"ID_PFR2_EL1", REG_ID_PFR2_EL1, 0x180380, SR_READ},
{"ISR_EL1", REG_ISR_EL1, 0x18c100, SR_READ},
{"LORC_EL1", REG_LORC_EL1, 0x18a460, SR_READ | SR_WRITE},
{"LOREA_EL1", REG_LOREA_EL1, 0x18a420, SR_READ | SR_WRITE},
{"LORID_EL1", REG_LORID_EL1, 0x18a4e0, SR_READ},
{"LORN_EL1", REG_LORN_EL1, 0x18a440, SR_READ | SR_WRITE},
{"LORSA_EL1", REG_LORSA_EL1, 0x18a400, SR_READ | SR_WRITE},
{"MAIR_EL1", REG_MAIR_EL1, 0x18a200, SR_READ | SR_WRITE},
{"MDCCINT_EL1", REG_MDCCINT_EL1, 0x100200, SR_READ | SR_WRITE},
{"MDCCSR_EL0", REG_MDCCSR_EL0, 0x130100, SR_READ},
{"MDRAR_EL1", REG_MDRAR_EL1, 0x101000, SR_READ},
{"MDSCR_EL1", REG_MDSCR_EL1, 0x100240, SR_READ | SR_WRITE},
{"MIDR_EL1", REG_MIDR_EL1, 0x180000, SR_READ},
{"MPAM0_EL1", REG_MPAM0_EL1, 0x18a520, SR_READ | SR_WRITE},
{"MPAM1_EL1", REG_MPAM1_EL1, 0x18a500, SR_READ | SR_WRITE},
{"MPAMIDR_EL1", REG_MPAMIDR_EL1, 0x18a480, SR_READ},
{"MPIDR_EL1", REG_MPIDR_EL1, 0x1800a0, SR_READ},
{"MVFR0_EL1", REG_MVFR0_EL1, 0x180300, SR_READ},
{"MVFR1_EL1", REG_MVFR1_EL1, 0x180320, SR_READ},
{"MVFR2_EL1", REG_MVFR2_EL1, 0x180340, SR_READ},
{"NZCV", REG_NZCV, 0x1b4200, SR_READ | SR_WRITE},
{"OSDLR_EL1", REG_OSDLR_EL1, 0x101380, SR_READ | SR_WRITE},
{"OSDTRRX_EL1", REG_OSDTRRX_EL1, 0x100040, SR_READ | SR_WRITE},
{"OSDTRTX_EL1", REG_OSDTRTX_EL1, 0x100340, SR_READ | SR_WRITE},
{"OSECCR_EL1", REG_OSECCR_EL1, 0x100640, SR_READ | SR_WRITE},
{"OSLAR_EL1", REG_OSLAR_EL1, 0x101080, SR_WRITE},
{"OSLSR_EL1", REG_OSLSR_EL1, 0x101180, SR_READ},
{"PAN", REG_PAN, 0x184260, SR_READ | SR_WRITE},
{"PAR_EL1", REG_PAR_EL1, 0x187400, SR_READ | SR_WRITE},
{"PMBIDR_EL1", REG_PMBIDR_EL1, 0x189ae0, SR_READ},
{"PMBLIMITR_EL1", REG_PMBLIMITR_EL1, 0x189a00, SR_READ | SR_WRITE},
{"PMBPTR_EL1", REG_PMBPTR_EL1, 0x189a20, SR_READ | SR_WRITE},
{"PMBSR_EL1", REG_PMBSR_EL1, 0x189a60, SR_READ | SR_WRITE},
{"PMCCFILTR_EL0", REG_PMCCFILTR_EL0, 0x1befe0, SR_READ | SR_WRITE},
{"PMCCNTR_EL0", REG_PMCCNTR_EL0, 0x1b9d00, SR_READ | SR_WRITE},
{"PMCEID0_EL0", REG_PMCEID0_EL0, 0x1b9cc0, SR_READ},
{"PMCEID1_EL0", REG_PMCEID1_EL0, 0x1b9ce0, SR_READ},
{"PMCNTENCLR_EL0", REG_PMCNTENCLR_EL0, 0x1b9c40, SR_READ | SR_WRITE},
{"PMCNTENSET_EL0", REG_PMCNTENSET_EL0, 0x1b9c20, SR_READ | SR_WRITE},
{"PMCR_EL0", REG_PMCR_EL0, 0x1b9c00, SR_READ | SR_WRITE},
{"PMEVCNTR0_EL0", REG_PMEVCNTR0_EL0, 0x1be800, SR_READ | SR_WRITE},
{"PMEVCNTR1_EL0", REG_PMEVCNTR1_EL0, 0x1be820, SR_READ | SR_WRITE},
{"PMEVCNTR2_EL0", REG_PMEVCNTR2_EL0, 0x1be840, SR_READ | SR_WRITE},
{"PMEVCNTR3_EL0", REG_PMEVCNTR3_EL0, 0x1be860, SR_READ | SR_WRITE},
{"PMEVCNTR4_EL0", REG_PMEVCNTR4_EL0, 0x1be880, SR_READ | SR_WRITE},
{"PMEVCNTR5_EL0", REG_PMEVCNTR5_EL0, 0x1be8a0, SR_READ | SR_WRITE},
{"PMEVCNTR6_EL0", REG_PMEVCNTR6_EL0, 0x1be8c0, SR_READ | SR_WRITE},
{"PMEVCNTR7_EL0", REG_PMEVCNTR7_EL0, 0x1be8e0, SR_READ | SR_WRITE},
{"PMEVCNTR8_EL0", REG_PMEVCNTR8_EL0, 0x1be900, SR_READ | SR_WRITE},
{"PMEVCNTR9_EL0", REG_PMEVCNTR9_EL0, 0x1be920, SR_READ | SR_WRITE},
{"PMEVCNTR10_EL0", REG_PMEVCNTR10_EL0, 0x1be940, SR_READ | SR_WRITE},
{"PMEVCNTR11_EL0", REG_PMEVCNTR11_EL0, 0x1be960, SR_READ | SR_WRITE},
{"PMEVCNTR12_EL0", REG_PMEVCNTR12_EL0, 0x1be980, SR_READ | SR_WRITE},
{"PMEVCNTR13_EL0", REG_PMEVCNTR13_EL0, 0x1be9a0, SR_READ | SR_WRITE},
{"PMEVCNTR14_EL0", REG_PMEVCNTR14_EL0, 0x1be9c0, SR_READ | SR_WRITE},
{"PMEVCNTR15_EL0", REG_PMEVCNTR15_EL0, 0x1be9e0, SR_READ | SR_WRITE},
{"PMEVCNTR16_EL0", REG_PMEVCNTR16_EL0, 0x1bea00, SR_READ | SR_WRITE},
{"PMEVCNTR17_EL0", REG_PMEVCNTR17_EL0, 0x1bea20, SR_READ | SR_WRITE},
{"PMEVCNTR18_EL0", REG_PMEVCNTR18_EL0, 0x1bea40, SR_READ | SR_WRITE},
{"PMEVCNTR19_EL0", REG_PMEVCNTR19_EL0, 0x1bea60, SR_READ | SR_WRITE},
{"PMEVCNTR20_EL0", REG_PMEVCNTR20_EL0, 0x1bea80, SR_READ | SR_WRITE},
{"PMEVCNTR21_EL0", REG_PMEVCNTR21_EL0, 0x1beaa0, SR_READ | SR_WRITE},
{"PMEVCNTR22_EL0", REG_PMEVCNTR22_EL0, 0x1beac0, SR_READ | SR_WRITE},
{"PMEVCNTR23_EL0", REG_PMEVCNTR23_EL0, 0x1beae0, SR_READ | SR_WRITE},
{"PMEVCNTR24_EL0", REG_PMEVCNTR24_EL0, 0x1beb00, SR_READ | SR_WRITE},
{"PMEVCNTR25_EL0", REG_PMEVCNTR25_EL0, 0x1beb20, SR_READ | SR_WRITE},
{"PMEVCNTR26_EL0", REG_PMEVCNTR26_EL0, 0x1beb40, SR_READ | SR_WRITE},
{"PMEVCNTR27_EL0", REG_PMEVCNTR27_EL0, 0x1beb60, SR_READ | SR_WRITE},
{"PMEVCNTR28_EL0", REG_PMEVCNTR28_EL0, 0x1beb80, SR_READ | SR_WRITE},
{"PMEVCNTR29_EL0", REG_PMEVCNTR29_EL0, 0x1beba0, SR_READ | SR_WRITE},
{"PMEVCNTR30_EL0", REG_PMEVCNTR30_EL0, 0x1bebc0, SR_READ | SR_WRITE},
{"PMEVTYPER0_EL0", REG_PMEVTYPER0_EL0, 0x1bec00, SR_READ | SR_WRITE},
{"PMEVTYPER1_EL0", REG_PMEVTYPER1_EL0, 0x1bec20, SR_READ | SR_WRITE},
{"PMEVTYPER2_EL0", REG_PMEVTYPER2_EL0, 0x1bec40, SR_READ | SR_WRITE},
{"PMEVTYPER3_EL0", REG_PMEVTYPER3_EL0, 0x1bec60, SR_READ | SR_WRITE},
{"PMEVTYPER4_EL0", REG_PMEVTYPER4_EL0, 0x1bec80, SR_READ | SR_WRITE},
{"PMEVTYPER5_EL0", REG_PMEVTYPER5_EL0, 0x1beca0, SR_READ | SR_WRITE},
{"PMEVTYPER6_EL0", REG_PMEVTYPER6_EL0, 0x1becc0, SR_READ | SR_WRITE},
{"PMEVTYPER7_EL0", REG_PMEVTYPER7_EL0, 0x1bece0, SR_READ | SR_WRITE},
{"PMEVTYPER8_EL0", REG_PMEVTYPER8_EL0, 0x1bed00, SR_READ | SR_WRITE},
{"PMEVTYPER9_EL0", REG_PMEVTYPER9_EL0, 0x1bed20, SR_READ | SR_WRITE},
{"PMEVTYPER10_EL0", REG_PMEVTYPER10_EL0, 0x1bed40, SR_READ | SR_WRITE},
{"PMEVTYPER11_EL0", REG_PMEVTYPER11_EL0, 0x1bed60, SR_READ | SR_WRITE},
{"PMEVTYPER12_EL0", REG_PMEVTYPER12_EL0, 0x1bed80, SR_READ | SR_WRITE},
{"PMEVTYPER13_EL0", REG_PMEVTYPER13_EL0, 0x1beda0, SR_READ | SR_WRITE},
{"PMEVTYPER14_EL0", REG_PMEVTYPER14_EL0, 0x1bedc0, SR_READ | SR_WRITE},
{"PMEVTYPER15_EL0", REG_PMEVTYPER15_EL0, 0x1bede0, SR_READ | SR_WRITE},
{"PMEVTYPER16_EL0", REG_PMEVTYPER16_EL0, 0x1bee00, SR_READ | SR_WRITE},
{"PMEVTYPER17_EL0", REG_PMEVTYPER17_EL0, 0x1bee20, SR_READ | SR_WRITE},
{"PMEVTYPER18_EL0", REG_PMEVTYPER18_EL0, 0x1bee40, SR_READ | SR_WRITE},
{"PMEVTYPER19_EL0", REG_PMEVTYPER19_EL0, 0x1bee60, SR_READ | SR_WRITE},
{"PMEVTYPER20_EL0", REG_PMEVTYPER20_EL0, 0x1bee80, SR_READ | SR_WRITE},
{"PMEVTYPER21_EL0", REG_PMEVTYPER21_EL0, 0x1beea0, SR_READ | SR_WRITE},
{"PMEVTYPER22_EL0", REG_PMEVTYPER22_EL0, 0x1beec0, SR_READ | SR_WRITE},
{"PMEVTYPER23_EL0", REG_PMEVTYPER23_EL0, 0x1beee0, SR_READ | SR_WRITE},
{"PMEVTYPER24_EL0", REG_PMEVTYPER24_EL0, 0x1bef00, SR_READ | SR_WRITE},
{"PMEVTYPER25_EL0", REG_PMEVTYPER25_EL0, 0x1bef20, SR_READ | SR_WRITE},
{"PMEVTYPER26_EL0", REG_PMEVTYPER26_EL0, 0x1bef40, SR_READ | SR_WRITE},
{"PMEVTYPER27_EL0", REG_PMEVTYPER27_EL0, 0x1bef60, SR_READ | SR_WRITE},
{"PMEVTYPER28_EL0", REG_PMEVTYPER28_EL0, 0x1bef80, SR_READ | SR_WRITE},
{"PMEVTYPER29_EL0", REG_PMEVTYPER29_EL0, 0x1befa0, SR_READ | SR_WRITE},
{"PMEVTYPER30_EL0", REG_PMEVTYPER30_EL0, 0x1befc0, SR_READ | SR_WRITE},
{"PMINTENCLR_EL1", REG_PMINTENCLR_EL1, 0x189e40, SR_READ | SR_WRITE},
{"PMINTENSET_EL1", REG_PMINTENSET_EL1, 0x189e20, SR_READ | SR_WRITE},
{"PMMIR_EL1", REG_PMMIR_EL1, 0x189ec0, SR_READ},
{"PMOVSCLR_EL0", REG_PMOVSCLR_EL0, 0x1b9c60, SR_READ | SR_WRITE},
{"PMOVSSET_EL0", REG_PMOVSSET_EL0, 0x1b9e60, SR_READ | SR_WRITE},
{"PMSCR_EL1", REG_PMSCR_EL1, 0x189900, SR_READ | SR_WRITE},
{"PMSELR_EL0", REG_PMSELR_EL0, 0x1b9ca0, SR_READ | SR_WRITE},
{"PMSEVFR_EL1", REG_PMSEVFR_EL1, 0x1899a0, SR_READ | SR_WRITE},
{"PMSFCR_EL1", REG_PMSFCR_EL1, 0x189980, SR_READ | SR_WRITE},
{"PMSICR_EL1", REG_PMSICR_EL1, 0x189940, SR_READ | SR_WRITE},
{"PMSIDR_EL1", REG_PMSIDR_EL1, 0x1899e0, SR_READ},
{"PMSIRR_EL1", REG_PMSIRR_EL1, 0x189960, SR_READ | SR_WRITE},
{"PMSLATFR_EL1", REG_PMSLATFR_EL1, 0x1899c0, SR_READ | SR_WRITE},
{"PMSWINC_EL0", REG_PMSWINC_EL0, 0x1b9c80, SR_WRITE},
{"PMUSERENR_EL0", REG_PMUSERENR_EL0, 0x1b9e00, SR_READ | SR_WRITE},
{"PMXEVCNTR_EL0", REG_PMXEVCNTR_EL0, 0x1b9d40, SR_READ | SR_WRITE},
{"PMXEVTYPER_EL0", REG_PMXEVTYPER_EL0, 0x1b9d20, SR_READ | SR_WRITE},
{"REVIDR_EL1", REG_REVIDR_EL1, 0x1800c0, SR_READ},
{"RGSR_EL1", REG_RGSR_EL1, 0x1810a0, SR_READ | SR_WRITE},
{"RMR_EL1", REG_RMR_EL1, 0x18c040, SR_READ | SR_WRITE},
{"RNDR", REG_RNDR, 0x1b2400, SR_READ},
{"RNDRRS", REG_RNDRRS, 0x1b2420, SR_READ},
{"RVBAR_EL1", REG_RVBAR_EL1, 0x18c020, SR_READ},
{"SCTLR_EL1", REG_SCTLR_EL1, 0x181000, SR_READ | SR_WRITE},
{"SCXTNUM_EL0", REG_SCXTNUM_EL0, 0x1bd0e0, SR_READ | SR_WRITE},
{"SCXTNUM_EL1", REG_SCXTNUM_EL1, 0x18d0e0, SR_READ | SR_WRITE},
{"SP_EL0", REG_SP_EL0, 0x184100, SR_READ | SR_WRITE},
{"SP_EL1", REG_SP_EL1, 0x1c4100, SR_READ | SR_WRITE},
{"SPSel", REG_SPSel, 0x184200, SR_READ | SR_WRITE},
{"SPSR_abt", REG_SPSR_abt, 0x1c4320, SR_READ | SR_WRITE},
{"SPSR_EL1", REG_SPSR_EL1, 0x184000, SR_READ | SR_WRITE},
{"SPSR_fiq", REG_SPSR_fiq, 0x1c4360, SR_READ | SR_WRITE},
{"SPSR_irq", REG_SPSR_irq, 0x1c4300, SR_READ | SR_WRITE},
{"SPSR_und", REG_SPSR_und, 0x1c4340, SR_READ | SR_WRITE},
{"SSBS", REG_SSBS, 0x1b42c0, SR_READ | SR_WRITE},
{"TCO", REG_TCO, 0x1b42e0, SR_READ | SR_WRITE},
{"TCR_EL1", REG_TCR_EL1, 0x182040, SR_READ | SR_WRITE},
{"TFSR_EL1", REG_TFSR_EL1, 0x185600, SR_READ | SR_WRITE},
{"TFSRE0_EL1", REG_TFSRE0_EL1, 0x185620, SR_READ | SR_WRITE},
{"TPIDR_EL0", REG_TPIDR_EL0, 0x1bd040, SR_READ | SR_WRITE},
{"TPIDR_EL1", REG_TPIDR_EL1, 0x18d080, SR_READ | SR_WRITE},
{"TPIDRRO_EL0", REG_TPIDRRO_EL0, 0x1bd060, SR_READ | SR_WRITE},
{"TRFCR_EL1", REG_TRFCR_EL1, 0x181220, SR_READ | SR_WRITE},
{"TTBR0_EL1", REG_TTBR0_EL1, 0x182000, SR_READ | SR_WRITE},
{"TTBR1_EL1", REG_TTBR1_EL1, 0x182020, SR_READ | SR_WRITE},
{"UAO", REG_UAO, 0x184280, SR_READ | SR_WRITE},
{"VBAR_EL1", REG_VBAR_EL1, 0x18c000, SR_READ | SR_WRITE},
{"ZCR_EL1", REG_ZCR_EL1, 0x181200, SR_READ | SR_WRITE},
}
func SysRegEnc(r int16) (string, uint32, uint8) {
// The automatic generator guarantees that the order
// of Reg in SystemReg struct is consistent with the
// order of system register declarations
if r <= SYSREG_BEGIN || r >= SYSREG_END {
return "", 0, 0
}
v := SystemReg[r-SYSREG_BEGIN-1]
return v.Name, v.Enc, v.AccessFlags
}

View File

@ -0,0 +1,200 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package obj
import (
"github.com/twitchyliquid64/golang-asm/objabi"
"log"
"math"
)
// Grow increases the length of s.P to lsiz.
func (s *LSym) Grow(lsiz int64) {
siz := int(lsiz)
if int64(siz) != lsiz {
log.Fatalf("LSym.Grow size %d too long", lsiz)
}
if len(s.P) >= siz {
return
}
s.P = append(s.P, make([]byte, siz-len(s.P))...)
}
// GrowCap increases the capacity of s.P to c.
func (s *LSym) GrowCap(c int64) {
if int64(cap(s.P)) >= c {
return
}
if s.P == nil {
s.P = make([]byte, 0, c)
return
}
b := make([]byte, len(s.P), c)
copy(b, s.P)
s.P = b
}
// prepwrite prepares to write data of size siz into s at offset off.
func (s *LSym) prepwrite(ctxt *Link, off int64, siz int) {
if off < 0 || siz < 0 || off >= 1<<30 {
ctxt.Diag("prepwrite: bad off=%d siz=%d s=%v", off, siz, s)
}
switch s.Type {
case objabi.Sxxx, objabi.SBSS:
s.Type = objabi.SDATA
case objabi.SNOPTRBSS:
s.Type = objabi.SNOPTRDATA
case objabi.STLSBSS:
ctxt.Diag("cannot supply data for %v var %v", s.Type, s.Name)
}
l := off + int64(siz)
s.Grow(l)
if l > s.Size {
s.Size = l
}
}
// WriteFloat32 writes f into s at offset off.
func (s *LSym) WriteFloat32(ctxt *Link, off int64, f float32) {
s.prepwrite(ctxt, off, 4)
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], math.Float32bits(f))
}
// WriteFloat64 writes f into s at offset off.
func (s *LSym) WriteFloat64(ctxt *Link, off int64, f float64) {
s.prepwrite(ctxt, off, 8)
ctxt.Arch.ByteOrder.PutUint64(s.P[off:], math.Float64bits(f))
}
// WriteInt writes an integer i of size siz into s at offset off.
func (s *LSym) WriteInt(ctxt *Link, off int64, siz int, i int64) {
s.prepwrite(ctxt, off, siz)
switch siz {
default:
ctxt.Diag("WriteInt: bad integer size: %d", siz)
case 1:
s.P[off] = byte(i)
case 2:
ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i))
case 4:
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(i))
case 8:
ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(i))
}
}
func (s *LSym) writeAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64, rtype objabi.RelocType) {
// Allow 4-byte addresses for DWARF.
if siz != ctxt.Arch.PtrSize && siz != 4 {
ctxt.Diag("WriteAddr: bad address size %d in %s", siz, s.Name)
}
s.prepwrite(ctxt, off, siz)
r := Addrel(s)
r.Off = int32(off)
if int64(r.Off) != off {
ctxt.Diag("WriteAddr: off overflow %d in %s", off, s.Name)
}
r.Siz = uint8(siz)
r.Sym = rsym
r.Type = rtype
r.Add = roff
}
// WriteAddr writes an address of size siz into s at offset off.
// rsym and roff specify the relocation for the address.
func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) {
s.writeAddr(ctxt, off, siz, rsym, roff, objabi.R_ADDR)
}
// WriteCURelativeAddr writes a pointer-sized address into s at offset off.
// rsym and roff specify the relocation for the address which will be
// resolved by the linker to an offset from the DW_AT_low_pc attribute of
// the DWARF Compile Unit of rsym.
func (s *LSym) WriteCURelativeAddr(ctxt *Link, off int64, rsym *LSym, roff int64) {
s.writeAddr(ctxt, off, ctxt.Arch.PtrSize, rsym, roff, objabi.R_ADDRCUOFF)
}
// WriteOff writes a 4 byte offset to rsym+roff into s at offset off.
// After linking the 4 bytes stored at s+off will be
// rsym+roff-(start of section that s is in).
func (s *LSym) WriteOff(ctxt *Link, off int64, rsym *LSym, roff int64) {
s.prepwrite(ctxt, off, 4)
r := Addrel(s)
r.Off = int32(off)
if int64(r.Off) != off {
ctxt.Diag("WriteOff: off overflow %d in %s", off, s.Name)
}
r.Siz = 4
r.Sym = rsym
r.Type = objabi.R_ADDROFF
r.Add = roff
}
// WriteWeakOff writes a weak 4 byte offset to rsym+roff into s at offset off.
// After linking the 4 bytes stored at s+off will be
// rsym+roff-(start of section that s is in).
func (s *LSym) WriteWeakOff(ctxt *Link, off int64, rsym *LSym, roff int64) {
s.prepwrite(ctxt, off, 4)
r := Addrel(s)
r.Off = int32(off)
if int64(r.Off) != off {
ctxt.Diag("WriteOff: off overflow %d in %s", off, s.Name)
}
r.Siz = 4
r.Sym = rsym
r.Type = objabi.R_WEAKADDROFF
r.Add = roff
}
// WriteString writes a string of size siz into s at offset off.
func (s *LSym) WriteString(ctxt *Link, off int64, siz int, str string) {
if siz < len(str) {
ctxt.Diag("WriteString: bad string size: %d < %d", siz, len(str))
}
s.prepwrite(ctxt, off, siz)
copy(s.P[off:off+int64(siz)], str)
}
// WriteBytes writes a slice of bytes into s at offset off.
func (s *LSym) WriteBytes(ctxt *Link, off int64, b []byte) int64 {
s.prepwrite(ctxt, off, len(b))
copy(s.P[off:], b)
return off + int64(len(b))
}
func Addrel(s *LSym) *Reloc {
if s.R == nil {
s.R = make([]Reloc, 0, 4)
}
s.R = append(s.R, Reloc{})
return &s.R[len(s.R)-1]
}

View File

@ -0,0 +1,690 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Writes dwarf information to object files.
package obj
import (
"github.com/twitchyliquid64/golang-asm/dwarf"
"github.com/twitchyliquid64/golang-asm/objabi"
"github.com/twitchyliquid64/golang-asm/src"
"fmt"
"sort"
"sync"
)
// Generate a sequence of opcodes that is as short as possible.
// See section 6.2.5
const (
LINE_BASE = -4
LINE_RANGE = 10
PC_RANGE = (255 - OPCODE_BASE) / LINE_RANGE
OPCODE_BASE = 11
)
// generateDebugLinesSymbol fills the debug lines symbol of a given function.
//
// It's worth noting that this function doesn't generate the full debug_lines
// DWARF section, saving that for the linker. This function just generates the
// state machine part of debug_lines. The full table is generated by the
// linker. Also, we use the file numbers from the full package (not just the
// function in question) when generating the state machine. We do this so we
// don't have to do a fixup on the indices when writing the full section.
func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
dctxt := dwCtxt{ctxt}
// Emit a LNE_set_address extended opcode, so as to establish the
// starting text address of this function.
dctxt.AddUint8(lines, 0)
dwarf.Uleb128put(dctxt, lines, 1+int64(ctxt.Arch.PtrSize))
dctxt.AddUint8(lines, dwarf.DW_LNE_set_address)
dctxt.AddAddress(lines, s, 0)
// Set up the debug_lines state machine to the default values
// we expect at the start of a new sequence.
stmt := true
line := int64(1)
pc := s.Func.Text.Pc
var lastpc int64 // last PC written to line table, not last PC in func
name := ""
prologue, wrotePrologue := false, false
// Walk the progs, generating the DWARF table.
for p := s.Func.Text; p != nil; p = p.Link {
prologue = prologue || (p.Pos.Xlogue() == src.PosPrologueEnd)
// If we're not at a real instruction, keep looping!
if p.Pos.Line() == 0 || (p.Link != nil && p.Link.Pc == p.Pc) {
continue
}
newStmt := p.Pos.IsStmt() != src.PosNotStmt
newName, newLine := linkgetlineFromPos(ctxt, p.Pos)
// Output debug info.
wrote := false
if name != newName {
newFile := ctxt.PosTable.FileIndex(newName) + 1 // 1 indexing for the table.
dctxt.AddUint8(lines, dwarf.DW_LNS_set_file)
dwarf.Uleb128put(dctxt, lines, int64(newFile))
name = newName
wrote = true
}
if prologue && !wrotePrologue {
dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_set_prologue_end))
wrotePrologue = true
wrote = true
}
if stmt != newStmt {
dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_negate_stmt))
stmt = newStmt
wrote = true
}
if line != int64(newLine) || wrote {
pcdelta := p.Pc - pc
lastpc = p.Pc
putpclcdelta(ctxt, dctxt, lines, uint64(pcdelta), int64(newLine)-line)
line, pc = int64(newLine), p.Pc
}
}
// Because these symbols will be concatenated together by the
// linker, we need to reset the state machine that controls the
// debug symbols. Do this using an end-of-sequence operator.
//
// Note: at one point in time, Delve did not support multiple end
// sequence ops within a compilation unit (bug for this:
// https://github.com/go-delve/delve/issues/1694), however the bug
// has since been fixed (Oct 2019).
//
// Issue 38192: the DWARF standard specifies that when you issue
// an end-sequence op, the PC value should be one past the last
// text address in the translation unit, so apply a delta to the
// text address before the end sequence op. If this isn't done,
// GDB will assign a line number of zero the last row in the line
// table, which we don't want.
lastlen := uint64(s.Size - (lastpc - s.Func.Text.Pc))
putpclcdelta(ctxt, dctxt, lines, lastlen, 0)
dctxt.AddUint8(lines, 0) // start extended opcode
dwarf.Uleb128put(dctxt, lines, 1)
dctxt.AddUint8(lines, dwarf.DW_LNE_end_sequence)
}
func putpclcdelta(linkctxt *Link, dctxt dwCtxt, s *LSym, deltaPC uint64, deltaLC int64) {
// Choose a special opcode that minimizes the number of bytes needed to
// encode the remaining PC delta and LC delta.
var opcode int64
if deltaLC < LINE_BASE {
if deltaPC >= PC_RANGE {
opcode = OPCODE_BASE + (LINE_RANGE * PC_RANGE)
} else {
opcode = OPCODE_BASE + (LINE_RANGE * int64(deltaPC))
}
} else if deltaLC < LINE_BASE+LINE_RANGE {
if deltaPC >= PC_RANGE {
opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * PC_RANGE)
if opcode > 255 {
opcode -= LINE_RANGE
}
} else {
opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * int64(deltaPC))
}
} else {
if deltaPC <= PC_RANGE {
opcode = OPCODE_BASE + (LINE_RANGE - 1) + (LINE_RANGE * int64(deltaPC))
if opcode > 255 {
opcode = 255
}
} else {
// Use opcode 249 (pc+=23, lc+=5) or 255 (pc+=24, lc+=1).
//
// Let x=deltaPC-PC_RANGE. If we use opcode 255, x will be the remaining
// deltaPC that we need to encode separately before emitting 255. If we
// use opcode 249, we will need to encode x+1. If x+1 takes one more
// byte to encode than x, then we use opcode 255.
//
// In all other cases x and x+1 take the same number of bytes to encode,
// so we use opcode 249, which may save us a byte in encoding deltaLC,
// for similar reasons.
switch deltaPC - PC_RANGE {
// PC_RANGE is the largest deltaPC we can encode in one byte, using
// DW_LNS_const_add_pc.
//
// (1<<16)-1 is the largest deltaPC we can encode in three bytes, using
// DW_LNS_fixed_advance_pc.
//
// (1<<(7n))-1 is the largest deltaPC we can encode in n+1 bytes for
// n=1,3,4,5,..., using DW_LNS_advance_pc.
case PC_RANGE, (1 << 7) - 1, (1 << 16) - 1, (1 << 21) - 1, (1 << 28) - 1,
(1 << 35) - 1, (1 << 42) - 1, (1 << 49) - 1, (1 << 56) - 1, (1 << 63) - 1:
opcode = 255
default:
opcode = OPCODE_BASE + LINE_RANGE*PC_RANGE - 1 // 249
}
}
}
if opcode < OPCODE_BASE || opcode > 255 {
panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
}
// Subtract from deltaPC and deltaLC the amounts that the opcode will add.
deltaPC -= uint64((opcode - OPCODE_BASE) / LINE_RANGE)
deltaLC -= (opcode-OPCODE_BASE)%LINE_RANGE + LINE_BASE
// Encode deltaPC.
if deltaPC != 0 {
if deltaPC <= PC_RANGE {
// Adjust the opcode so that we can use the 1-byte DW_LNS_const_add_pc
// instruction.
opcode -= LINE_RANGE * int64(PC_RANGE-deltaPC)
if opcode < OPCODE_BASE {
panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
}
dctxt.AddUint8(s, dwarf.DW_LNS_const_add_pc)
} else if (1<<14) <= deltaPC && deltaPC < (1<<16) {
dctxt.AddUint8(s, dwarf.DW_LNS_fixed_advance_pc)
dctxt.AddUint16(s, uint16(deltaPC))
} else {
dctxt.AddUint8(s, dwarf.DW_LNS_advance_pc)
dwarf.Uleb128put(dctxt, s, int64(deltaPC))
}
}
// Encode deltaLC.
if deltaLC != 0 {
dctxt.AddUint8(s, dwarf.DW_LNS_advance_line)
dwarf.Sleb128put(dctxt, s, deltaLC)
}
// Output the special opcode.
dctxt.AddUint8(s, uint8(opcode))
}
// implement dwarf.Context
type dwCtxt struct{ *Link }
func (c dwCtxt) PtrSize() int {
return c.Arch.PtrSize
}
func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
ls := s.(*LSym)
ls.WriteInt(c.Link, ls.Size, size, i)
}
func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) {
c.AddInt(s, 2, int64(i))
}
func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) {
b := []byte{byte(i)}
c.AddBytes(s, b)
}
func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
ls := s.(*LSym)
ls.WriteBytes(c.Link, ls.Size, b)
}
func (c dwCtxt) AddString(s dwarf.Sym, v string) {
ls := s.(*LSym)
ls.WriteString(c.Link, ls.Size, len(v), v)
ls.WriteInt(c.Link, ls.Size, 1, 0)
}
func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
ls := s.(*LSym)
size := c.PtrSize()
if data != nil {
rsym := data.(*LSym)
ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
} else {
ls.WriteInt(c.Link, ls.Size, size, value)
}
}
func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
ls := s.(*LSym)
rsym := data.(*LSym)
ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
}
func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
panic("should be used only in the linker")
}
func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
size := 4
if isDwarf64(c.Link) {
size = 8
}
ls := s.(*LSym)
rsym := t.(*LSym)
ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
r := &ls.R[len(ls.R)-1]
r.Type = objabi.R_DWARFSECREF
}
func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
ls := s.(*LSym)
rsym := f.(*LSym)
fidx := c.Link.PosTable.FileIndex(rsym.Name)
// Note the +1 here -- the value we're writing is going to be an
// index into the DWARF line table file section, whose entries
// are numbered starting at 1, not 0.
ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
}
func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
ls := s.(*LSym)
return ls.Size
}
// Here "from" is a symbol corresponding to an inlined or concrete
// function, "to" is the symbol for the corresponding abstract
// function, and "dclIdx" is the index of the symbol of interest with
// respect to the Dcl slice of the original pre-optimization version
// of the inlined function.
func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
ls := from.(*LSym)
tls := to.(*LSym)
ridx := len(ls.R) - 1
c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
}
func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
ls := s.(*LSym)
c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
}
func (c dwCtxt) Logf(format string, args ...interface{}) {
c.Link.Logf(format, args...)
}
func isDwarf64(ctxt *Link) bool {
return ctxt.Headtype == objabi.Haix
}
func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfDebugLines *LSym) {
if s.Type != objabi.STEXT {
ctxt.Diag("dwarfSym of non-TEXT %v", s)
}
if s.Func.dwarfInfoSym == nil {
s.Func.dwarfInfoSym = &LSym{
Type: objabi.SDWARFFCN,
}
if ctxt.Flag_locationlists {
s.Func.dwarfLocSym = &LSym{
Type: objabi.SDWARFLOC,
}
}
s.Func.dwarfRangesSym = &LSym{
Type: objabi.SDWARFRANGE,
}
s.Func.dwarfDebugLinesSym = &LSym{
Type: objabi.SDWARFLINES,
}
if s.WasInlined() {
s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
}
}
return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfDebugLinesSym
}
func (s *LSym) Length(dwarfContext interface{}) int64 {
return s.Size
}
// fileSymbol returns a symbol corresponding to the source file of the
// first instruction (prog) of the specified function. This will
// presumably be the file in which the function is defined.
func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
p := fn.Func.Text
if p != nil {
f, _ := linkgetlineFromPos(ctxt, p.Pos)
fsym := ctxt.Lookup(f)
return fsym
}
return nil
}
// populateDWARF fills in the DWARF Debugging Information Entries for
// TEXT symbol 's'. The various DWARF symbols must already have been
// initialized in InitTextSym.
func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) {
info, loc, ranges, absfunc, lines := ctxt.dwarfSym(s)
if info.Size != 0 {
ctxt.Diag("makeFuncDebugEntry double process %v", s)
}
var scopes []dwarf.Scope
var inlcalls dwarf.InlCalls
if ctxt.DebugInfo != nil {
scopes, inlcalls = ctxt.DebugInfo(s, info, curfn)
}
var err error
dwctxt := dwCtxt{ctxt}
filesym := ctxt.fileSymbol(s)
fnstate := &dwarf.FnState{
Name: s.Name,
Importpath: myimportpath,
Info: info,
Filesym: filesym,
Loc: loc,
Ranges: ranges,
Absfn: absfunc,
StartPC: s,
Size: s.Size,
External: !s.Static(),
Scopes: scopes,
InlCalls: inlcalls,
UseBASEntries: ctxt.UseBASEntries,
}
if absfunc != nil {
err = dwarf.PutAbstractFunc(dwctxt, fnstate)
if err != nil {
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
}
err = dwarf.PutConcreteFunc(dwctxt, fnstate)
} else {
err = dwarf.PutDefaultFunc(dwctxt, fnstate)
}
if err != nil {
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
}
// Fill in the debug lines symbol.
ctxt.generateDebugLinesSymbol(s, lines)
}
// DwarfIntConst creates a link symbol for an integer constant with the
// given name, type and value.
func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
if myimportpath == "" {
return
}
s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
s.Type = objabi.SDWARFCONST
ctxt.Data = append(ctxt.Data, s)
})
dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
}
func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
if absfn.Size != 0 {
ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
}
if s.Func == nil {
s.Func = new(FuncInfo)
}
scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
dwctxt := dwCtxt{ctxt}
filesym := ctxt.fileSymbol(s)
fnstate := dwarf.FnState{
Name: s.Name,
Importpath: myimportpath,
Info: absfn,
Filesym: filesym,
Absfn: absfn,
External: !s.Static(),
Scopes: scopes,
UseBASEntries: ctxt.UseBASEntries,
}
if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
}
}
// This table is designed to aid in the creation of references between
// DWARF subprogram DIEs.
//
// In most cases when one DWARF DIE has to refer to another DWARF DIE,
// the target of the reference has an LSym, which makes it easy to use
// the existing relocation mechanism. For DWARF inlined routine DIEs,
// however, the subprogram DIE has to refer to a child
// parameter/variable DIE of the abstract subprogram. This child DIE
// doesn't have an LSym, and also of interest is the fact that when
// DWARF generation is happening for inlined function F within caller
// G, it's possible that DWARF generation hasn't happened yet for F,
// so there is no way to know the offset of a child DIE within F's
// abstract function. Making matters more complex, each inlined
// instance of F may refer to a subset of the original F's variables
// (depending on what happens with optimization, some vars may be
// eliminated).
//
// The fixup table below helps overcome this hurdle. At the point
// where a parameter/variable reference is made (via a call to
// "ReferenceChildDIE"), a fixup record is generate that records
// the relocation that is targeting that child variable. At a later
// point when the abstract function DIE is emitted, there will be
// a call to "RegisterChildDIEOffsets", at which point the offsets
// needed to apply fixups are captured. Finally, once the parallel
// portion of the compilation is done, fixups can actually be applied
// during the "Finalize" method (this can't be done during the
// parallel portion of the compile due to the possibility of data
// races).
//
// This table is also used to record the "precursor" function node for
// each function that is the target of an inline -- child DIE references
// have to be made with respect to the original pre-optimization
// version of the function (to allow for the fact that each inlined
// body may be optimized differently).
type DwarfFixupTable struct {
ctxt *Link
mu sync.Mutex
symtab map[*LSym]int // maps abstract fn LSYM to index in svec
svec []symFixups
precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym
}
type symFixups struct {
fixups []relFixup
doffsets []declOffset
inlIndex int32
defseen bool
}
type declOffset struct {
// Index of variable within DCL list of pre-optimization function
dclIdx int32
// Offset of var's child DIE with respect to containing subprogram DIE
offset int32
}
type relFixup struct {
refsym *LSym
relidx int32
dclidx int32
}
type fnState struct {
// precursor function (really *gc.Node)
precursor interface{}
// abstract function symbol
absfn *LSym
}
func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
return &DwarfFixupTable{
ctxt: ctxt,
symtab: make(map[*LSym]int),
precursor: make(map[*LSym]fnState),
}
}
func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} {
if fnstate, found := ft.precursor[s]; found {
return fnstate.precursor
}
return nil
}
func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
if _, found := ft.precursor[s]; found {
ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
}
// initialize abstract function symbol now. This is done here so
// as to avoid data races later on during the parallel portion of
// the back end.
absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
absfn.Set(AttrDuplicateOK, true)
absfn.Type = objabi.SDWARFABSFCN
ft.ctxt.Data = append(ft.ctxt.Data, absfn)
// In the case of "late" inlining (inlines that happen during
// wrapper generation as opposed to the main inlining phase) it's
// possible that we didn't cache the abstract function sym for the
// text symbol -- do so now if needed. See issue 38068.
if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
s.Func.dwarfAbsFnSym = absfn
}
ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
}
// Make a note of a child DIE reference: relocation 'ridx' within symbol 's'
// is targeting child 'c' of DIE with symbol 'tgt'.
func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
// Protect against concurrent access if multiple backend workers
ft.mu.Lock()
defer ft.mu.Unlock()
// Create entry for symbol if not already present.
idx, found := ft.symtab[tgt]
if !found {
ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
idx = len(ft.svec) - 1
ft.symtab[tgt] = idx
}
// Do we have child DIE offsets available? If so, then apply them,
// otherwise create a fixup record.
sf := &ft.svec[idx]
if len(sf.doffsets) > 0 {
found := false
for _, do := range sf.doffsets {
if do.dclIdx == int32(dclidx) {
off := do.offset
s.R[ridx].Add += int64(off)
found = true
break
}
}
if !found {
ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
}
} else {
sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
}
}
// Called once DWARF generation is complete for a given abstract function,
// whose children might have been referenced via a call above. Stores
// the offsets for any child DIEs (vars, params) so that they can be
// consumed later in on DwarfFixupTable.Finalize, which applies any
// outstanding fixups.
func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
// Length of these two slices should agree
if len(vars) != len(coffsets) {
ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
return
}
// Generate the slice of declOffset's based in vars/coffsets
doffsets := make([]declOffset, len(coffsets))
for i := range coffsets {
doffsets[i].dclIdx = vars[i].ChildIndex
doffsets[i].offset = coffsets[i]
}
ft.mu.Lock()
defer ft.mu.Unlock()
// Store offsets for this symbol.
idx, found := ft.symtab[s]
if !found {
sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
ft.svec = append(ft.svec, sf)
ft.symtab[s] = len(ft.svec) - 1
} else {
sf := &ft.svec[idx]
sf.doffsets = doffsets
sf.defseen = true
}
}
func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
sf := &ft.svec[slot]
for _, f := range sf.fixups {
dfound := false
for _, doffset := range sf.doffsets {
if doffset.dclIdx == f.dclidx {
f.refsym.R[f.relidx].Add += int64(doffset.offset)
dfound = true
break
}
}
if !dfound {
ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
}
}
}
// return the LSym corresponding to the 'abstract subprogram' DWARF
// info entry for a function.
func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
// Protect against concurrent access if multiple backend workers
ft.mu.Lock()
defer ft.mu.Unlock()
if fnstate, found := ft.precursor[fnsym]; found {
return fnstate.absfn
}
ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
return nil
}
// Called after all functions have been compiled; the main job of this
// function is to identify cases where there are outstanding fixups.
// This scenario crops up when we have references to variables of an
// inlined routine, but that routine is defined in some other package.
// This helper walks through and locate these fixups, then invokes a
// helper to create an abstract subprogram DIE for each one.
func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
if trace {
ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
}
// Collect up the keys from the precursor map, then sort the
// resulting list (don't want to rely on map ordering here).
fns := make([]*LSym, len(ft.precursor))
idx := 0
for fn := range ft.precursor {
fns[idx] = fn
idx++
}
sort.Sort(BySymName(fns))
// Should not be called during parallel portion of compilation.
if ft.ctxt.InParallel {
ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
}
// Generate any missing abstract functions.
for _, s := range fns {
absfn := ft.AbsFuncDwarfSym(s)
slot, found := ft.symtab[absfn]
if !found || !ft.svec[slot].defseen {
ft.ctxt.GenAbstractFunc(s)
}
}
// Apply fixups.
for _, s := range fns {
absfn := ft.AbsFuncDwarfSym(s)
slot, found := ft.symtab[absfn]
if !found {
ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
} else {
ft.processFixups(slot, s)
}
}
}
type BySymName []*LSym
func (s BySymName) Len() int { return len(s) }
func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
func (s BySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

16
vendor/github.com/twitchyliquid64/golang-asm/obj/go.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package obj
// go-specific code shared across loaders (5l, 6l, 8l).
func Nopout(p *Prog) {
p.As = ANOP
p.Scond = 0
p.From = Addr{}
p.RestArgs = nil
p.Reg = 0
p.To = Addr{}
}

131
vendor/github.com/twitchyliquid64/golang-asm/obj/inl.go generated vendored Normal file
View File

@ -0,0 +1,131 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package obj
import "github.com/twitchyliquid64/golang-asm/src"
// InlTree is a collection of inlined calls. The Parent field of an
// InlinedCall is the index of another InlinedCall in InlTree.
//
// The compiler maintains a global inlining tree and adds a node to it
// every time a function is inlined. For example, suppose f() calls g()
// and g has two calls to h(), and that f, g, and h are inlineable:
//
// 1 func main() {
// 2 f()
// 3 }
// 4 func f() {
// 5 g()
// 6 }
// 7 func g() {
// 8 h()
// 9 h()
// 10 }
// 11 func h() {
// 12 println("H")
// 13 }
//
// Assuming the global tree starts empty, inlining will produce the
// following tree:
//
// []InlinedCall{
// {Parent: -1, Func: "f", Pos: <line 2>},
// {Parent: 0, Func: "g", Pos: <line 5>},
// {Parent: 1, Func: "h", Pos: <line 8>},
// {Parent: 1, Func: "h", Pos: <line 9>},
// }
//
// The nodes of h inlined into main will have inlining indexes 2 and 3.
//
// Eventually, the compiler extracts a per-function inlining tree from
// the global inlining tree (see pcln.go).
type InlTree struct {
nodes []InlinedCall
}
// InlinedCall is a node in an InlTree.
type InlinedCall struct {
Parent int // index of the parent in the InlTree or < 0 if outermost call
Pos src.XPos // position of the inlined call
Func *LSym // function that was inlined
ParentPC int32 // PC of instruction just before inlined body. Only valid in local trees.
}
// Add adds a new call to the tree, returning its index.
func (tree *InlTree) Add(parent int, pos src.XPos, func_ *LSym) int {
r := len(tree.nodes)
call := InlinedCall{
Parent: parent,
Pos: pos,
Func: func_,
}
tree.nodes = append(tree.nodes, call)
return r
}
func (tree *InlTree) Parent(inlIndex int) int {
return tree.nodes[inlIndex].Parent
}
func (tree *InlTree) InlinedFunction(inlIndex int) *LSym {
return tree.nodes[inlIndex].Func
}
func (tree *InlTree) CallPos(inlIndex int) src.XPos {
return tree.nodes[inlIndex].Pos
}
func (tree *InlTree) setParentPC(inlIndex int, pc int32) {
tree.nodes[inlIndex].ParentPC = pc
}
// OutermostPos returns the outermost position corresponding to xpos,
// which is where xpos was ultimately inlined to. In the example for
// InlTree, main() contains inlined AST nodes from h(), but the
// outermost position for those nodes is line 2.
func (ctxt *Link) OutermostPos(xpos src.XPos) src.Pos {
pos := ctxt.InnermostPos(xpos)
outerxpos := xpos
for ix := pos.Base().InliningIndex(); ix >= 0; {
call := ctxt.InlTree.nodes[ix]
ix = call.Parent
outerxpos = call.Pos
}
return ctxt.PosTable.Pos(outerxpos)
}
// InnermostPos returns the innermost position corresponding to xpos,
// that is, the code that is inlined and that inlines nothing else.
// In the example for InlTree above, the code for println within h
// would have an innermost position with line number 12, whether
// h was not inlined, inlined into g, g-then-f, or g-then-f-then-main.
// This corresponds to what someone debugging main, f, g, or h might
// expect to see while single-stepping.
func (ctxt *Link) InnermostPos(xpos src.XPos) src.Pos {
return ctxt.PosTable.Pos(xpos)
}
// AllPos returns a slice of the positions inlined at xpos, from
// innermost (index zero) to outermost. To avoid gratuitous allocation
// the result is passed in and extended if necessary.
func (ctxt *Link) AllPos(xpos src.XPos, result []src.Pos) []src.Pos {
pos := ctxt.InnermostPos(xpos)
result = result[:0]
result = append(result, ctxt.PosTable.Pos(xpos))
for ix := pos.Base().InliningIndex(); ix >= 0; {
call := ctxt.InlTree.nodes[ix]
ix = call.Parent
result = append(result, ctxt.PosTable.Pos(call.Pos))
}
return result
}
func dumpInlTree(ctxt *Link, tree InlTree) {
for i, call := range tree.nodes {
pos := ctxt.PosTable.Pos(call.Pos)
ctxt.Logf("%0d | %0d | %s (%s) pc=%d\n", i, call.Parent, call.Func, pos, call.ParentPC)
}
}

85
vendor/github.com/twitchyliquid64/golang-asm/obj/ld.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package obj
/*
* add library to library list.
* srcref: src file referring to package
* objref: object file referring to package
* file: object file, e.g., /home/rsc/go/pkg/container/vector.a
* pkg: package import path, e.g. container/vector
*/
const (
LOG = 5
)
func mkfwd(sym *LSym) {
var dwn [LOG]int32
var cnt [LOG]int32
var lst [LOG]*Prog
for i := 0; i < LOG; i++ {
if i == 0 {
cnt[i] = 1
} else {
cnt[i] = LOG * cnt[i-1]
}
dwn[i] = 1
lst[i] = nil
}
i := 0
for p := sym.Func.Text; p != nil && p.Link != nil; p = p.Link {
i--
if i < 0 {
i = LOG - 1
}
p.Forwd = nil
dwn[i]--
if dwn[i] <= 0 {
dwn[i] = cnt[i]
if lst[i] != nil {
lst[i].Forwd = p
}
lst[i] = p
}
}
}
func Appendp(q *Prog, newprog ProgAlloc) *Prog {
p := newprog()
p.Link = q.Link
q.Link = p
p.Pos = q.Pos
return p
}

View File

@ -0,0 +1,30 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package obj
import (
"github.com/twitchyliquid64/golang-asm/goobj"
"github.com/twitchyliquid64/golang-asm/src"
)
// AddImport adds a package to the list of imported packages.
func (ctxt *Link) AddImport(pkg string, fingerprint goobj.FingerprintType) {
ctxt.Imports = append(ctxt.Imports, goobj.ImportedPkg{Pkg: pkg, Fingerprint: fingerprint})
}
func linkgetlineFromPos(ctxt *Link, xpos src.XPos) (f string, l int32) {
pos := ctxt.PosTable.Pos(xpos)
if !pos.IsKnown() {
pos = src.Pos{}
}
// TODO(gri) Should this use relative or absolute line number?
return pos.SymFilename(), int32(pos.RelLine())
}
// getFileIndexAndLine returns the file index (local to the CU), and the line number for a position.
func getFileIndexAndLine(ctxt *Link, xpos src.XPos) (int, int32) {
f, l := linkgetlineFromPos(ctxt, xpos)
return ctxt.PosTable.FileIndex(f), l
}

View File

@ -0,0 +1,771 @@
// Derived from Inferno utils/6l/l.h and related files.
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package obj
import (
"bufio"
"github.com/twitchyliquid64/golang-asm/dwarf"
"github.com/twitchyliquid64/golang-asm/goobj"
"github.com/twitchyliquid64/golang-asm/objabi"
"github.com/twitchyliquid64/golang-asm/src"
"github.com/twitchyliquid64/golang-asm/sys"
"fmt"
"sync"
)
// An Addr is an argument to an instruction.
// The general forms and their encodings are:
//
// sym±offset(symkind)(reg)(index*scale)
// Memory reference at address &sym(symkind) + offset + reg + index*scale.
// Any of sym(symkind), ±offset, (reg), (index*scale), and *scale can be omitted.
// If (reg) and *scale are both omitted, the resulting expression (index) is parsed as (reg).
// To force a parsing as index*scale, write (index*1).
// Encoding:
// type = TYPE_MEM
// name = symkind (NAME_AUTO, ...) or 0 (NAME_NONE)
// sym = sym
// offset = ±offset
// reg = reg (REG_*)
// index = index (REG_*)
// scale = scale (1, 2, 4, 8)
//
// $<mem>
// Effective address of memory reference <mem>, defined above.
// Encoding: same as memory reference, but type = TYPE_ADDR.
//
// $<±integer value>
// This is a special case of $<mem>, in which only ±offset is present.
// It has a separate type for easy recognition.
// Encoding:
// type = TYPE_CONST
// offset = ±integer value
//
// *<mem>
// Indirect reference through memory reference <mem>, defined above.
// Only used on x86 for CALL/JMP *sym(SB), which calls/jumps to a function
// pointer stored in the data word sym(SB), not a function named sym(SB).
// Encoding: same as above, but type = TYPE_INDIR.
//
// $*$<mem>
// No longer used.
// On machines with actual SB registers, $*$<mem> forced the
// instruction encoding to use a full 32-bit constant, never a
// reference relative to SB.
//
// $<floating point literal>
// Floating point constant value.
// Encoding:
// type = TYPE_FCONST
// val = floating point value
//
// $<string literal, up to 8 chars>
// String literal value (raw bytes used for DATA instruction).
// Encoding:
// type = TYPE_SCONST
// val = string
//
// <register name>
// Any register: integer, floating point, control, segment, and so on.
// If looking for specific register kind, must check type and reg value range.
// Encoding:
// type = TYPE_REG
// reg = reg (REG_*)
//
// x(PC)
// Encoding:
// type = TYPE_BRANCH
// val = Prog* reference OR ELSE offset = target pc (branch takes priority)
//
// $±x-±y
// Final argument to TEXT, specifying local frame size x and argument size y.
// In this form, x and y are integer literals only, not arbitrary expressions.
// This avoids parsing ambiguities due to the use of - as a separator.
// The ± are optional.
// If the final argument to TEXT omits the -±y, the encoding should still
// use TYPE_TEXTSIZE (not TYPE_CONST), with u.argsize = ArgsSizeUnknown.
// Encoding:
// type = TYPE_TEXTSIZE
// offset = x
// val = int32(y)
//
// reg<<shift, reg>>shift, reg->shift, reg@>shift
// Shifted register value, for ARM and ARM64.
// In this form, reg must be a register and shift can be a register or an integer constant.
// Encoding:
// type = TYPE_SHIFT
// On ARM:
// offset = (reg&15) | shifttype<<5 | count
// shifttype = 0, 1, 2, 3 for <<, >>, ->, @>
// count = (reg&15)<<8 | 1<<4 for a register shift count, (n&31)<<7 for an integer constant.
// On ARM64:
// offset = (reg&31)<<16 | shifttype<<22 | (count&63)<<10
// shifttype = 0, 1, 2 for <<, >>, ->
//
// (reg, reg)
// A destination register pair. When used as the last argument of an instruction,
// this form makes clear that both registers are destinations.
// Encoding:
// type = TYPE_REGREG
// reg = first register
// offset = second register
//
// [reg, reg, reg-reg]
// Register list for ARM, ARM64, 386/AMD64.
// Encoding:
// type = TYPE_REGLIST
// On ARM:
// offset = bit mask of registers in list; R0 is low bit.
// On ARM64:
// offset = register count (Q:size) | arrangement (opcode) | first register
// On 386/AMD64:
// reg = range low register
// offset = 2 packed registers + kind tag (see x86.EncodeRegisterRange)
//
// reg, reg
// Register pair for ARM.
// TYPE_REGREG2
//
// (reg+reg)
// Register pair for PPC64.
// Encoding:
// type = TYPE_MEM
// reg = first register
// index = second register
// scale = 1
//
// reg.[US]XT[BHWX]
// Register extension for ARM64
// Encoding:
// type = TYPE_REG
// reg = REG_[US]XT[BHWX] + register + shift amount
// offset = ((reg&31) << 16) | (exttype << 13) | (amount<<10)
//
// reg.<T>
// Register arrangement for ARM64 SIMD register
// e.g.: V1.S4, V2.S2, V7.D2, V2.H4, V6.B16
// Encoding:
// type = TYPE_REG
// reg = REG_ARNG + register + arrangement
//
// reg.<T>[index]
// Register element for ARM64
// Encoding:
// type = TYPE_REG
// reg = REG_ELEM + register + arrangement
// index = element index
type Addr struct {
Reg int16
Index int16
Scale int16 // Sometimes holds a register.
Type AddrType
Name AddrName
Class int8
Offset int64
Sym *LSym
// argument value:
// for TYPE_SCONST, a string
// for TYPE_FCONST, a float64
// for TYPE_BRANCH, a *Prog (optional)
// for TYPE_TEXTSIZE, an int32 (optional)
Val interface{}
}
type AddrName int8
const (
NAME_NONE AddrName = iota
NAME_EXTERN
NAME_STATIC
NAME_AUTO
NAME_PARAM
// A reference to name@GOT(SB) is a reference to the entry in the global offset
// table for 'name'.
NAME_GOTREF
// Indicates that this is a reference to a TOC anchor.
NAME_TOCREF
)
//go:generate stringer -type AddrType
type AddrType uint8
const (
TYPE_NONE AddrType = iota
TYPE_BRANCH
TYPE_TEXTSIZE
TYPE_MEM
TYPE_CONST
TYPE_FCONST
TYPE_SCONST
TYPE_REG
TYPE_ADDR
TYPE_SHIFT
TYPE_REGREG
TYPE_REGREG2
TYPE_INDIR
TYPE_REGLIST
)
func (a *Addr) Target() *Prog {
if a.Type == TYPE_BRANCH && a.Val != nil {
return a.Val.(*Prog)
}
return nil
}
func (a *Addr) SetTarget(t *Prog) {
if a.Type != TYPE_BRANCH {
panic("setting branch target when type is not TYPE_BRANCH")
}
a.Val = t
}
// Prog describes a single machine instruction.
//
// The general instruction form is:
//
// (1) As.Scond From [, ...RestArgs], To
// (2) As.Scond From, Reg [, ...RestArgs], To, RegTo2
//
// where As is an opcode and the others are arguments:
// From, Reg are sources, and To, RegTo2 are destinations.
// RestArgs can hold additional sources and destinations.
// Usually, not all arguments are present.
// For example, MOVL R1, R2 encodes using only As=MOVL, From=R1, To=R2.
// The Scond field holds additional condition bits for systems (like arm)
// that have generalized conditional execution.
// (2) form is present for compatibility with older code,
// to avoid too much changes in a single swing.
// (1) scheme is enough to express any kind of operand combination.
//
// Jump instructions use the To.Val field to point to the target *Prog,
// which must be in the same linked list as the jump instruction.
//
// The Progs for a given function are arranged in a list linked through the Link field.
//
// Each Prog is charged to a specific source line in the debug information,
// specified by Pos.Line().
// Every Prog has a Ctxt field that defines its context.
// For performance reasons, Progs usually are usually bulk allocated, cached, and reused;
// those bulk allocators should always be used, rather than new(Prog).
//
// The other fields not yet mentioned are for use by the back ends and should
// be left zeroed by creators of Prog lists.
type Prog struct {
Ctxt *Link // linker context
Link *Prog // next Prog in linked list
From Addr // first source operand
RestArgs []Addr // can pack any operands that not fit into {Prog.From, Prog.To}
To Addr // destination operand (second is RegTo2 below)
Pool *Prog // constant pool entry, for arm,arm64 back ends
Forwd *Prog // for x86 back end
Rel *Prog // for x86, arm back ends
Pc int64 // for back ends or assembler: virtual or actual program counter, depending on phase
Pos src.XPos // source position of this instruction
Spadj int32 // effect of instruction on stack pointer (increment or decrement amount)
As As // assembler opcode
Reg int16 // 2nd source operand
RegTo2 int16 // 2nd destination operand
Mark uint16 // bitmask of arch-specific items
Optab uint16 // arch-specific opcode index
Scond uint8 // bits that describe instruction suffixes (e.g. ARM conditions)
Back uint8 // for x86 back end: backwards branch state
Ft uint8 // for x86 back end: type index of Prog.From
Tt uint8 // for x86 back end: type index of Prog.To
Isize uint8 // for x86 back end: size of the instruction in bytes
}
// From3Type returns p.GetFrom3().Type, or TYPE_NONE when
// p.GetFrom3() returns nil.
//
// Deprecated: for the same reasons as Prog.GetFrom3.
func (p *Prog) From3Type() AddrType {
if p.RestArgs == nil {
return TYPE_NONE
}
return p.RestArgs[0].Type
}
// GetFrom3 returns second source operand (the first is Prog.From).
// In combination with Prog.From and Prog.To it makes common 3 operand
// case easier to use.
//
// Should be used only when RestArgs is set with SetFrom3.
//
// Deprecated: better use RestArgs directly or define backend-specific getters.
// Introduced to simplify transition to []Addr.
// Usage of this is discouraged due to fragility and lack of guarantees.
func (p *Prog) GetFrom3() *Addr {
if p.RestArgs == nil {
return nil
}
return &p.RestArgs[0]
}
// SetFrom3 assigns []Addr{a} to p.RestArgs.
// In pair with Prog.GetFrom3 it can help in emulation of Prog.From3.
//
// Deprecated: for the same reasons as Prog.GetFrom3.
func (p *Prog) SetFrom3(a Addr) {
p.RestArgs = []Addr{a}
}
// An As denotes an assembler opcode.
// There are some portable opcodes, declared here in package obj,
// that are common to all architectures.
// However, the majority of opcodes are arch-specific
// and are declared in their respective architecture's subpackage.
type As int16
// These are the portable opcodes.
const (
AXXX As = iota
ACALL
ADUFFCOPY
ADUFFZERO
AEND
AFUNCDATA
AJMP
ANOP
APCALIGN
APCDATA
ARET
AGETCALLERPC
ATEXT
AUNDEF
A_ARCHSPECIFIC
)
// Each architecture is allotted a distinct subspace of opcode values
// for declaring its arch-specific opcodes.
// Within this subspace, the first arch-specific opcode should be
// at offset A_ARCHSPECIFIC.
//
// Subspaces are aligned to a power of two so opcodes can be masked
// with AMask and used as compact array indices.
const (
ABase386 = (1 + iota) << 11
ABaseARM
ABaseAMD64
ABasePPC64
ABaseARM64
ABaseMIPS
ABaseRISCV
ABaseS390X
ABaseWasm
AllowedOpCodes = 1 << 11 // The number of opcodes available for any given architecture.
AMask = AllowedOpCodes - 1 // AND with this to use the opcode as an array index.
)
// An LSym is the sort of symbol that is written to an object file.
// It represents Go symbols in a flat pkg+"."+name namespace.
type LSym struct {
Name string
Type objabi.SymKind
Attribute
RefIdx int // Index of this symbol in the symbol reference list.
Size int64
Gotype *LSym
P []byte
R []Reloc
Func *FuncInfo
Pkg string
PkgIdx int32
SymIdx int32 // TODO: replace RefIdx
}
// A FuncInfo contains extra fields for STEXT symbols.
type FuncInfo struct {
Args int32
Locals int32
Align int32
FuncID objabi.FuncID
Text *Prog
Autot map[*LSym]struct{}
Pcln Pcln
InlMarks []InlMark
dwarfInfoSym *LSym
dwarfLocSym *LSym
dwarfRangesSym *LSym
dwarfAbsFnSym *LSym
dwarfDebugLinesSym *LSym
GCArgs *LSym
GCLocals *LSym
GCRegs *LSym // Only if !go115ReduceLiveness
StackObjects *LSym
OpenCodedDeferInfo *LSym
FuncInfoSym *LSym
}
type InlMark struct {
// When unwinding from an instruction in an inlined body, mark
// where we should unwind to.
// id records the global inlining id of the inlined body.
// p records the location of an instruction in the parent (inliner) frame.
p *Prog
id int32
}
// Mark p as the instruction to set as the pc when
// "unwinding" the inlining global frame id. Usually it should be
// instruction with a file:line at the callsite, and occur
// just before the body of the inlined function.
func (fi *FuncInfo) AddInlMark(p *Prog, id int32) {
fi.InlMarks = append(fi.InlMarks, InlMark{p: p, id: id})
}
// Record the type symbol for an auto variable so that the linker
// an emit DWARF type information for the type.
func (fi *FuncInfo) RecordAutoType(gotype *LSym) {
if fi.Autot == nil {
fi.Autot = make(map[*LSym]struct{})
}
fi.Autot[gotype] = struct{}{}
}
//go:generate stringer -type ABI
// ABI is the calling convention of a text symbol.
type ABI uint8
const (
// ABI0 is the stable stack-based ABI. It's important that the
// value of this is "0": we can't distinguish between
// references to data and ABI0 text symbols in assembly code,
// and hence this doesn't distinguish between symbols without
// an ABI and text symbols with ABI0.
ABI0 ABI = iota
// ABIInternal is the internal ABI that may change between Go
// versions. All Go functions use the internal ABI and the
// compiler generates wrappers for calls to and from other
// ABIs.
ABIInternal
ABICount
)
// Attribute is a set of symbol attributes.
type Attribute uint32
const (
AttrDuplicateOK Attribute = 1 << iota
AttrCFunc
AttrNoSplit
AttrLeaf
AttrWrapper
AttrNeedCtxt
AttrNoFrame
AttrOnList
AttrStatic
// MakeTypelink means that the type should have an entry in the typelink table.
AttrMakeTypelink
// ReflectMethod means the function may call reflect.Type.Method or
// reflect.Type.MethodByName. Matching is imprecise (as reflect.Type
// can be used through a custom interface), so ReflectMethod may be
// set in some cases when the reflect package is not called.
//
// Used by the linker to determine what methods can be pruned.
AttrReflectMethod
// Local means make the symbol local even when compiling Go code to reference Go
// symbols in other shared libraries, as in this mode symbols are global by
// default. "local" here means in the sense of the dynamic linker, i.e. not
// visible outside of the module (shared library or executable) that contains its
// definition. (When not compiling to support Go shared libraries, all symbols are
// local in this sense unless there is a cgo_export_* directive).
AttrLocal
// For function symbols; indicates that the specified function was the
// target of an inline during compilation
AttrWasInlined
// TopFrame means that this function is an entry point and unwinders should not
// keep unwinding beyond this frame.
AttrTopFrame
// Indexed indicates this symbol has been assigned with an index (when using the
// new object file format).
AttrIndexed
// Only applied on type descriptor symbols, UsedInIface indicates this type is
// converted to an interface.
//
// Used by the linker to determine what methods can be pruned.
AttrUsedInIface
// ContentAddressable indicates this is a content-addressable symbol.
AttrContentAddressable
// attrABIBase is the value at which the ABI is encoded in
// Attribute. This must be last; all bits after this are
// assumed to be an ABI value.
//
// MUST BE LAST since all bits above this comprise the ABI.
attrABIBase
)
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 }
func (a Attribute) CFunc() bool { return a&AttrCFunc != 0 }
func (a Attribute) NoSplit() bool { return a&AttrNoSplit != 0 }
func (a Attribute) Leaf() bool { return a&AttrLeaf != 0 }
func (a Attribute) OnList() bool { return a&AttrOnList != 0 }
func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 }
func (a Attribute) Local() bool { return a&AttrLocal != 0 }
func (a Attribute) Wrapper() bool { return a&AttrWrapper != 0 }
func (a Attribute) NeedCtxt() bool { return a&AttrNeedCtxt != 0 }
func (a Attribute) NoFrame() bool { return a&AttrNoFrame != 0 }
func (a Attribute) Static() bool { return a&AttrStatic != 0 }
func (a Attribute) WasInlined() bool { return a&AttrWasInlined != 0 }
func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 }
func (a Attribute) Indexed() bool { return a&AttrIndexed != 0 }
func (a Attribute) UsedInIface() bool { return a&AttrUsedInIface != 0 }
func (a Attribute) ContentAddressable() bool { return a&AttrContentAddressable != 0 }
func (a *Attribute) Set(flag Attribute, value bool) {
if value {
*a |= flag
} else {
*a &^= flag
}
}
func (a Attribute) ABI() ABI { return ABI(a / attrABIBase) }
func (a *Attribute) SetABI(abi ABI) {
const mask = 1 // Only one ABI bit for now.
*a = (*a &^ (mask * attrABIBase)) | Attribute(abi)*attrABIBase
}
var textAttrStrings = [...]struct {
bit Attribute
s string
}{
{bit: AttrDuplicateOK, s: "DUPOK"},
{bit: AttrMakeTypelink, s: ""},
{bit: AttrCFunc, s: "CFUNC"},
{bit: AttrNoSplit, s: "NOSPLIT"},
{bit: AttrLeaf, s: "LEAF"},
{bit: AttrOnList, s: ""},
{bit: AttrReflectMethod, s: "REFLECTMETHOD"},
{bit: AttrLocal, s: "LOCAL"},
{bit: AttrWrapper, s: "WRAPPER"},
{bit: AttrNeedCtxt, s: "NEEDCTXT"},
{bit: AttrNoFrame, s: "NOFRAME"},
{bit: AttrStatic, s: "STATIC"},
{bit: AttrWasInlined, s: ""},
{bit: AttrTopFrame, s: "TOPFRAME"},
{bit: AttrIndexed, s: ""},
{bit: AttrContentAddressable, s: ""},
}
// TextAttrString formats a for printing in as part of a TEXT prog.
func (a Attribute) TextAttrString() string {
var s string
for _, x := range textAttrStrings {
if a&x.bit != 0 {
if x.s != "" {
s += x.s + "|"
}
a &^= x.bit
}
}
switch a.ABI() {
case ABI0:
case ABIInternal:
s += "ABIInternal|"
a.SetABI(0) // Clear ABI so we don't print below.
}
if a != 0 {
s += fmt.Sprintf("UnknownAttribute(%d)|", a)
}
// Chop off trailing |, if present.
if len(s) > 0 {
s = s[:len(s)-1]
}
return s
}
func (s *LSym) String() string {
return s.Name
}
// The compiler needs *LSym to be assignable to cmd/compile/internal/ssa.Sym.
func (s *LSym) CanBeAnSSASym() {
}
type Pcln struct {
Pcsp Pcdata
Pcfile Pcdata
Pcline Pcdata
Pcinline Pcdata
Pcdata []Pcdata
Funcdata []*LSym
Funcdataoff []int64
UsedFiles map[goobj.CUFileIndex]struct{} // file indices used while generating pcfile
InlTree InlTree // per-function inlining tree extracted from the global tree
}
type Reloc struct {
Off int32
Siz uint8
Type objabi.RelocType
Add int64
Sym *LSym
}
type Auto struct {
Asym *LSym
Aoffset int32
Name AddrName
Gotype *LSym
}
type Pcdata struct {
P []byte
}
// Link holds the context for writing object code from a compiler
// to be linker input or for reading that input into the linker.
type Link struct {
Headtype objabi.HeadType
Arch *LinkArch
Debugasm int
Debugvlog bool
Debugpcln string
Flag_shared bool
Flag_dynlink bool
Flag_linkshared bool
Flag_optimize bool
Flag_locationlists bool
Retpoline bool // emit use of retpoline stubs for indirect jmp/call
Bso *bufio.Writer
Pathname string
Pkgpath string // the current package's import path, "" if unknown
hashmu sync.Mutex // protects hash, funchash
hash map[string]*LSym // name -> sym mapping
funchash map[string]*LSym // name -> sym mapping for ABIInternal syms
statichash map[string]*LSym // name -> sym mapping for static syms
PosTable src.PosTable
InlTree InlTree // global inlining tree used by gc/inl.go
DwFixups *DwarfFixupTable
Imports []goobj.ImportedPkg
DiagFunc func(string, ...interface{})
DiagFlush func()
DebugInfo func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) // if non-nil, curfn is a *gc.Node
GenAbstractFunc func(fn *LSym)
Errors int
InParallel bool // parallel backend phase in effect
UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges
IsAsm bool // is the source assembly language, which may contain surprising idioms (e.g., call tables)
// state for writing objects
Text []*LSym
Data []*LSym
// ABIAliases are text symbols that should be aliased to all
// ABIs. These symbols may only be referenced and not defined
// by this object, since the need for an alias may appear in a
// different object than the definition. Hence, this
// information can't be carried in the symbol definition.
//
// TODO(austin): Replace this with ABI wrappers once the ABIs
// actually diverge.
ABIAliases []*LSym
// Constant symbols (e.g. $i64.*) are data symbols created late
// in the concurrent phase. To ensure a deterministic order, we
// add them to a separate list, sort at the end, and append it
// to Data.
constSyms []*LSym
// pkgIdx maps package path to index. The index is used for
// symbol reference in the object file.
pkgIdx map[string]int32
defs []*LSym // list of defined symbols in the current package
hashed64defs []*LSym // list of defined short (64-bit or less) hashed (content-addressable) symbols
hasheddefs []*LSym // list of defined hashed (content-addressable) symbols
nonpkgdefs []*LSym // list of defined non-package symbols
nonpkgrefs []*LSym // list of referenced non-package symbols
Fingerprint goobj.FingerprintType // fingerprint of symbol indices, to catch index mismatch
}
func (ctxt *Link) Diag(format string, args ...interface{}) {
ctxt.Errors++
ctxt.DiagFunc(format, args...)
}
func (ctxt *Link) Logf(format string, args ...interface{}) {
fmt.Fprintf(ctxt.Bso, format, args...)
ctxt.Bso.Flush()
}
// The smallest possible offset from the hardware stack pointer to a local
// variable on the stack. Architectures that use a link register save its value
// on the stack in the function prologue and so always have a pointer between
// the hardware stack pointer and the local variable area.
func (ctxt *Link) FixedFrameSize() int64 {
switch ctxt.Arch.Family {
case sys.AMD64, sys.I386, sys.Wasm:
return 0
case sys.PPC64:
// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
// just use that much stack always on ppc64x.
return int64(4 * ctxt.Arch.PtrSize)
default:
return int64(ctxt.Arch.PtrSize)
}
}
// LinkArch is the definition of a single architecture.
type LinkArch struct {
*sys.Arch
Init func(*Link)
Preprocess func(*Link, *LSym, ProgAlloc)
Assemble func(*Link, *LSym, ProgAlloc)
Progedit func(*Link, *Prog, ProgAlloc)
UnaryDst map[As]bool // Instruction takes one operand, a destination.
DWARFRegisters map[int16]int16
}

View File

@ -0,0 +1,481 @@
// cmd/9c/9.out.h from Vita Nuova.
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package mips
import (
"github.com/twitchyliquid64/golang-asm/obj"
)
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p mips
/*
* mips 64
*/
const (
NSNAME = 8
NSYM = 50
NREG = 32 /* number of general registers */
NFREG = 32 /* number of floating point registers */
NWREG = 32 /* number of MSA registers */
)
const (
REG_R0 = obj.RBaseMIPS + iota // must be a multiple of 32
REG_R1
REG_R2
REG_R3
REG_R4
REG_R5
REG_R6
REG_R7
REG_R8
REG_R9
REG_R10
REG_R11
REG_R12
REG_R13
REG_R14
REG_R15
REG_R16
REG_R17
REG_R18
REG_R19
REG_R20
REG_R21
REG_R22
REG_R23
REG_R24
REG_R25
REG_R26
REG_R27
REG_R28
REG_R29
REG_R30
REG_R31
REG_F0 // must be a multiple of 32
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_F8
REG_F9
REG_F10
REG_F11
REG_F12
REG_F13
REG_F14
REG_F15
REG_F16
REG_F17
REG_F18
REG_F19
REG_F20
REG_F21
REG_F22
REG_F23
REG_F24
REG_F25
REG_F26
REG_F27
REG_F28
REG_F29
REG_F30
REG_F31
// co-processor 0 control registers
REG_M0 // must be a multiple of 32
REG_M1
REG_M2
REG_M3
REG_M4
REG_M5
REG_M6
REG_M7
REG_M8
REG_M9
REG_M10
REG_M11
REG_M12
REG_M13
REG_M14
REG_M15
REG_M16
REG_M17
REG_M18
REG_M19
REG_M20
REG_M21
REG_M22
REG_M23
REG_M24
REG_M25
REG_M26
REG_M27
REG_M28
REG_M29
REG_M30
REG_M31
// FPU control registers
REG_FCR0 // must be a multiple of 32
REG_FCR1
REG_FCR2
REG_FCR3
REG_FCR4
REG_FCR5
REG_FCR6
REG_FCR7
REG_FCR8
REG_FCR9
REG_FCR10
REG_FCR11
REG_FCR12
REG_FCR13
REG_FCR14
REG_FCR15
REG_FCR16
REG_FCR17
REG_FCR18
REG_FCR19
REG_FCR20
REG_FCR21
REG_FCR22
REG_FCR23
REG_FCR24
REG_FCR25
REG_FCR26
REG_FCR27
REG_FCR28
REG_FCR29
REG_FCR30
REG_FCR31
// MSA registers
// The lower bits of W registers are alias to F registers
REG_W0 // must be a multiple of 32
REG_W1
REG_W2
REG_W3
REG_W4
REG_W5
REG_W6
REG_W7
REG_W8
REG_W9
REG_W10
REG_W11
REG_W12
REG_W13
REG_W14
REG_W15
REG_W16
REG_W17
REG_W18
REG_W19
REG_W20
REG_W21
REG_W22
REG_W23
REG_W24
REG_W25
REG_W26
REG_W27
REG_W28
REG_W29
REG_W30
REG_W31
REG_HI
REG_LO
REG_LAST = REG_LO // the last defined register
REG_SPECIAL = REG_M0
REGZERO = REG_R0 /* set to zero */
REGSP = REG_R29
REGSB = REG_R28
REGLINK = REG_R31
REGRET = REG_R1
REGARG = -1 /* -1 disables passing the first argument in register */
REGRT1 = REG_R1 /* reserved for runtime, duffzero and duffcopy */
REGRT2 = REG_R2 /* reserved for runtime, duffcopy */
REGCTXT = REG_R22 /* context for closures */
REGG = REG_R30 /* G */
REGTMP = REG_R23 /* used by the linker */
FREGRET = REG_F0
)
// https://llvm.org/svn/llvm-project/llvm/trunk/lib/Target/Mips/MipsRegisterInfo.td search for DwarfRegNum
// https://gcc.gnu.org/viewcvs/gcc/trunk/gcc/config/mips/mips.c?view=co&revision=258099&content-type=text%2Fplain search for mips_dwarf_regno
// For now, this is adequate for both 32 and 64 bit.
var MIPSDWARFRegisters = map[int16]int16{}
func init() {
// f assigns dwarfregisters[from:to] = (base):(to-from+base)
f := func(from, to, base int16) {
for r := int16(from); r <= to; r++ {
MIPSDWARFRegisters[r] = (r - from) + base
}
}
f(REG_R0, REG_R31, 0)
f(REG_F0, REG_F31, 32) // For 32-bit MIPS, compiler only uses even numbered registers -- see cmd/compile/internal/ssa/gen/MIPSOps.go
MIPSDWARFRegisters[REG_HI] = 64
MIPSDWARFRegisters[REG_LO] = 65
// The lower bits of W registers are alias to F registers
f(REG_W0, REG_W31, 32)
}
const (
BIG = 32766
)
const (
/* mark flags */
FOLL = 1 << 0
LABEL = 1 << 1
LEAF = 1 << 2
SYNC = 1 << 3
BRANCH = 1 << 4
LOAD = 1 << 5
FCMP = 1 << 6
NOSCHED = 1 << 7
NSCHED = 20
)
const (
C_NONE = iota
C_REG
C_FREG
C_FCREG
C_MREG /* special processor register */
C_WREG /* MSA registers */
C_HI
C_LO
C_ZCON
C_SCON /* 16 bit signed */
C_UCON /* 32 bit signed, low 16 bits 0 */
C_ADD0CON
C_AND0CON
C_ADDCON /* -0x8000 <= v < 0 */
C_ANDCON /* 0 < v <= 0xFFFF */
C_LCON /* other 32 */
C_DCON /* other 64 (could subdivide further) */
C_SACON /* $n(REG) where n <= int16 */
C_SECON
C_LACON /* $n(REG) where int16 < n <= int32 */
C_LECON
C_DACON /* $n(REG) where int32 < n */
C_STCON /* $tlsvar */
C_SBRA
C_LBRA
C_SAUTO
C_LAUTO
C_SEXT
C_LEXT
C_ZOREG
C_SOREG
C_LOREG
C_GOK
C_ADDR
C_TLS
C_TEXTSIZE
C_NCLASS /* must be the last */
)
const (
AABSD = obj.ABaseMIPS + obj.A_ARCHSPECIFIC + iota
AABSF
AABSW
AADD
AADDD
AADDF
AADDU
AADDW
AAND
ABEQ
ABFPF
ABFPT
ABGEZ
ABGEZAL
ABGTZ
ABLEZ
ABLTZ
ABLTZAL
ABNE
ABREAK
ACLO
ACLZ
ACMOVF
ACMOVN
ACMOVT
ACMOVZ
ACMPEQD
ACMPEQF
ACMPGED
ACMPGEF
ACMPGTD
ACMPGTF
ADIV
ADIVD
ADIVF
ADIVU
ADIVW
AGOK
ALL
ALLV
ALUI
AMADD
AMOVB
AMOVBU
AMOVD
AMOVDF
AMOVDW
AMOVF
AMOVFD
AMOVFW
AMOVH
AMOVHU
AMOVW
AMOVWD
AMOVWF
AMOVWL
AMOVWR
AMSUB
AMUL
AMULD
AMULF
AMULU
AMULW
ANEGD
ANEGF
ANEGW
ANEGV
ANOOP // hardware nop
ANOR
AOR
AREM
AREMU
ARFE
ASC
ASCV
ASGT
ASGTU
ASLL
ASQRTD
ASQRTF
ASRA
ASRL
ASUB
ASUBD
ASUBF
ASUBU
ASUBW
ASYNC
ASYSCALL
ATEQ
ATLBP
ATLBR
ATLBWI
ATLBWR
ATNE
AWORD
AXOR
/* 64-bit */
AMOVV
AMOVVL
AMOVVR
ASLLV
ASRAV
ASRLV
ADIVV
ADIVVU
AREMV
AREMVU
AMULV
AMULVU
AADDV
AADDVU
ASUBV
ASUBVU
/* 64-bit FP */
ATRUNCFV
ATRUNCDV
ATRUNCFW
ATRUNCDW
AMOVWU
AMOVFV
AMOVDV
AMOVVF
AMOVVD
/* MSA */
AVMOVB
AVMOVH
AVMOVW
AVMOVD
ALAST
// aliases
AJMP = obj.AJMP
AJAL = obj.ACALL
ARET = obj.ARET
)
func init() {
// The asm encoder generally assumes that the lowest 5 bits of the
// REG_XX constants match the machine instruction encoding, i.e.
// the lowest 5 bits is the register number.
// Check this here.
if REG_R0%32 != 0 {
panic("REG_R0 is not a multiple of 32")
}
if REG_F0%32 != 0 {
panic("REG_F0 is not a multiple of 32")
}
if REG_M0%32 != 0 {
panic("REG_M0 is not a multiple of 32")
}
if REG_FCR0%32 != 0 {
panic("REG_FCR0 is not a multiple of 32")
}
if REG_W0%32 != 0 {
panic("REG_W0 is not a multiple of 32")
}
}

View File

@ -0,0 +1,135 @@
// Code generated by stringer -i a.out.go -o anames.go -p mips; DO NOT EDIT.
package mips
import "github.com/twitchyliquid64/golang-asm/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "ABSD",
"ABSF",
"ABSW",
"ADD",
"ADDD",
"ADDF",
"ADDU",
"ADDW",
"AND",
"BEQ",
"BFPF",
"BFPT",
"BGEZ",
"BGEZAL",
"BGTZ",
"BLEZ",
"BLTZ",
"BLTZAL",
"BNE",
"BREAK",
"CLO",
"CLZ",
"CMOVF",
"CMOVN",
"CMOVT",
"CMOVZ",
"CMPEQD",
"CMPEQF",
"CMPGED",
"CMPGEF",
"CMPGTD",
"CMPGTF",
"DIV",
"DIVD",
"DIVF",
"DIVU",
"DIVW",
"GOK",
"LL",
"LLV",
"LUI",
"MADD",
"MOVB",
"MOVBU",
"MOVD",
"MOVDF",
"MOVDW",
"MOVF",
"MOVFD",
"MOVFW",
"MOVH",
"MOVHU",
"MOVW",
"MOVWD",
"MOVWF",
"MOVWL",
"MOVWR",
"MSUB",
"MUL",
"MULD",
"MULF",
"MULU",
"MULW",
"NEGD",
"NEGF",
"NEGW",
"NEGV",
"NOOP",
"NOR",
"OR",
"REM",
"REMU",
"RFE",
"SC",
"SCV",
"SGT",
"SGTU",
"SLL",
"SQRTD",
"SQRTF",
"SRA",
"SRL",
"SUB",
"SUBD",
"SUBF",
"SUBU",
"SUBW",
"SYNC",
"SYSCALL",
"TEQ",
"TLBP",
"TLBR",
"TLBWI",
"TLBWR",
"TNE",
"WORD",
"XOR",
"MOVV",
"MOVVL",
"MOVVR",
"SLLV",
"SRAV",
"SRLV",
"DIVV",
"DIVVU",
"REMV",
"REMVU",
"MULV",
"MULVU",
"ADDV",
"ADDVU",
"SUBV",
"SUBVU",
"TRUNCFV",
"TRUNCDV",
"TRUNCFW",
"TRUNCDW",
"MOVWU",
"MOVFV",
"MOVDV",
"MOVVF",
"MOVVD",
"VMOVB",
"VMOVH",
"VMOVW",
"VMOVD",
"LAST",
}

View File

@ -0,0 +1,45 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mips
var cnames0 = []string{
"NONE",
"REG",
"FREG",
"FCREG",
"MREG",
"WREG",
"HI",
"LO",
"ZCON",
"SCON",
"UCON",
"ADD0CON",
"AND0CON",
"ADDCON",
"ANDCON",
"LCON",
"DCON",
"SACON",
"SECON",
"LACON",
"LECON",
"DACON",
"STCON",
"SBRA",
"LBRA",
"SAUTO",
"LAUTO",
"SEXT",
"LEXT",
"ZOREG",
"SOREG",
"LOREG",
"GOK",
"ADDR",
"TLS",
"TEXTSIZE",
"NCLASS",
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,83 @@
// cmd/9l/list.c from Vita Nuova.
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package mips
import (
"github.com/twitchyliquid64/golang-asm/obj"
"fmt"
)
func init() {
obj.RegisterRegister(obj.RBaseMIPS, REG_LAST+1, rconv)
obj.RegisterOpcode(obj.ABaseMIPS, Anames)
}
func rconv(r int) string {
if r == 0 {
return "NONE"
}
if r == REGG {
// Special case.
return "g"
}
if REG_R0 <= r && r <= REG_R31 {
return fmt.Sprintf("R%d", r-REG_R0)
}
if REG_F0 <= r && r <= REG_F31 {
return fmt.Sprintf("F%d", r-REG_F0)
}
if REG_M0 <= r && r <= REG_M31 {
return fmt.Sprintf("M%d", r-REG_M0)
}
if REG_FCR0 <= r && r <= REG_FCR31 {
return fmt.Sprintf("FCR%d", r-REG_FCR0)
}
if REG_W0 <= r && r <= REG_W31 {
return fmt.Sprintf("W%d", r-REG_W0)
}
if r == REG_HI {
return "HI"
}
if r == REG_LO {
return "LO"
}
return fmt.Sprintf("Rgok(%d)", r-obj.RBaseMIPS)
}
func DRconv(a int) string {
s := "C_??"
if a >= C_NONE && a <= C_NCLASS {
s = cnames0[a]
}
var fp string
fp += s
return fp
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,755 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Writing Go object files.
package obj
import (
"bytes"
"github.com/twitchyliquid64/golang-asm/bio"
"github.com/twitchyliquid64/golang-asm/goobj"
"github.com/twitchyliquid64/golang-asm/objabi"
"github.com/twitchyliquid64/golang-asm/sys"
"crypto/sha1"
"encoding/binary"
"fmt"
"io"
"path/filepath"
"sort"
"strings"
)
// Entry point of writing new object file.
func WriteObjFile(ctxt *Link, b *bio.Writer) {
debugAsmEmit(ctxt)
genFuncInfoSyms(ctxt)
w := writer{
Writer: goobj.NewWriter(b),
ctxt: ctxt,
pkgpath: objabi.PathToPrefix(ctxt.Pkgpath),
}
start := b.Offset()
w.init()
// Header
// We just reserve the space. We'll fill in the offsets later.
flags := uint32(0)
if ctxt.Flag_shared {
flags |= goobj.ObjFlagShared
}
if w.pkgpath == "" {
flags |= goobj.ObjFlagNeedNameExpansion
}
if ctxt.IsAsm {
flags |= goobj.ObjFlagFromAssembly
}
h := goobj.Header{
Magic: goobj.Magic,
Fingerprint: ctxt.Fingerprint,
Flags: flags,
}
h.Write(w.Writer)
// String table
w.StringTable()
// Autolib
h.Offsets[goobj.BlkAutolib] = w.Offset()
for i := range ctxt.Imports {
ctxt.Imports[i].Write(w.Writer)
}
// Package references
h.Offsets[goobj.BlkPkgIdx] = w.Offset()
for _, pkg := range w.pkglist {
w.StringRef(pkg)
}
// File table (for DWARF and pcln generation).
h.Offsets[goobj.BlkFile] = w.Offset()
for _, f := range ctxt.PosTable.FileTable() {
w.StringRef(filepath.ToSlash(f))
}
// Symbol definitions
h.Offsets[goobj.BlkSymdef] = w.Offset()
for _, s := range ctxt.defs {
w.Sym(s)
}
// Short hashed symbol definitions
h.Offsets[goobj.BlkHashed64def] = w.Offset()
for _, s := range ctxt.hashed64defs {
w.Sym(s)
}
// Hashed symbol definitions
h.Offsets[goobj.BlkHasheddef] = w.Offset()
for _, s := range ctxt.hasheddefs {
w.Sym(s)
}
// Non-pkg symbol definitions
h.Offsets[goobj.BlkNonpkgdef] = w.Offset()
for _, s := range ctxt.nonpkgdefs {
w.Sym(s)
}
// Non-pkg symbol references
h.Offsets[goobj.BlkNonpkgref] = w.Offset()
for _, s := range ctxt.nonpkgrefs {
w.Sym(s)
}
// Referenced package symbol flags
h.Offsets[goobj.BlkRefFlags] = w.Offset()
w.refFlags()
// Hashes
h.Offsets[goobj.BlkHash64] = w.Offset()
for _, s := range ctxt.hashed64defs {
w.Hash64(s)
}
h.Offsets[goobj.BlkHash] = w.Offset()
for _, s := range ctxt.hasheddefs {
w.Hash(s)
}
// TODO: hashedrefs unused/unsupported for now
// Reloc indexes
h.Offsets[goobj.BlkRelocIdx] = w.Offset()
nreloc := uint32(0)
lists := [][]*LSym{ctxt.defs, ctxt.hashed64defs, ctxt.hasheddefs, ctxt.nonpkgdefs}
for _, list := range lists {
for _, s := range list {
w.Uint32(nreloc)
nreloc += uint32(len(s.R))
}
}
w.Uint32(nreloc)
// Symbol Info indexes
h.Offsets[goobj.BlkAuxIdx] = w.Offset()
naux := uint32(0)
for _, list := range lists {
for _, s := range list {
w.Uint32(naux)
naux += uint32(nAuxSym(s))
}
}
w.Uint32(naux)
// Data indexes
h.Offsets[goobj.BlkDataIdx] = w.Offset()
dataOff := uint32(0)
for _, list := range lists {
for _, s := range list {
w.Uint32(dataOff)
dataOff += uint32(len(s.P))
}
}
w.Uint32(dataOff)
// Relocs
h.Offsets[goobj.BlkReloc] = w.Offset()
for _, list := range lists {
for _, s := range list {
for i := range s.R {
w.Reloc(&s.R[i])
}
}
}
// Aux symbol info
h.Offsets[goobj.BlkAux] = w.Offset()
for _, list := range lists {
for _, s := range list {
w.Aux(s)
}
}
// Data
h.Offsets[goobj.BlkData] = w.Offset()
for _, list := range lists {
for _, s := range list {
w.Bytes(s.P)
}
}
// Pcdata
h.Offsets[goobj.BlkPcdata] = w.Offset()
for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
if s.Func != nil {
pc := &s.Func.Pcln
w.Bytes(pc.Pcsp.P)
w.Bytes(pc.Pcfile.P)
w.Bytes(pc.Pcline.P)
w.Bytes(pc.Pcinline.P)
for i := range pc.Pcdata {
w.Bytes(pc.Pcdata[i].P)
}
}
}
// Blocks used only by tools (objdump, nm).
// Referenced symbol names from other packages
h.Offsets[goobj.BlkRefName] = w.Offset()
w.refNames()
h.Offsets[goobj.BlkEnd] = w.Offset()
// Fix up block offsets in the header
end := start + int64(w.Offset())
b.MustSeek(start, 0)
h.Write(w.Writer)
b.MustSeek(end, 0)
}
type writer struct {
*goobj.Writer
ctxt *Link
pkgpath string // the package import path (escaped), "" if unknown
pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
}
// prepare package index list
func (w *writer) init() {
w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
w.pkglist[0] = "" // dummy invalid package for index 0
for pkg, i := range w.ctxt.pkgIdx {
w.pkglist[i] = pkg
}
}
func (w *writer) StringTable() {
w.AddString("")
for _, p := range w.ctxt.Imports {
w.AddString(p.Pkg)
}
for _, pkg := range w.pkglist {
w.AddString(pkg)
}
w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
// TODO: this includes references of indexed symbols from other packages,
// for which the linker doesn't need the name. Consider moving them to
// a separate block (for tools only).
if w.pkgpath != "" {
s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
}
// Don't put names of builtins into the string table (to save
// space).
if s.PkgIdx == goobj.PkgIdxBuiltin {
return
}
w.AddString(s.Name)
})
// All filenames are in the postable.
for _, f := range w.ctxt.PosTable.FileTable() {
w.AddString(filepath.ToSlash(f))
}
}
func (w *writer) Sym(s *LSym) {
abi := uint16(s.ABI())
if s.Static() {
abi = goobj.SymABIstatic
}
flag := uint8(0)
if s.DuplicateOK() {
flag |= goobj.SymFlagDupok
}
if s.Local() {
flag |= goobj.SymFlagLocal
}
if s.MakeTypelink() {
flag |= goobj.SymFlagTypelink
}
if s.Leaf() {
flag |= goobj.SymFlagLeaf
}
if s.NoSplit() {
flag |= goobj.SymFlagNoSplit
}
if s.ReflectMethod() {
flag |= goobj.SymFlagReflectMethod
}
if s.TopFrame() {
flag |= goobj.SymFlagTopFrame
}
if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
flag |= goobj.SymFlagGoType
}
flag2 := uint8(0)
if s.UsedInIface() {
flag2 |= goobj.SymFlagUsedInIface
}
if strings.HasPrefix(s.Name, "go.itab.") && s.Type == objabi.SRODATA {
flag2 |= goobj.SymFlagItab
}
name := s.Name
if strings.HasPrefix(name, "gofile..") {
name = filepath.ToSlash(name)
}
var align uint32
if s.Func != nil {
align = uint32(s.Func.Align)
}
if s.ContentAddressable() {
// We generally assume data symbols are natually aligned,
// except for strings. If we dedup a string symbol and a
// non-string symbol with the same content, we should keep
// the largest alignment.
// TODO: maybe the compiler could set the alignment for all
// data symbols more carefully.
if s.Size != 0 && !strings.HasPrefix(s.Name, "go.string.") {
switch {
case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
align = 8
case s.Size%4 == 0:
align = 4
case s.Size%2 == 0:
align = 2
}
// don't bother setting align to 1.
}
}
var o goobj.Sym
o.SetName(name, w.Writer)
o.SetABI(abi)
o.SetType(uint8(s.Type))
o.SetFlag(flag)
o.SetFlag2(flag2)
o.SetSiz(uint32(s.Size))
o.SetAlign(align)
o.Write(w.Writer)
}
func (w *writer) Hash64(s *LSym) {
if !s.ContentAddressable() || len(s.R) != 0 {
panic("Hash of non-content-addresable symbol")
}
b := contentHash64(s)
w.Bytes(b[:])
}
func (w *writer) Hash(s *LSym) {
if !s.ContentAddressable() {
panic("Hash of non-content-addresable symbol")
}
b := w.contentHash(s)
w.Bytes(b[:])
}
func contentHash64(s *LSym) goobj.Hash64Type {
var b goobj.Hash64Type
copy(b[:], s.P)
return b
}
// Compute the content hash for a content-addressable symbol.
// We build a content hash based on its content and relocations.
// Depending on the category of the referenced symbol, we choose
// different hash algorithms such that the hash is globally
// consistent.
// - For referenced content-addressable symbol, its content hash
// is globally consistent.
// - For package symbol and builtin symbol, its local index is
// globally consistent.
// - For non-package symbol, its fully-expanded name is globally
// consistent. For now, we require we know the current package
// path so we can always expand symbol names. (Otherwise,
// symbols with relocations are not considered hashable.)
//
// For now, we assume there is no circular dependencies among
// hashed symbols.
func (w *writer) contentHash(s *LSym) goobj.HashType {
h := sha1.New()
// The compiler trims trailing zeros _sometimes_. We just do
// it always.
h.Write(bytes.TrimRight(s.P, "\x00"))
var tmp [14]byte
for i := range s.R {
r := &s.R[i]
binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
tmp[4] = r.Siz
tmp[5] = uint8(r.Type)
binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
h.Write(tmp[:])
rs := r.Sym
switch rs.PkgIdx {
case goobj.PkgIdxHashed64:
h.Write([]byte{0})
t := contentHash64(rs)
h.Write(t[:])
case goobj.PkgIdxHashed:
h.Write([]byte{1})
t := w.contentHash(rs)
h.Write(t[:])
case goobj.PkgIdxNone:
h.Write([]byte{2})
io.WriteString(h, rs.Name) // name is already expanded at this point
case goobj.PkgIdxBuiltin:
h.Write([]byte{3})
binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
h.Write(tmp[:4])
case goobj.PkgIdxSelf:
io.WriteString(h, w.pkgpath)
binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
h.Write(tmp[:4])
default:
io.WriteString(h, rs.Pkg)
binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
h.Write(tmp[:4])
}
}
var b goobj.HashType
copy(b[:], h.Sum(nil))
return b
}
func makeSymRef(s *LSym) goobj.SymRef {
if s == nil {
return goobj.SymRef{}
}
if s.PkgIdx == 0 || !s.Indexed() {
fmt.Printf("unindexed symbol reference: %v\n", s)
panic("unindexed symbol reference")
}
return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
}
func (w *writer) Reloc(r *Reloc) {
var o goobj.Reloc
o.SetOff(r.Off)
o.SetSiz(r.Siz)
o.SetType(uint8(r.Type))
o.SetAdd(r.Add)
o.SetSym(makeSymRef(r.Sym))
o.Write(w.Writer)
}
func (w *writer) aux1(typ uint8, rs *LSym) {
var o goobj.Aux
o.SetType(typ)
o.SetSym(makeSymRef(rs))
o.Write(w.Writer)
}
func (w *writer) Aux(s *LSym) {
if s.Gotype != nil {
w.aux1(goobj.AuxGotype, s.Gotype)
}
if s.Func != nil {
w.aux1(goobj.AuxFuncInfo, s.Func.FuncInfoSym)
for _, d := range s.Func.Pcln.Funcdata {
w.aux1(goobj.AuxFuncdata, d)
}
if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
w.aux1(goobj.AuxDwarfInfo, s.Func.dwarfInfoSym)
}
if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
w.aux1(goobj.AuxDwarfLoc, s.Func.dwarfLocSym)
}
if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
w.aux1(goobj.AuxDwarfRanges, s.Func.dwarfRangesSym)
}
if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
w.aux1(goobj.AuxDwarfLines, s.Func.dwarfDebugLinesSym)
}
}
}
// Emits flags of referenced indexed symbols.
func (w *writer) refFlags() {
seen := make(map[*LSym]bool)
w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
switch rs.PkgIdx {
case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
return
case goobj.PkgIdxInvalid:
panic("unindexed symbol reference")
}
if seen[rs] {
return
}
seen[rs] = true
symref := makeSymRef(rs)
flag2 := uint8(0)
if rs.UsedInIface() {
flag2 |= goobj.SymFlagUsedInIface
}
if flag2 == 0 {
return // no need to write zero flags
}
var o goobj.RefFlags
o.SetSym(symref)
o.SetFlag2(flag2)
o.Write(w.Writer)
})
}
// Emits names of referenced indexed symbols, used by tools (objdump, nm)
// only.
func (w *writer) refNames() {
seen := make(map[*LSym]bool)
w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
switch rs.PkgIdx {
case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf: // not an external indexed reference
return
case goobj.PkgIdxInvalid:
panic("unindexed symbol reference")
}
if seen[rs] {
return
}
seen[rs] = true
symref := makeSymRef(rs)
var o goobj.RefName
o.SetSym(symref)
o.SetName(rs.Name, w.Writer)
o.Write(w.Writer)
})
// TODO: output in sorted order?
// Currently tools (cmd/internal/goobj package) doesn't use mmap,
// and it just read it into a map in memory upfront. If it uses
// mmap, if the output is sorted, it probably could avoid reading
// into memory and just do lookups in the mmap'd object file.
}
// return the number of aux symbols s have.
func nAuxSym(s *LSym) int {
n := 0
if s.Gotype != nil {
n++
}
if s.Func != nil {
// FuncInfo is an aux symbol, each Funcdata is an aux symbol
n += 1 + len(s.Func.Pcln.Funcdata)
if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
n++
}
if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
n++
}
if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
n++
}
if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
n++
}
}
return n
}
// generate symbols for FuncInfo.
func genFuncInfoSyms(ctxt *Link) {
infosyms := make([]*LSym, 0, len(ctxt.Text))
var pcdataoff uint32
var b bytes.Buffer
symidx := int32(len(ctxt.defs))
for _, s := range ctxt.Text {
if s.Func == nil {
continue
}
o := goobj.FuncInfo{
Args: uint32(s.Func.Args),
Locals: uint32(s.Func.Locals),
FuncID: objabi.FuncID(s.Func.FuncID),
}
pc := &s.Func.Pcln
o.Pcsp = pcdataoff
pcdataoff += uint32(len(pc.Pcsp.P))
o.Pcfile = pcdataoff
pcdataoff += uint32(len(pc.Pcfile.P))
o.Pcline = pcdataoff
pcdataoff += uint32(len(pc.Pcline.P))
o.Pcinline = pcdataoff
pcdataoff += uint32(len(pc.Pcinline.P))
o.Pcdata = make([]uint32, len(pc.Pcdata))
for i, pcd := range pc.Pcdata {
o.Pcdata[i] = pcdataoff
pcdataoff += uint32(len(pcd.P))
}
o.PcdataEnd = pcdataoff
o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
for i, x := range pc.Funcdataoff {
o.Funcdataoff[i] = uint32(x)
}
i := 0
o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
for f := range pc.UsedFiles {
o.File[i] = f
i++
}
sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
for i, inl := range pc.InlTree.nodes {
f, l := getFileIndexAndLine(ctxt, inl.Pos)
o.InlTree[i] = goobj.InlTreeNode{
Parent: int32(inl.Parent),
File: goobj.CUFileIndex(f),
Line: l,
Func: makeSymRef(inl.Func),
ParentPC: inl.ParentPC,
}
}
o.Write(&b)
isym := &LSym{
Type: objabi.SDATA, // for now, I don't think it matters
PkgIdx: goobj.PkgIdxSelf,
SymIdx: symidx,
P: append([]byte(nil), b.Bytes()...),
}
isym.Set(AttrIndexed, true)
symidx++
infosyms = append(infosyms, isym)
s.Func.FuncInfoSym = isym
b.Reset()
dwsyms := []*LSym{s.Func.dwarfRangesSym, s.Func.dwarfLocSym, s.Func.dwarfDebugLinesSym, s.Func.dwarfInfoSym}
for _, s := range dwsyms {
if s == nil || s.Size == 0 {
continue
}
s.PkgIdx = goobj.PkgIdxSelf
s.SymIdx = symidx
s.Set(AttrIndexed, true)
symidx++
infosyms = append(infosyms, s)
}
}
ctxt.defs = append(ctxt.defs, infosyms...)
}
// debugDumpAux is a dumper for selected aux symbols.
func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
// Most aux symbols (ex: funcdata) are not interesting--
// pick out just the DWARF ones for now.
if aux.Type != objabi.SDWARFLOC &&
aux.Type != objabi.SDWARFFCN &&
aux.Type != objabi.SDWARFABSFCN &&
aux.Type != objabi.SDWARFLINES &&
aux.Type != objabi.SDWARFRANGE {
return
}
ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
}
func debugAsmEmit(ctxt *Link) {
if ctxt.Debugasm > 0 {
ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
if ctxt.Debugasm > 1 {
fn := func(par *LSym, aux *LSym) {
writeAuxSymDebug(ctxt, par, aux)
}
ctxt.traverseAuxSyms(traverseAux, fn)
}
}
}
func (ctxt *Link) writeSymDebug(s *LSym) {
ctxt.writeSymDebugNamed(s, s.Name)
}
func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
ver := ""
if ctxt.Debugasm > 1 {
ver = fmt.Sprintf("<%d>", s.ABI())
}
fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
if s.Type != 0 {
fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
}
if s.Static() {
fmt.Fprint(ctxt.Bso, "static ")
}
if s.DuplicateOK() {
fmt.Fprintf(ctxt.Bso, "dupok ")
}
if s.CFunc() {
fmt.Fprintf(ctxt.Bso, "cfunc ")
}
if s.NoSplit() {
fmt.Fprintf(ctxt.Bso, "nosplit ")
}
if s.TopFrame() {
fmt.Fprintf(ctxt.Bso, "topframe ")
}
fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
if s.Type == objabi.STEXT {
fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(s.Func.Args), uint64(s.Func.Locals), uint64(s.Func.FuncID))
if s.Leaf() {
fmt.Fprintf(ctxt.Bso, " leaf")
}
}
fmt.Fprintf(ctxt.Bso, "\n")
if s.Type == objabi.STEXT {
for p := s.Func.Text; p != nil; p = p.Link {
fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
if ctxt.Debugasm > 1 {
io.WriteString(ctxt.Bso, p.String())
} else {
p.InnermostString(ctxt.Bso)
}
fmt.Fprintln(ctxt.Bso)
}
}
for i := 0; i < len(s.P); i += 16 {
fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
j := i
for ; j < i+16 && j < len(s.P); j++ {
fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
}
for ; j < i+16; j++ {
fmt.Fprintf(ctxt.Bso, " ")
}
fmt.Fprintf(ctxt.Bso, " ")
for j = i; j < i+16 && j < len(s.P); j++ {
c := int(s.P[j])
b := byte('.')
if ' ' <= c && c <= 0x7e {
b = byte(c)
}
ctxt.Bso.WriteByte(b)
}
fmt.Fprintf(ctxt.Bso, "\n")
}
sort.Sort(relocByOff(s.R)) // generate stable output
for _, r := range s.R {
name := ""
ver := ""
if r.Sym != nil {
name = r.Sym.Name
if ctxt.Debugasm > 1 {
ver = fmt.Sprintf("<%d>", s.ABI())
}
} else if r.Type == objabi.R_TLS_LE {
name = "TLS"
}
if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%x\n", int(r.Off), r.Siz, r.Type, name, ver, uint64(r.Add))
} else {
fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
}
}
}
// relocByOff sorts relocations by their offsets.
type relocByOff []Reloc
func (x relocByOff) Len() int { return len(x) }
func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }

View File

@ -0,0 +1,176 @@
// Inferno utils/6l/pass.c
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/pass.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package obj
// Code and data passes.
// brloop returns the ultimate destination of the series of unconditional jumps beginning at p.
// In the case of an infinite loop, brloop returns nil.
func brloop(p *Prog) *Prog {
c := 0
for q := p; q != nil; q = q.To.Target() {
if q.As != AJMP || q.To.Target() == nil {
return q
}
c++
if c >= 5000 {
// infinite loop
return nil
}
}
panic("unreachable")
}
// checkaddr checks that a has an expected encoding, especially TYPE_CONST vs TYPE_ADDR.
func checkaddr(ctxt *Link, p *Prog, a *Addr) {
switch a.Type {
case TYPE_NONE, TYPE_REGREG2, TYPE_REGLIST:
return
case TYPE_BRANCH, TYPE_TEXTSIZE:
if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 {
break
}
return
case TYPE_MEM:
return
case TYPE_CONST:
// TODO(rsc): After fixing SHRQ, check a.Index != 0 too.
if a.Name != 0 || a.Sym != nil || a.Reg != 0 {
ctxt.Diag("argument is TYPE_CONST, should be TYPE_ADDR, in %v", p)
return
}
if a.Reg != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
break
}
return
case TYPE_FCONST, TYPE_SCONST:
if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Offset != 0 || a.Sym != nil {
break
}
return
case TYPE_REG:
// TODO(rsc): After fixing PINSRQ, check a.Offset != 0 too.
// TODO(rsc): After fixing SHRQ, check a.Index != 0 too.
if a.Scale != 0 || a.Name != 0 || a.Sym != nil {
break
}
return
case TYPE_ADDR:
if a.Val != nil {
break
}
if a.Reg == 0 && a.Index == 0 && a.Scale == 0 && a.Name == 0 && a.Sym == nil {
ctxt.Diag("argument is TYPE_ADDR, should be TYPE_CONST, in %v", p)
}
return
case TYPE_SHIFT, TYPE_REGREG:
if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
break
}
return
case TYPE_INDIR:
// Expect sym and name to be set, nothing else.
// Technically more is allowed, but this is only used for *name(SB).
if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name == 0 || a.Offset != 0 || a.Sym == nil || a.Val != nil {
break
}
return
}
ctxt.Diag("invalid encoding for argument %v", p)
}
func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
for p := sym.Func.Text; p != nil; p = p.Link {
checkaddr(ctxt, p, &p.From)
if p.GetFrom3() != nil {
checkaddr(ctxt, p, p.GetFrom3())
}
checkaddr(ctxt, p, &p.To)
if ctxt.Arch.Progedit != nil {
ctxt.Arch.Progedit(ctxt, p, newprog)
}
if p.To.Type != TYPE_BRANCH {
continue
}
if p.To.Val != nil {
continue
}
if p.To.Sym != nil {
continue
}
q := sym.Func.Text
for q != nil && p.To.Offset != q.Pc {
if q.Forwd != nil && p.To.Offset >= q.Forwd.Pc {
q = q.Forwd
} else {
q = q.Link
}
}
if q == nil {
name := "<nil>"
if p.To.Sym != nil {
name = p.To.Sym.Name
}
ctxt.Diag("branch out of range (%#x)\n%v [%s]", uint32(p.To.Offset), p, name)
p.To.Type = TYPE_NONE
}
p.To.SetTarget(q)
}
if !ctxt.Flag_optimize {
return
}
// Collapse series of jumps to jumps.
for p := sym.Func.Text; p != nil; p = p.Link {
if p.To.Target() == nil {
continue
}
p.To.SetTarget(brloop(p.To.Target()))
if p.To.Target() != nil && p.To.Type == TYPE_BRANCH {
p.To.Offset = p.To.Target().Pc
}
}
}

View File

@ -0,0 +1,413 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package obj
import (
"github.com/twitchyliquid64/golang-asm/goobj"
"encoding/binary"
"log"
)
// funcpctab writes to dst a pc-value table mapping the code in func to the values
// returned by valfunc parameterized by arg. The invocation of valfunc to update the
// current value is, for each p,
//
// val = valfunc(func, val, p, 0, arg);
// record val as value at p->pc;
// val = valfunc(func, val, p, 1, arg);
//
// where func is the function, val is the current value, p is the instruction being
// considered, and arg can be used to further parameterize valfunc.
func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*Link, *LSym, int32, *Prog, int32, interface{}) int32, arg interface{}) {
dbg := desc == ctxt.Debugpcln
dst.P = dst.P[:0]
if dbg {
ctxt.Logf("funcpctab %s [valfunc=%s]\n", func_.Name, desc)
}
val := int32(-1)
oldval := val
if func_.Func.Text == nil {
return
}
pc := func_.Func.Text.Pc
if dbg {
ctxt.Logf("%6x %6d %v\n", uint64(pc), val, func_.Func.Text)
}
buf := make([]byte, binary.MaxVarintLen32)
started := false
for p := func_.Func.Text; p != nil; p = p.Link {
// Update val. If it's not changing, keep going.
val = valfunc(ctxt, func_, val, p, 0, arg)
if val == oldval && started {
val = valfunc(ctxt, func_, val, p, 1, arg)
if dbg {
ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
}
continue
}
// If the pc of the next instruction is the same as the
// pc of this instruction, this instruction is not a real
// instruction. Keep going, so that we only emit a delta
// for a true instruction boundary in the program.
if p.Link != nil && p.Link.Pc == p.Pc {
val = valfunc(ctxt, func_, val, p, 1, arg)
if dbg {
ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
}
continue
}
// The table is a sequence of (value, pc) pairs, where each
// pair states that the given value is in effect from the current position
// up to the given pc, which becomes the new current position.
// To generate the table as we scan over the program instructions,
// we emit a "(value" when pc == func->value, and then
// each time we observe a change in value we emit ", pc) (value".
// When the scan is over, we emit the closing ", pc)".
//
// The table is delta-encoded. The value deltas are signed and
// transmitted in zig-zag form, where a complement bit is placed in bit 0,
// and the pc deltas are unsigned. Both kinds of deltas are sent
// as variable-length little-endian base-128 integers,
// where the 0x80 bit indicates that the integer continues.
if dbg {
ctxt.Logf("%6x %6d %v\n", uint64(p.Pc), val, p)
}
if started {
pcdelta := (p.Pc - pc) / int64(ctxt.Arch.MinLC)
n := binary.PutUvarint(buf, uint64(pcdelta))
dst.P = append(dst.P, buf[:n]...)
pc = p.Pc
}
delta := val - oldval
n := binary.PutVarint(buf, int64(delta))
dst.P = append(dst.P, buf[:n]...)
oldval = val
started = true
val = valfunc(ctxt, func_, val, p, 1, arg)
}
if started {
if dbg {
ctxt.Logf("%6x done\n", uint64(func_.Func.Text.Pc+func_.Size))
}
v := (func_.Size - pc) / int64(ctxt.Arch.MinLC)
if v < 0 {
ctxt.Diag("negative pc offset: %v", v)
}
n := binary.PutUvarint(buf, uint64(v))
dst.P = append(dst.P, buf[:n]...)
// add terminating varint-encoded 0, which is just 0
dst.P = append(dst.P, 0)
}
if dbg {
ctxt.Logf("wrote %d bytes to %p\n", len(dst.P), dst)
for _, p := range dst.P {
ctxt.Logf(" %02x", p)
}
ctxt.Logf("\n")
}
}
// pctofileline computes either the file number (arg == 0)
// or the line number (arg == 1) to use at p.
// Because p.Pos applies to p, phase == 0 (before p)
// takes care of the update.
func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
if p.As == ATEXT || p.As == ANOP || p.Pos.Line() == 0 || phase == 1 {
return oldval
}
f, l := getFileIndexAndLine(ctxt, p.Pos)
if arg == nil {
return l
}
pcln := arg.(*Pcln)
pcln.UsedFiles[goobj.CUFileIndex(f)] = struct{}{}
return int32(f)
}
// pcinlineState holds the state used to create a function's inlining
// tree and the PC-value table that maps PCs to nodes in that tree.
type pcinlineState struct {
globalToLocal map[int]int
localTree InlTree
}
// addBranch adds a branch from the global inlining tree in ctxt to
// the function's local inlining tree, returning the index in the local tree.
func (s *pcinlineState) addBranch(ctxt *Link, globalIndex int) int {
if globalIndex < 0 {
return -1
}
localIndex, ok := s.globalToLocal[globalIndex]
if ok {
return localIndex
}
// Since tracebacks don't include column information, we could
// use one node for multiple calls of the same function on the
// same line (e.g., f(x) + f(y)). For now, we use one node for
// each inlined call.
call := ctxt.InlTree.nodes[globalIndex]
call.Parent = s.addBranch(ctxt, call.Parent)
localIndex = len(s.localTree.nodes)
s.localTree.nodes = append(s.localTree.nodes, call)
s.globalToLocal[globalIndex] = localIndex
return localIndex
}
func (s *pcinlineState) setParentPC(ctxt *Link, globalIndex int, pc int32) {
localIndex, ok := s.globalToLocal[globalIndex]
if !ok {
// We know where to unwind to when we need to unwind a body identified
// by globalIndex. But there may be no instructions generated by that
// body (it's empty, or its instructions were CSEd with other things, etc.).
// In that case, we don't need an unwind entry.
// TODO: is this really right? Seems to happen a whole lot...
return
}
s.localTree.setParentPC(localIndex, pc)
}
// pctoinline computes the index into the local inlining tree to use at p.
// If p is not the result of inlining, pctoinline returns -1. Because p.Pos
// applies to p, phase == 0 (before p) takes care of the update.
func (s *pcinlineState) pctoinline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
if phase == 1 {
return oldval
}
posBase := ctxt.PosTable.Pos(p.Pos).Base()
if posBase == nil {
return -1
}
globalIndex := posBase.InliningIndex()
if globalIndex < 0 {
return -1
}
if s.globalToLocal == nil {
s.globalToLocal = make(map[int]int)
}
return int32(s.addBranch(ctxt, globalIndex))
}
// pctospadj computes the sp adjustment in effect.
// It is oldval plus any adjustment made by p itself.
// The adjustment by p takes effect only after p, so we
// apply the change during phase == 1.
func pctospadj(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
if oldval == -1 { // starting
oldval = 0
}
if phase == 0 {
return oldval
}
if oldval+p.Spadj < -10000 || oldval+p.Spadj > 1100000000 {
ctxt.Diag("overflow in spadj: %d + %d = %d", oldval, p.Spadj, oldval+p.Spadj)
ctxt.DiagFlush()
log.Fatalf("bad code")
}
return oldval + p.Spadj
}
// pctopcdata computes the pcdata value in effect at p.
// A PCDATA instruction sets the value in effect at future
// non-PCDATA instructions.
// Since PCDATA instructions have no width in the final code,
// it does not matter which phase we use for the update.
func pctopcdata(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
if phase == 0 || p.As != APCDATA || p.From.Offset != int64(arg.(uint32)) {
return oldval
}
if int64(int32(p.To.Offset)) != p.To.Offset {
ctxt.Diag("overflow in PCDATA instruction: %v", p)
ctxt.DiagFlush()
log.Fatalf("bad code")
}
return int32(p.To.Offset)
}
func linkpcln(ctxt *Link, cursym *LSym) {
pcln := &cursym.Func.Pcln
pcln.UsedFiles = make(map[goobj.CUFileIndex]struct{})
npcdata := 0
nfuncdata := 0
for p := cursym.Func.Text; p != nil; p = p.Link {
// Find the highest ID of any used PCDATA table. This ignores PCDATA table
// that consist entirely of "-1", since that's the assumed default value.
// From.Offset is table ID
// To.Offset is data
if p.As == APCDATA && p.From.Offset >= int64(npcdata) && p.To.Offset != -1 { // ignore -1 as we start at -1, if we only see -1, nothing changed
npcdata = int(p.From.Offset + 1)
}
// Find the highest ID of any FUNCDATA table.
// From.Offset is table ID
if p.As == AFUNCDATA && p.From.Offset >= int64(nfuncdata) {
nfuncdata = int(p.From.Offset + 1)
}
}
pcln.Pcdata = make([]Pcdata, npcdata)
pcln.Pcdata = pcln.Pcdata[:npcdata]
pcln.Funcdata = make([]*LSym, nfuncdata)
pcln.Funcdataoff = make([]int64, nfuncdata)
pcln.Funcdataoff = pcln.Funcdataoff[:nfuncdata]
funcpctab(ctxt, &pcln.Pcsp, cursym, "pctospadj", pctospadj, nil)
funcpctab(ctxt, &pcln.Pcfile, cursym, "pctofile", pctofileline, pcln)
funcpctab(ctxt, &pcln.Pcline, cursym, "pctoline", pctofileline, nil)
// Check that all the Progs used as inline markers are still reachable.
// See issue #40473.
inlMarkProgs := make(map[*Prog]struct{}, len(cursym.Func.InlMarks))
for _, inlMark := range cursym.Func.InlMarks {
inlMarkProgs[inlMark.p] = struct{}{}
}
for p := cursym.Func.Text; p != nil; p = p.Link {
if _, ok := inlMarkProgs[p]; ok {
delete(inlMarkProgs, p)
}
}
if len(inlMarkProgs) > 0 {
ctxt.Diag("one or more instructions used as inline markers are no longer reachable")
}
pcinlineState := new(pcinlineState)
funcpctab(ctxt, &pcln.Pcinline, cursym, "pctoinline", pcinlineState.pctoinline, nil)
for _, inlMark := range cursym.Func.InlMarks {
pcinlineState.setParentPC(ctxt, int(inlMark.id), int32(inlMark.p.Pc))
}
pcln.InlTree = pcinlineState.localTree
if ctxt.Debugpcln == "pctoinline" && len(pcln.InlTree.nodes) > 0 {
ctxt.Logf("-- inlining tree for %s:\n", cursym)
dumpInlTree(ctxt, pcln.InlTree)
ctxt.Logf("--\n")
}
// tabulate which pc and func data we have.
havepc := make([]uint32, (npcdata+31)/32)
havefunc := make([]uint32, (nfuncdata+31)/32)
for p := cursym.Func.Text; p != nil; p = p.Link {
if p.As == AFUNCDATA {
if (havefunc[p.From.Offset/32]>>uint64(p.From.Offset%32))&1 != 0 {
ctxt.Diag("multiple definitions for FUNCDATA $%d", p.From.Offset)
}
havefunc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
}
if p.As == APCDATA && p.To.Offset != -1 {
havepc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
}
}
// pcdata.
for i := 0; i < npcdata; i++ {
if (havepc[i/32]>>uint(i%32))&1 == 0 {
continue
}
funcpctab(ctxt, &pcln.Pcdata[i], cursym, "pctopcdata", pctopcdata, interface{}(uint32(i)))
}
// funcdata
if nfuncdata > 0 {
for p := cursym.Func.Text; p != nil; p = p.Link {
if p.As != AFUNCDATA {
continue
}
i := int(p.From.Offset)
pcln.Funcdataoff[i] = p.To.Offset
if p.To.Type != TYPE_CONST {
// TODO: Dedup.
//funcdata_bytes += p->to.sym->size;
pcln.Funcdata[i] = p.To.Sym
}
}
}
}
// PCIter iterates over encoded pcdata tables.
type PCIter struct {
p []byte
PC uint32
NextPC uint32
PCScale uint32
Value int32
start bool
Done bool
}
// newPCIter creates a PCIter with a scale factor for the PC step size.
func NewPCIter(pcScale uint32) *PCIter {
it := new(PCIter)
it.PCScale = pcScale
return it
}
// Next advances it to the Next pc.
func (it *PCIter) Next() {
it.PC = it.NextPC
if it.Done {
return
}
if len(it.p) == 0 {
it.Done = true
return
}
// Value delta
val, n := binary.Varint(it.p)
if n <= 0 {
log.Fatalf("bad Value varint in pciterNext: read %v", n)
}
it.p = it.p[n:]
if val == 0 && !it.start {
it.Done = true
return
}
it.start = false
it.Value += int32(val)
// pc delta
pc, n := binary.Uvarint(it.p)
if n <= 0 {
log.Fatalf("bad pc varint in pciterNext: read %v", n)
}
it.p = it.p[n:]
it.NextPC = it.PC + uint32(pc)*it.PCScale
}
// init prepares it to iterate over p,
// and advances it to the first pc.
func (it *PCIter) Init(p []byte) {
it.p = p
it.PC = 0
it.NextPC = 0
it.Value = -1
it.start = true
it.Done = false
it.Next()
}

View File

@ -0,0 +1,314 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package obj
import (
"github.com/twitchyliquid64/golang-asm/objabi"
"fmt"
"strings"
)
type Plist struct {
Firstpc *Prog
Curfn interface{} // holds a *gc.Node, if non-nil
}
// ProgAlloc is a function that allocates Progs.
// It is used to provide access to cached/bulk-allocated Progs to the assemblers.
type ProgAlloc func() *Prog
func Flushplist(ctxt *Link, plist *Plist, newprog ProgAlloc, myimportpath string) {
// Build list of symbols, and assign instructions to lists.
var curtext *LSym
var etext *Prog
var text []*LSym
var plink *Prog
for p := plist.Firstpc; p != nil; p = plink {
if ctxt.Debugasm > 0 && ctxt.Debugvlog {
fmt.Printf("obj: %v\n", p)
}
plink = p.Link
p.Link = nil
switch p.As {
case AEND:
continue
case ATEXT:
s := p.From.Sym
if s == nil {
// func _() { }
curtext = nil
continue
}
text = append(text, s)
etext = p
curtext = s
continue
case AFUNCDATA:
// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
if curtext == nil { // func _() {}
continue
}
if p.To.Sym.Name == "go_args_stackmap" {
if p.From.Type != TYPE_CONST || p.From.Offset != objabi.FUNCDATA_ArgsPointerMaps {
ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
}
p.To.Sym = ctxt.LookupDerived(curtext, curtext.Name+".args_stackmap")
}
}
if curtext == nil {
etext = nil
continue
}
etext.Link = p
etext = p
}
if newprog == nil {
newprog = ctxt.NewProg
}
// Add reference to Go arguments for C or assembly functions without them.
for _, s := range text {
if !strings.HasPrefix(s.Name, "\"\".") {
continue
}
found := false
for p := s.Func.Text; p != nil; p = p.Link {
if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == objabi.FUNCDATA_ArgsPointerMaps {
found = true
break
}
}
if !found {
p := Appendp(s.Func.Text, newprog)
p.As = AFUNCDATA
p.From.Type = TYPE_CONST
p.From.Offset = objabi.FUNCDATA_ArgsPointerMaps
p.To.Type = TYPE_MEM
p.To.Name = NAME_EXTERN
p.To.Sym = ctxt.LookupDerived(s, s.Name+".args_stackmap")
}
}
// Turn functions into machine code images.
for _, s := range text {
mkfwd(s)
linkpatch(ctxt, s, newprog)
ctxt.Arch.Preprocess(ctxt, s, newprog)
ctxt.Arch.Assemble(ctxt, s, newprog)
if ctxt.Errors > 0 {
continue
}
linkpcln(ctxt, s)
if myimportpath != "" {
ctxt.populateDWARF(plist.Curfn, s, myimportpath)
}
}
}
func (ctxt *Link) InitTextSym(s *LSym, flag int) {
if s == nil {
// func _() { }
return
}
if s.Func != nil {
ctxt.Diag("InitTextSym double init for %s", s.Name)
}
s.Func = new(FuncInfo)
if s.OnList() {
ctxt.Diag("symbol %s listed multiple times", s.Name)
}
name := strings.Replace(s.Name, "\"\"", ctxt.Pkgpath, -1)
s.Func.FuncID = objabi.GetFuncID(name, flag&WRAPPER != 0)
s.Set(AttrOnList, true)
s.Set(AttrDuplicateOK, flag&DUPOK != 0)
s.Set(AttrNoSplit, flag&NOSPLIT != 0)
s.Set(AttrReflectMethod, flag&REFLECTMETHOD != 0)
s.Set(AttrWrapper, flag&WRAPPER != 0)
s.Set(AttrNeedCtxt, flag&NEEDCTXT != 0)
s.Set(AttrNoFrame, flag&NOFRAME != 0)
s.Set(AttrTopFrame, flag&TOPFRAME != 0)
s.Type = objabi.STEXT
ctxt.Text = append(ctxt.Text, s)
// Set up DWARF entries for s
ctxt.dwarfSym(s)
}
func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
if s.OnList() {
ctxt.Diag("symbol %s listed multiple times", s.Name)
}
s.Set(AttrOnList, true)
ctxt.Data = append(ctxt.Data, s)
s.Size = size
if s.Type == 0 {
s.Type = objabi.SBSS
}
if flag&DUPOK != 0 {
s.Set(AttrDuplicateOK, true)
}
if flag&RODATA != 0 {
s.Type = objabi.SRODATA
} else if flag&NOPTR != 0 {
if s.Type == objabi.SDATA {
s.Type = objabi.SNOPTRDATA
} else {
s.Type = objabi.SNOPTRBSS
}
} else if flag&TLSBSS != 0 {
s.Type = objabi.STLSBSS
}
if strings.HasPrefix(s.Name, "\"\"."+StaticNamePref) {
s.Set(AttrStatic, true)
}
}
// EmitEntryLiveness generates PCDATA Progs after p to switch to the
// liveness map active at the entry of function s. It returns the last
// Prog generated.
func (ctxt *Link) EmitEntryLiveness(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := ctxt.EmitEntryStackMap(s, p, newprog)
pcdata = ctxt.EmitEntryRegMap(s, pcdata, newprog)
return pcdata
}
// Similar to EmitEntryLiveness, but just emit stack map.
func (ctxt *Link) EmitEntryStackMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
pcdata.Pos = s.Func.Text.Pos
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_StackMapIndex
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
return pcdata
}
// Similar to EmitEntryLiveness, but just emit register map.
func (ctxt *Link) EmitEntryRegMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
pcdata.Pos = s.Func.Text.Pos
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_RegMapIndex
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = -1
return pcdata
}
// StartUnsafePoint generates PCDATA Progs after p to mark the
// beginning of an unsafe point. The unsafe point starts immediately
// after p.
// It returns the last Prog generated.
func (ctxt *Link) StartUnsafePoint(p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_RegMapIndex
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = objabi.PCDATA_RegMapUnsafe
return pcdata
}
// EndUnsafePoint generates PCDATA Progs after p to mark the end of an
// unsafe point, restoring the register map index to oldval.
// The unsafe point ends right after p.
// It returns the last Prog generated.
func (ctxt *Link) EndUnsafePoint(p *Prog, newprog ProgAlloc, oldval int64) *Prog {
pcdata := Appendp(p, newprog)
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_RegMapIndex
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = oldval
return pcdata
}
// MarkUnsafePoints inserts PCDATAs to mark nonpreemptible and restartable
// instruction sequences, based on isUnsafePoint and isRestartable predicate.
// p0 is the start of the instruction stream.
// isUnsafePoint(p) returns true if p is not safe for async preemption.
// isRestartable(p) returns true if we can restart at the start of p (this Prog)
// upon async preemption. (Currently multi-Prog restartable sequence is not
// supported.)
// isRestartable can be nil. In this case it is treated as always returning false.
// If isUnsafePoint(p) and isRestartable(p) are both true, it is treated as
// an unsafe point.
func MarkUnsafePoints(ctxt *Link, p0 *Prog, newprog ProgAlloc, isUnsafePoint, isRestartable func(*Prog) bool) {
if isRestartable == nil {
// Default implementation: nothing is restartable.
isRestartable = func(*Prog) bool { return false }
}
prev := p0
prevPcdata := int64(-1) // entry PC data value
prevRestart := int64(0)
for p := prev.Link; p != nil; p, prev = p.Link, p {
if p.As == APCDATA && p.From.Offset == objabi.PCDATA_RegMapIndex {
prevPcdata = p.To.Offset
continue
}
if prevPcdata == objabi.PCDATA_RegMapUnsafe {
continue // already unsafe
}
if isUnsafePoint(p) {
q := ctxt.StartUnsafePoint(prev, newprog)
q.Pc = p.Pc
q.Link = p
// Advance to the end of unsafe point.
for p.Link != nil && isUnsafePoint(p.Link) {
p = p.Link
}
if p.Link == nil {
break // Reached the end, don't bother marking the end
}
p = ctxt.EndUnsafePoint(p, newprog, prevPcdata)
p.Pc = p.Link.Pc
continue
}
if isRestartable(p) {
val := int64(objabi.PCDATA_Restart1)
if val == prevRestart {
val = objabi.PCDATA_Restart2
}
prevRestart = val
q := Appendp(prev, newprog)
q.As = APCDATA
q.From.Type = TYPE_CONST
q.From.Offset = objabi.PCDATA_RegMapIndex
q.To.Type = TYPE_CONST
q.To.Offset = val
q.Pc = p.Pc
q.Link = p
if p.Link == nil {
break // Reached the end, don't bother marking the end
}
if isRestartable(p.Link) {
// Next Prog is also restartable. No need to mark the end
// of this sequence. We'll just go ahead mark the next one.
continue
}
p = Appendp(p, newprog)
p.As = APCDATA
p.From.Type = TYPE_CONST
p.From.Offset = objabi.PCDATA_RegMapIndex
p.To.Type = TYPE_CONST
p.To.Offset = prevPcdata
p.Pc = p.Link.Pc
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,615 @@
// Code generated by stringer -i a.out.go -o anames.go -p ppc64; DO NOT EDIT.
package ppc64
import "github.com/twitchyliquid64/golang-asm/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "ADD",
"ADDCC",
"ADDIS",
"ADDV",
"ADDVCC",
"ADDC",
"ADDCCC",
"ADDCV",
"ADDCVCC",
"ADDME",
"ADDMECC",
"ADDMEVCC",
"ADDMEV",
"ADDE",
"ADDECC",
"ADDEVCC",
"ADDEV",
"ADDZE",
"ADDZECC",
"ADDZEVCC",
"ADDZEV",
"ADDEX",
"AND",
"ANDCC",
"ANDN",
"ANDNCC",
"ANDISCC",
"BC",
"BCL",
"BEQ",
"BGE",
"BGT",
"BLE",
"BLT",
"BNE",
"BVC",
"BVS",
"CMP",
"CMPU",
"CMPEQB",
"CNTLZW",
"CNTLZWCC",
"CRAND",
"CRANDN",
"CREQV",
"CRNAND",
"CRNOR",
"CROR",
"CRORN",
"CRXOR",
"DIVW",
"DIVWCC",
"DIVWVCC",
"DIVWV",
"DIVWU",
"DIVWUCC",
"DIVWUVCC",
"DIVWUV",
"MODUD",
"MODUW",
"MODSD",
"MODSW",
"EQV",
"EQVCC",
"EXTSB",
"EXTSBCC",
"EXTSH",
"EXTSHCC",
"FABS",
"FABSCC",
"FADD",
"FADDCC",
"FADDS",
"FADDSCC",
"FCMPO",
"FCMPU",
"FCTIW",
"FCTIWCC",
"FCTIWZ",
"FCTIWZCC",
"FDIV",
"FDIVCC",
"FDIVS",
"FDIVSCC",
"FMADD",
"FMADDCC",
"FMADDS",
"FMADDSCC",
"FMOVD",
"FMOVDCC",
"FMOVDU",
"FMOVS",
"FMOVSU",
"FMOVSX",
"FMOVSZ",
"FMSUB",
"FMSUBCC",
"FMSUBS",
"FMSUBSCC",
"FMUL",
"FMULCC",
"FMULS",
"FMULSCC",
"FNABS",
"FNABSCC",
"FNEG",
"FNEGCC",
"FNMADD",
"FNMADDCC",
"FNMADDS",
"FNMADDSCC",
"FNMSUB",
"FNMSUBCC",
"FNMSUBS",
"FNMSUBSCC",
"FRSP",
"FRSPCC",
"FSUB",
"FSUBCC",
"FSUBS",
"FSUBSCC",
"ISEL",
"MOVMW",
"LBAR",
"LHAR",
"LSW",
"LWAR",
"LWSYNC",
"MOVDBR",
"MOVWBR",
"MOVB",
"MOVBU",
"MOVBZ",
"MOVBZU",
"MOVH",
"MOVHBR",
"MOVHU",
"MOVHZ",
"MOVHZU",
"MOVW",
"MOVWU",
"MOVFL",
"MOVCRFS",
"MTFSB0",
"MTFSB0CC",
"MTFSB1",
"MTFSB1CC",
"MULHW",
"MULHWCC",
"MULHWU",
"MULHWUCC",
"MULLW",
"MULLWCC",
"MULLWVCC",
"MULLWV",
"NAND",
"NANDCC",
"NEG",
"NEGCC",
"NEGVCC",
"NEGV",
"NOR",
"NORCC",
"OR",
"ORCC",
"ORN",
"ORNCC",
"ORIS",
"REM",
"REMU",
"RFI",
"RLWMI",
"RLWMICC",
"RLWNM",
"RLWNMCC",
"CLRLSLWI",
"SLW",
"SLWCC",
"SRW",
"SRAW",
"SRAWCC",
"SRWCC",
"STBCCC",
"STHCCC",
"STSW",
"STWCCC",
"SUB",
"SUBCC",
"SUBVCC",
"SUBC",
"SUBCCC",
"SUBCV",
"SUBCVCC",
"SUBME",
"SUBMECC",
"SUBMEVCC",
"SUBMEV",
"SUBV",
"SUBE",
"SUBECC",
"SUBEV",
"SUBEVCC",
"SUBZE",
"SUBZECC",
"SUBZEVCC",
"SUBZEV",
"SYNC",
"XOR",
"XORCC",
"XORIS",
"DCBF",
"DCBI",
"DCBST",
"DCBT",
"DCBTST",
"DCBZ",
"ECIWX",
"ECOWX",
"EIEIO",
"ICBI",
"ISYNC",
"PTESYNC",
"TLBIE",
"TLBIEL",
"TLBSYNC",
"TW",
"SYSCALL",
"WORD",
"RFCI",
"FCPSGN",
"FCPSGNCC",
"FRES",
"FRESCC",
"FRIM",
"FRIMCC",
"FRIP",
"FRIPCC",
"FRIZ",
"FRIZCC",
"FRIN",
"FRINCC",
"FRSQRTE",
"FRSQRTECC",
"FSEL",
"FSELCC",
"FSQRT",
"FSQRTCC",
"FSQRTS",
"FSQRTSCC",
"CNTLZD",
"CNTLZDCC",
"CMPW",
"CMPWU",
"CMPB",
"FTDIV",
"FTSQRT",
"DIVD",
"DIVDCC",
"DIVDE",
"DIVDECC",
"DIVDEU",
"DIVDEUCC",
"DIVDVCC",
"DIVDV",
"DIVDU",
"DIVDUCC",
"DIVDUVCC",
"DIVDUV",
"EXTSW",
"EXTSWCC",
"FCFID",
"FCFIDCC",
"FCFIDU",
"FCFIDUCC",
"FCFIDS",
"FCFIDSCC",
"FCTID",
"FCTIDCC",
"FCTIDZ",
"FCTIDZCC",
"LDAR",
"MOVD",
"MOVDU",
"MOVWZ",
"MOVWZU",
"MULHD",
"MULHDCC",
"MULHDU",
"MULHDUCC",
"MULLD",
"MULLDCC",
"MULLDVCC",
"MULLDV",
"RFID",
"RLDMI",
"RLDMICC",
"RLDIMI",
"RLDIMICC",
"RLDC",
"RLDCCC",
"RLDCR",
"RLDCRCC",
"RLDICR",
"RLDICRCC",
"RLDCL",
"RLDCLCC",
"RLDICL",
"RLDICLCC",
"RLDIC",
"RLDICCC",
"CLRLSLDI",
"ROTL",
"ROTLW",
"SLBIA",
"SLBIE",
"SLBMFEE",
"SLBMFEV",
"SLBMTE",
"SLD",
"SLDCC",
"SRD",
"SRAD",
"SRADCC",
"SRDCC",
"STDCCC",
"TD",
"DWORD",
"REMD",
"REMDU",
"HRFID",
"POPCNTD",
"POPCNTW",
"POPCNTB",
"CNTTZW",
"CNTTZWCC",
"CNTTZD",
"CNTTZDCC",
"COPY",
"PASTECC",
"DARN",
"LDMX",
"MADDHD",
"MADDHDU",
"MADDLD",
"LV",
"LVEBX",
"LVEHX",
"LVEWX",
"LVX",
"LVXL",
"LVSL",
"LVSR",
"STV",
"STVEBX",
"STVEHX",
"STVEWX",
"STVX",
"STVXL",
"VAND",
"VANDC",
"VNAND",
"VOR",
"VORC",
"VNOR",
"VXOR",
"VEQV",
"VADDUM",
"VADDUBM",
"VADDUHM",
"VADDUWM",
"VADDUDM",
"VADDUQM",
"VADDCU",
"VADDCUQ",
"VADDCUW",
"VADDUS",
"VADDUBS",
"VADDUHS",
"VADDUWS",
"VADDSS",
"VADDSBS",
"VADDSHS",
"VADDSWS",
"VADDE",
"VADDEUQM",
"VADDECUQ",
"VSUBUM",
"VSUBUBM",
"VSUBUHM",
"VSUBUWM",
"VSUBUDM",
"VSUBUQM",
"VSUBCU",
"VSUBCUQ",
"VSUBCUW",
"VSUBUS",
"VSUBUBS",
"VSUBUHS",
"VSUBUWS",
"VSUBSS",
"VSUBSBS",
"VSUBSHS",
"VSUBSWS",
"VSUBE",
"VSUBEUQM",
"VSUBECUQ",
"VMULESB",
"VMULOSB",
"VMULEUB",
"VMULOUB",
"VMULESH",
"VMULOSH",
"VMULEUH",
"VMULOUH",
"VMULESW",
"VMULOSW",
"VMULEUW",
"VMULOUW",
"VMULUWM",
"VPMSUM",
"VPMSUMB",
"VPMSUMH",
"VPMSUMW",
"VPMSUMD",
"VMSUMUDM",
"VR",
"VRLB",
"VRLH",
"VRLW",
"VRLD",
"VS",
"VSLB",
"VSLH",
"VSLW",
"VSL",
"VSLO",
"VSRB",
"VSRH",
"VSRW",
"VSR",
"VSRO",
"VSLD",
"VSRD",
"VSA",
"VSRAB",
"VSRAH",
"VSRAW",
"VSRAD",
"VSOI",
"VSLDOI",
"VCLZ",
"VCLZB",
"VCLZH",
"VCLZW",
"VCLZD",
"VPOPCNT",
"VPOPCNTB",
"VPOPCNTH",
"VPOPCNTW",
"VPOPCNTD",
"VCMPEQ",
"VCMPEQUB",
"VCMPEQUBCC",
"VCMPEQUH",
"VCMPEQUHCC",
"VCMPEQUW",
"VCMPEQUWCC",
"VCMPEQUD",
"VCMPEQUDCC",
"VCMPGT",
"VCMPGTUB",
"VCMPGTUBCC",
"VCMPGTUH",
"VCMPGTUHCC",
"VCMPGTUW",
"VCMPGTUWCC",
"VCMPGTUD",
"VCMPGTUDCC",
"VCMPGTSB",
"VCMPGTSBCC",
"VCMPGTSH",
"VCMPGTSHCC",
"VCMPGTSW",
"VCMPGTSWCC",
"VCMPGTSD",
"VCMPGTSDCC",
"VCMPNEZB",
"VCMPNEZBCC",
"VCMPNEB",
"VCMPNEBCC",
"VCMPNEH",
"VCMPNEHCC",
"VCMPNEW",
"VCMPNEWCC",
"VPERM",
"VPERMXOR",
"VPERMR",
"VBPERMQ",
"VBPERMD",
"VSEL",
"VSPLT",
"VSPLTB",
"VSPLTH",
"VSPLTW",
"VSPLTI",
"VSPLTISB",
"VSPLTISH",
"VSPLTISW",
"VCIPH",
"VCIPHER",
"VCIPHERLAST",
"VNCIPH",
"VNCIPHER",
"VNCIPHERLAST",
"VSBOX",
"VSHASIGMA",
"VSHASIGMAW",
"VSHASIGMAD",
"VMRGEW",
"VMRGOW",
"LXV",
"LXVL",
"LXVLL",
"LXVD2X",
"LXVW4X",
"LXVH8X",
"LXVB16X",
"LXVX",
"LXVDSX",
"STXV",
"STXVL",
"STXVLL",
"STXVD2X",
"STXVW4X",
"STXVH8X",
"STXVB16X",
"STXVX",
"LXSDX",
"STXSDX",
"LXSIWAX",
"LXSIWZX",
"STXSIWX",
"MFVSRD",
"MFFPRD",
"MFVRD",
"MFVSRWZ",
"MFVSRLD",
"MTVSRD",
"MTFPRD",
"MTVRD",
"MTVSRWA",
"MTVSRWZ",
"MTVSRDD",
"MTVSRWS",
"XXLAND",
"XXLANDC",
"XXLEQV",
"XXLNAND",
"XXLOR",
"XXLORC",
"XXLNOR",
"XXLORQ",
"XXLXOR",
"XXSEL",
"XXMRGHW",
"XXMRGLW",
"XXSPLT",
"XXSPLTW",
"XXSPLTIB",
"XXPERM",
"XXPERMDI",
"XXSLDWI",
"XXBRQ",
"XXBRD",
"XXBRW",
"XXBRH",
"XSCVDPSP",
"XSCVSPDP",
"XSCVDPSPN",
"XSCVSPDPN",
"XVCVDPSP",
"XVCVSPDP",
"XSCVDPSXDS",
"XSCVDPSXWS",
"XSCVDPUXDS",
"XSCVDPUXWS",
"XSCVSXDDP",
"XSCVUXDDP",
"XSCVSXDSP",
"XSCVUXDSP",
"XVCVDPSXDS",
"XVCVDPSXWS",
"XVCVDPUXDS",
"XVCVDPUXWS",
"XVCVSPSXDS",
"XVCVSPSXWS",
"XVCVSPUXDS",
"XVCVSPUXWS",
"XVCVSXDDP",
"XVCVSXWDP",
"XVCVUXDDP",
"XVCVUXWDP",
"XVCVSXDSP",
"XVCVSXWSP",
"XVCVUXDSP",
"XVCVUXWSP",
"LAST",
}

View File

@ -0,0 +1,51 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ppc64
var cnames9 = []string{
"NONE",
"REG",
"FREG",
"VREG",
"VSREG",
"CREG",
"SPR",
"ZCON",
"SCON",
"UCON",
"ADDCON",
"ANDCON",
"LCON",
"DCON",
"SACON",
"SECON",
"LACON",
"LECON",
"DACON",
"SBRA",
"LBRA",
"LBRAPIC",
"SAUTO",
"LAUTO",
"SEXT",
"LEXT",
"ZOREG",
"SOREG",
"LOREG",
"FPSCR",
"MSR",
"XER",
"LR",
"CTR",
"ANY",
"GOK",
"ADDR",
"GOTADDR",
"TOCADDR",
"TLS_LE",
"TLS_IE",
"TEXTSIZE",
"NCLASS",
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,244 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package ppc64 implements a PPC64 assembler that assembles Go asm into
the corresponding PPC64 instructions as defined by the Power ISA 3.0B.
This document provides information on how to write code in Go assembler
for PPC64, focusing on the differences between Go and PPC64 assembly language.
It assumes some knowledge of PPC64 assembler. The original implementation of
PPC64 in Go defined many opcodes that are different from PPC64 opcodes, but
updates to the Go assembly language used mnemonics that are mostly similar if not
identical to the PPC64 mneumonics, such as VMX and VSX instructions. Not all detail
is included here; refer to the Power ISA document if interested in more detail.
Starting with Go 1.15 the Go objdump supports the -gnu option, which provides a
side by side view of the Go assembler and the PPC64 assembler output. This is
extremely helpful in determining what final PPC64 assembly is generated from the
corresponding Go assembly.
In the examples below, the Go assembly is on the left, PPC64 assembly on the right.
1. Operand ordering
In Go asm, the last operand (right) is the target operand, but with PPC64 asm,
the first operand (left) is the target. The order of the remaining operands is
not consistent: in general opcodes with 3 operands that perform math or logical
operations have their operands in reverse order. Opcodes for vector instructions
and those with more than 3 operands usually have operands in the same order except
for the target operand, which is first in PPC64 asm and last in Go asm.
Example:
ADD R3, R4, R5 <=> add r5, r4, r3
2. Constant operands
In Go asm, an operand that starts with '$' indicates a constant value. If the
instruction using the constant has an immediate version of the opcode, then an
immediate value is used with the opcode if possible.
Example:
ADD $1, R3, R4 <=> addi r4, r3, 1
3. Opcodes setting condition codes
In PPC64 asm, some instructions other than compares have variations that can set
the condition code where meaningful. This is indicated by adding '.' to the end
of the PPC64 instruction. In Go asm, these instructions have 'CC' at the end of
the opcode. The possible settings of the condition code depend on the instruction.
CR0 is the default for fixed-point instructions; CR1 for floating point; CR6 for
vector instructions.
Example:
ANDCC R3, R4, R5 <=> and. r5, r3, r4 (set CR0)
4. Loads and stores from memory
In Go asm, opcodes starting with 'MOV' indicate a load or store. When the target
is a memory reference, then it is a store; when the target is a register and the
source is a memory reference, then it is a load.
MOV{B,H,W,D} variations identify the size as byte, halfword, word, doubleword.
Adding 'Z' to the opcode for a load indicates zero extend; if omitted it is sign extend.
Adding 'U' to a load or store indicates an update of the base register with the offset.
Adding 'BR' to an opcode indicates byte-reversed load or store, or the order opposite
of the expected endian order. If 'BR' is used then zero extend is assumed.
Memory references n(Ra) indicate the address in Ra + n. When used with an update form
of an opcode, the value in Ra is incremented by n.
Memory references (Ra+Rb) or (Ra)(Rb) indicate the address Ra + Rb, used by indexed
loads or stores. Both forms are accepted. When used with an update then the base register
is updated by the value in the index register.
Examples:
MOVD (R3), R4 <=> ld r4,0(r3)
MOVW (R3), R4 <=> lwa r4,0(r3)
MOVWZU 4(R3), R4 <=> lwzu r4,4(r3)
MOVWZ (R3+R5), R4 <=> lwzx r4,r3,r5
MOVHZ (R3), R4 <=> lhz r4,0(r3)
MOVHU 2(R3), R4 <=> lhau r4,2(r3)
MOVBZ (R3), R4 <=> lbz r4,0(r3)
MOVD R4,(R3) <=> std r4,0(r3)
MOVW R4,(R3) <=> stw r4,0(r3)
MOVW R4,(R3+R5) <=> stwx r4,r3,r5
MOVWU R4,4(R3) <=> stwu r4,4(r3)
MOVH R4,2(R3) <=> sth r4,2(r3)
MOVBU R4,(R3)(R5) <=> stbux r4,r3,r5
4. Compares
When an instruction does a compare or other operation that might
result in a condition code, then the resulting condition is set
in a field of the condition register. The condition register consists
of 8 4-bit fields named CR0 - CR7. When a compare instruction
identifies a CR then the resulting condition is set in that field
to be read by a later branch or isel instruction. Within these fields,
bits are set to indicate less than, greater than, or equal conditions.
Once an instruction sets a condition, then a subsequent branch, isel or
other instruction can read the condition field and operate based on the
bit settings.
Examples:
CMP R3, R4 <=> cmp r3, r4 (CR0 assumed)
CMP R3, R4, CR1 <=> cmp cr1, r3, r4
Note that the condition register is the target operand of compare opcodes, so
the remaining operands are in the same order for Go asm and PPC64 asm.
When CR0 is used then it is implicit and does not need to be specified.
5. Branches
Many branches are represented as a form of the BC instruction. There are
other extended opcodes to make it easier to see what type of branch is being
used.
The following is a brief description of the BC instruction and its commonly
used operands.
BC op1, op2, op3
op1: type of branch
16 -> bctr (branch on ctr)
12 -> bcr (branch if cr bit is set)
8 -> bcr+bctr (branch on ctr and cr values)
4 -> bcr != 0 (branch if specified cr bit is not set)
There are more combinations but these are the most common.
op2: condition register field and condition bit
This contains an immediate value indicating which condition field
to read and what bits to test. Each field is 4 bits long with CR0
at bit 0, CR1 at bit 4, etc. The value is computed as 4*CR+condition
with these condition values:
0 -> LT
1 -> GT
2 -> EQ
3 -> OVG
Thus 0 means test CR0 for LT, 5 means CR1 for GT, 30 means CR7 for EQ.
op3: branch target
Examples:
BC 12, 0, target <=> blt cr0, target
BC 12, 2, target <=> beq cr0, target
BC 12, 5, target <=> bgt cr1, target
BC 12, 30, target <=> beq cr7, target
BC 4, 6, target <=> bne cr1, target
BC 4, 1, target <=> ble cr1, target
The following extended opcodes are available for ease of use and readability:
BNE CR2, target <=> bne cr2, target
BEQ CR4, target <=> beq cr4, target
BLT target <=> blt target (cr0 default)
BGE CR7, target <=> bge cr7, target
Refer to the ISA for more information on additional values for the BC instruction,
how to handle OVG information, and much more.
5. Align directive
Starting with Go 1.12, Go asm supports the PCALIGN directive, which indicates
that the next instruction should be aligned to the specified value. Currently
8 and 16 are the only supported values, and a maximum of 2 NOPs will be added
to align the code. That means in the case where the code is aligned to 4 but
PCALIGN $16 is at that location, the code will only be aligned to 8 to avoid
adding 3 NOPs.
The purpose of this directive is to improve performance for cases like loops
where better alignment (8 or 16 instead of 4) might be helpful. This directive
exists in PPC64 assembler and is frequently used by PPC64 assembler writers.
PCALIGN $16
PCALIGN $8
Functions in Go are aligned to 16 bytes, as is the case in all other compilers
for PPC64.
6. Shift instructions
The simple scalar shifts on PPC64 expect a shift count that fits in 5 bits for
32-bit values or 6 bit for 64-bit values. If the shift count is a constant value
greater than the max then the assembler sets it to the max for that size (31 for
32 bit values, 63 for 64 bit values). If the shift count is in a register, then
only the low 5 or 6 bits of the register will be used as the shift count. The
Go compiler will add appropriate code to compare the shift value to achieve the
the correct result, and the assembler does not add extra checking.
Examples:
SRAD $8,R3,R4 => sradi r4,r3,8
SRD $8,R3,R4 => rldicl r4,r3,56,8
SLD $8,R3,R4 => rldicr r4,r3,8,55
SRAW $16,R4,R5 => srawi r5,r4,16
SRW $40,R4,R5 => rlwinm r5,r4,0,0,31
SLW $12,R4,R5 => rlwinm r5,r4,12,0,19
Some non-simple shifts have operands in the Go assembly which don't map directly
onto operands in the PPC64 assembly. When an operand in a shift instruction in the
Go assembly is a bit mask, that mask is represented as a start and end bit in the
PPC64 assembly instead of a mask. See the ISA for more detail on these types of shifts.
Here are a few examples:
RLWMI $7,R3,$65535,R6 => rlwimi r6,r3,7,16,31
RLDMI $0,R4,$7,R6 => rldimi r6,r4,0,61
More recently, Go opcodes were added which map directly onto the PPC64 opcodes. It is
recommended to use the newer opcodes to avoid confusion.
RLDICL $0,R4,$15,R6 => rldicl r6,r4,0,15
RLDICR $0,R4,$15,R6 => rldicr r6.r4,0,15
Register naming
1. Special register usage in Go asm
The following registers should not be modified by user Go assembler code.
R0: Go code expects this register to contain the value 0.
R1: Stack pointer
R2: TOC pointer when compiled with -shared or -dynlink (a.k.a position independent code)
R13: TLS pointer
R30: g (goroutine)
Register names:
Rn is used for general purpose registers. (0-31)
Fn is used for floating point registers. (0-31)
Vn is used for vector registers. Slot 0 of Vn overlaps with Fn. (0-31)
VSn is used for vector-scalar registers. V0-V31 overlap with VS32-VS63. (0-63)
CTR represents the count register.
LR represents the link register.
*/
package ppc64

View File

@ -0,0 +1,104 @@
// cmd/9l/list.c from Vita Nuova.
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package ppc64
import (
"github.com/twitchyliquid64/golang-asm/obj"
"fmt"
)
func init() {
obj.RegisterRegister(obj.RBasePPC64, REG_DCR0+1024, rconv)
obj.RegisterOpcode(obj.ABasePPC64, Anames)
}
func rconv(r int) string {
if r == 0 {
return "NONE"
}
if r == REGG {
// Special case.
return "g"
}
if REG_R0 <= r && r <= REG_R31 {
return fmt.Sprintf("R%d", r-REG_R0)
}
if REG_F0 <= r && r <= REG_F31 {
return fmt.Sprintf("F%d", r-REG_F0)
}
if REG_V0 <= r && r <= REG_V31 {
return fmt.Sprintf("V%d", r-REG_V0)
}
if REG_VS0 <= r && r <= REG_VS63 {
return fmt.Sprintf("VS%d", r-REG_VS0)
}
if REG_CR0 <= r && r <= REG_CR7 {
return fmt.Sprintf("CR%d", r-REG_CR0)
}
if r == REG_CR {
return "CR"
}
if REG_SPR0 <= r && r <= REG_SPR0+1023 {
switch r {
case REG_XER:
return "XER"
case REG_LR:
return "LR"
case REG_CTR:
return "CTR"
}
return fmt.Sprintf("SPR(%d)", r-REG_SPR0)
}
if REG_DCR0 <= r && r <= REG_DCR0+1023 {
return fmt.Sprintf("DCR(%d)", r-REG_DCR0)
}
if r == REG_FPSCR {
return "FPSCR"
}
if r == REG_MSR {
return "MSR"
}
return fmt.Sprintf("Rgok(%d)", r-obj.RBasePPC64)
}
func DRconv(a int) string {
s := "C_??"
if a >= C_NONE && a <= C_NCLASS {
s = cnames9[a]
}
var fp string
fp += s
return fp
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,258 @@
// Code generated by stringer -i cpu.go -o anames.go -p riscv; DO NOT EDIT.
package riscv
import "github.com/twitchyliquid64/golang-asm/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "ADDI",
"SLTI",
"SLTIU",
"ANDI",
"ORI",
"XORI",
"SLLI",
"SRLI",
"SRAI",
"LUI",
"AUIPC",
"ADD",
"SLT",
"SLTU",
"AND",
"OR",
"XOR",
"SLL",
"SRL",
"SUB",
"SRA",
"SLLIRV32",
"SRLIRV32",
"SRAIRV32",
"JAL",
"JALR",
"BEQ",
"BNE",
"BLT",
"BLTU",
"BGE",
"BGEU",
"LW",
"LWU",
"LH",
"LHU",
"LB",
"LBU",
"SW",
"SH",
"SB",
"FENCE",
"FENCEI",
"FENCETSO",
"ADDIW",
"SLLIW",
"SRLIW",
"SRAIW",
"ADDW",
"SLLW",
"SRLW",
"SUBW",
"SRAW",
"LD",
"SD",
"MUL",
"MULH",
"MULHU",
"MULHSU",
"MULW",
"DIV",
"DIVU",
"REM",
"REMU",
"DIVW",
"DIVUW",
"REMW",
"REMUW",
"LRD",
"SCD",
"LRW",
"SCW",
"AMOSWAPD",
"AMOADDD",
"AMOANDD",
"AMOORD",
"AMOXORD",
"AMOMAXD",
"AMOMAXUD",
"AMOMIND",
"AMOMINUD",
"AMOSWAPW",
"AMOADDW",
"AMOANDW",
"AMOORW",
"AMOXORW",
"AMOMAXW",
"AMOMAXUW",
"AMOMINW",
"AMOMINUW",
"RDCYCLE",
"RDCYCLEH",
"RDTIME",
"RDTIMEH",
"RDINSTRET",
"RDINSTRETH",
"FRCSR",
"FSCSR",
"FRRM",
"FSRM",
"FRFLAGS",
"FSFLAGS",
"FSRMI",
"FSFLAGSI",
"FLW",
"FSW",
"FADDS",
"FSUBS",
"FMULS",
"FDIVS",
"FMINS",
"FMAXS",
"FSQRTS",
"FMADDS",
"FMSUBS",
"FNMADDS",
"FNMSUBS",
"FCVTWS",
"FCVTLS",
"FCVTSW",
"FCVTSL",
"FCVTWUS",
"FCVTLUS",
"FCVTSWU",
"FCVTSLU",
"FSGNJS",
"FSGNJNS",
"FSGNJXS",
"FMVXS",
"FMVSX",
"FMVXW",
"FMVWX",
"FEQS",
"FLTS",
"FLES",
"FCLASSS",
"FLD",
"FSD",
"FADDD",
"FSUBD",
"FMULD",
"FDIVD",
"FMIND",
"FMAXD",
"FSQRTD",
"FMADDD",
"FMSUBD",
"FNMADDD",
"FNMSUBD",
"FCVTWD",
"FCVTLD",
"FCVTDW",
"FCVTDL",
"FCVTWUD",
"FCVTLUD",
"FCVTDWU",
"FCVTDLU",
"FCVTSD",
"FCVTDS",
"FSGNJD",
"FSGNJND",
"FSGNJXD",
"FMVXD",
"FMVDX",
"FEQD",
"FLTD",
"FLED",
"FCLASSD",
"FLQ",
"FSQ",
"FADDQ",
"FSUBQ",
"FMULQ",
"FDIVQ",
"FMINQ",
"FMAXQ",
"FSQRTQ",
"FMADDQ",
"FMSUBQ",
"FNMADDQ",
"FNMSUBQ",
"FCVTWQ",
"FCVTLQ",
"FCVTSQ",
"FCVTDQ",
"FCVTQW",
"FCVTQL",
"FCVTQS",
"FCVTQD",
"FCVTWUQ",
"FCVTLUQ",
"FCVTQWU",
"FCVTQLU",
"FSGNJQ",
"FSGNJNQ",
"FSGNJXQ",
"FMVXQ",
"FMVQX",
"FEQQ",
"FLEQ",
"FLTQ",
"FCLASSQ",
"CSRRW",
"CSRRS",
"CSRRC",
"CSRRWI",
"CSRRSI",
"CSRRCI",
"ECALL",
"SCALL",
"EBREAK",
"SBREAK",
"MRET",
"SRET",
"URET",
"DRET",
"WFI",
"SFENCEVMA",
"HFENCEGVMA",
"HFENCEVVMA",
"WORD",
"BEQZ",
"BGEZ",
"BGT",
"BGTU",
"BGTZ",
"BLE",
"BLEU",
"BLEZ",
"BLTZ",
"BNEZ",
"FNEGD",
"FNEGS",
"FNED",
"FNES",
"MOV",
"MOVB",
"MOVBU",
"MOVF",
"MOVD",
"MOVH",
"MOVHU",
"MOVW",
"MOVWU",
"NEG",
"NEGW",
"NOT",
"SEQZ",
"SNEZ",
"LAST",
}

View File

@ -0,0 +1,644 @@
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
// Portions Copyright © 2019 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package riscv
import "github.com/twitchyliquid64/golang-asm/obj"
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p riscv
const (
// Base register numberings.
REG_X0 = obj.RBaseRISCV + iota
REG_X1
REG_X2
REG_X3
REG_X4
REG_X5
REG_X6
REG_X7
REG_X8
REG_X9
REG_X10
REG_X11
REG_X12
REG_X13
REG_X14
REG_X15
REG_X16
REG_X17
REG_X18
REG_X19
REG_X20
REG_X21
REG_X22
REG_X23
REG_X24
REG_X25
REG_X26
REG_X27
REG_X28
REG_X29
REG_X30
REG_X31
// FP register numberings.
REG_F0
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_F8
REG_F9
REG_F10
REG_F11
REG_F12
REG_F13
REG_F14
REG_F15
REG_F16
REG_F17
REG_F18
REG_F19
REG_F20
REG_F21
REG_F22
REG_F23
REG_F24
REG_F25
REG_F26
REG_F27
REG_F28
REG_F29
REG_F30
REG_F31
// This marks the end of the register numbering.
REG_END
// General registers reassigned to ABI names.
REG_ZERO = REG_X0
REG_RA = REG_X1 // aka REG_LR
REG_SP = REG_X2
REG_GP = REG_X3 // aka REG_SB
REG_TP = REG_X4 // aka REG_G
REG_T0 = REG_X5
REG_T1 = REG_X6
REG_T2 = REG_X7
REG_S0 = REG_X8
REG_S1 = REG_X9
REG_A0 = REG_X10
REG_A1 = REG_X11
REG_A2 = REG_X12
REG_A3 = REG_X13
REG_A4 = REG_X14
REG_A5 = REG_X15
REG_A6 = REG_X16
REG_A7 = REG_X17
REG_S2 = REG_X18
REG_S3 = REG_X19
REG_S4 = REG_X20 // aka REG_CTXT
REG_S5 = REG_X21
REG_S6 = REG_X22
REG_S7 = REG_X23
REG_S8 = REG_X24
REG_S9 = REG_X25
REG_S10 = REG_X26
REG_S11 = REG_X27
REG_T3 = REG_X28
REG_T4 = REG_X29
REG_T5 = REG_X30
REG_T6 = REG_X31 // aka REG_TMP
// Go runtime register names.
REG_G = REG_TP // G pointer.
REG_CTXT = REG_S4 // Context for closures.
REG_LR = REG_RA // Link register.
REG_TMP = REG_T6 // Reserved for assembler use.
// ABI names for floating point registers.
REG_FT0 = REG_F0
REG_FT1 = REG_F1
REG_FT2 = REG_F2
REG_FT3 = REG_F3
REG_FT4 = REG_F4
REG_FT5 = REG_F5
REG_FT6 = REG_F6
REG_FT7 = REG_F7
REG_FS0 = REG_F8
REG_FS1 = REG_F9
REG_FA0 = REG_F10
REG_FA1 = REG_F11
REG_FA2 = REG_F12
REG_FA3 = REG_F13
REG_FA4 = REG_F14
REG_FA5 = REG_F15
REG_FA6 = REG_F16
REG_FA7 = REG_F17
REG_FS2 = REG_F18
REG_FS3 = REG_F19
REG_FS4 = REG_F20
REG_FS5 = REG_F21
REG_FS6 = REG_F22
REG_FS7 = REG_F23
REG_FS8 = REG_F24
REG_FS9 = REG_F25
REG_FS10 = REG_F26
REG_FS11 = REG_F27
REG_FT8 = REG_F28
REG_FT9 = REG_F29
REG_FT10 = REG_F30
REG_FT11 = REG_F31
// Names generated by the SSA compiler.
REGSP = REG_SP
REGG = REG_G
)
// https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#dwarf-register-numbers
var RISCV64DWARFRegisters = map[int16]int16{
// Integer Registers.
REG_X0: 0,
REG_X1: 1,
REG_X2: 2,
REG_X3: 3,
REG_X4: 4,
REG_X5: 5,
REG_X6: 6,
REG_X7: 7,
REG_X8: 8,
REG_X9: 9,
REG_X10: 10,
REG_X11: 11,
REG_X12: 12,
REG_X13: 13,
REG_X14: 14,
REG_X15: 15,
REG_X16: 16,
REG_X17: 17,
REG_X18: 18,
REG_X19: 19,
REG_X20: 20,
REG_X21: 21,
REG_X22: 22,
REG_X23: 23,
REG_X24: 24,
REG_X25: 25,
REG_X26: 26,
REG_X27: 27,
REG_X28: 28,
REG_X29: 29,
REG_X30: 30,
REG_X31: 31,
// Floating-Point Registers.
REG_F0: 32,
REG_F1: 33,
REG_F2: 34,
REG_F3: 35,
REG_F4: 36,
REG_F5: 37,
REG_F6: 38,
REG_F7: 39,
REG_F8: 40,
REG_F9: 41,
REG_F10: 42,
REG_F11: 43,
REG_F12: 44,
REG_F13: 45,
REG_F14: 46,
REG_F15: 47,
REG_F16: 48,
REG_F17: 49,
REG_F18: 50,
REG_F19: 51,
REG_F20: 52,
REG_F21: 53,
REG_F22: 54,
REG_F23: 55,
REG_F24: 56,
REG_F25: 57,
REG_F26: 58,
REG_F27: 59,
REG_F28: 60,
REG_F29: 61,
REG_F30: 62,
REG_F31: 63,
}
// Prog.Mark flags.
const (
// NEED_PCREL_ITYPE_RELOC is set on AUIPC instructions to indicate that
// it is the first instruction in an AUIPC + I-type pair that needs a
// R_RISCV_PCREL_ITYPE relocation.
NEED_PCREL_ITYPE_RELOC = 1 << 0
// NEED_PCREL_STYPE_RELOC is set on AUIPC instructions to indicate that
// it is the first instruction in an AUIPC + S-type pair that needs a
// R_RISCV_PCREL_STYPE relocation.
NEED_PCREL_STYPE_RELOC = 1 << 1
)
// RISC-V mnemonics, as defined in the "opcodes" and "opcodes-pseudo" files
// from:
//
// https://github.com/riscv/riscv-opcodes
//
// As well as some pseudo-mnemonics (e.g. MOV) used only in the assembler.
//
// See also "The RISC-V Instruction Set Manual" at:
//
// https://riscv.org/specifications/
//
// If you modify this table, you MUST run 'go generate' to regenerate anames.go!
const (
// Unprivileged ISA (Document Version 20190608-Base-Ratified)
// 2.4: Integer Computational Instructions
AADDI = obj.ABaseRISCV + obj.A_ARCHSPECIFIC + iota
ASLTI
ASLTIU
AANDI
AORI
AXORI
ASLLI
ASRLI
ASRAI
ALUI
AAUIPC
AADD
ASLT
ASLTU
AAND
AOR
AXOR
ASLL
ASRL
ASUB
ASRA
// The SLL/SRL/SRA instructions differ slightly between RV32 and RV64,
// hence there are pseudo-opcodes for the RV32 specific versions.
ASLLIRV32
ASRLIRV32
ASRAIRV32
// 2.5: Control Transfer Instructions
AJAL
AJALR
ABEQ
ABNE
ABLT
ABLTU
ABGE
ABGEU
// 2.6: Load and Store Instructions
ALW
ALWU
ALH
ALHU
ALB
ALBU
ASW
ASH
ASB
// 2.7: Memory Ordering Instructions
AFENCE
AFENCEI
AFENCETSO
// 5.2: Integer Computational Instructions (RV64I)
AADDIW
ASLLIW
ASRLIW
ASRAIW
AADDW
ASLLW
ASRLW
ASUBW
ASRAW
// 5.3: Load and Store Instructions (RV64I)
ALD
ASD
// 7.1: Multiplication Operations
AMUL
AMULH
AMULHU
AMULHSU
AMULW
ADIV
ADIVU
AREM
AREMU
ADIVW
ADIVUW
AREMW
AREMUW
// 8.2: Load-Reserved/Store-Conditional Instructions
ALRD
ASCD
ALRW
ASCW
// 8.3: Atomic Memory Operations
AAMOSWAPD
AAMOADDD
AAMOANDD
AAMOORD
AAMOXORD
AAMOMAXD
AAMOMAXUD
AAMOMIND
AAMOMINUD
AAMOSWAPW
AAMOADDW
AAMOANDW
AAMOORW
AAMOXORW
AAMOMAXW
AAMOMAXUW
AAMOMINW
AAMOMINUW
// 10.1: Base Counters and Timers
ARDCYCLE
ARDCYCLEH
ARDTIME
ARDTIMEH
ARDINSTRET
ARDINSTRETH
// 11.2: Floating-Point Control and Status Register
AFRCSR
AFSCSR
AFRRM
AFSRM
AFRFLAGS
AFSFLAGS
AFSRMI
AFSFLAGSI
// 11.5: Single-Precision Load and Store Instructions
AFLW
AFSW
// 11.6: Single-Precision Floating-Point Computational Instructions
AFADDS
AFSUBS
AFMULS
AFDIVS
AFMINS
AFMAXS
AFSQRTS
AFMADDS
AFMSUBS
AFNMADDS
AFNMSUBS
// 11.7: Single-Precision Floating-Point Conversion and Move Instructions
AFCVTWS
AFCVTLS
AFCVTSW
AFCVTSL
AFCVTWUS
AFCVTLUS
AFCVTSWU
AFCVTSLU
AFSGNJS
AFSGNJNS
AFSGNJXS
AFMVXS
AFMVSX
AFMVXW
AFMVWX
// 11.8: Single-Precision Floating-Point Compare Instructions
AFEQS
AFLTS
AFLES
// 11.9: Single-Precision Floating-Point Classify Instruction
AFCLASSS
// 12.3: Double-Precision Load and Store Instructions
AFLD
AFSD
// 12.4: Double-Precision Floating-Point Computational Instructions
AFADDD
AFSUBD
AFMULD
AFDIVD
AFMIND
AFMAXD
AFSQRTD
AFMADDD
AFMSUBD
AFNMADDD
AFNMSUBD
// 12.5: Double-Precision Floating-Point Conversion and Move Instructions
AFCVTWD
AFCVTLD
AFCVTDW
AFCVTDL
AFCVTWUD
AFCVTLUD
AFCVTDWU
AFCVTDLU
AFCVTSD
AFCVTDS
AFSGNJD
AFSGNJND
AFSGNJXD
AFMVXD
AFMVDX
// 12.6: Double-Precision Floating-Point Compare Instructions
AFEQD
AFLTD
AFLED
// 12.7: Double-Precision Floating-Point Classify Instruction
AFCLASSD
// 13.1 Quad-Precision Load and Store Instructions
AFLQ
AFSQ
// 13.2: Quad-Precision Computational Instructions
AFADDQ
AFSUBQ
AFMULQ
AFDIVQ
AFMINQ
AFMAXQ
AFSQRTQ
AFMADDQ
AFMSUBQ
AFNMADDQ
AFNMSUBQ
// 13.3 Quad-Precision Convert and Move Instructions
AFCVTWQ
AFCVTLQ
AFCVTSQ
AFCVTDQ
AFCVTQW
AFCVTQL
AFCVTQS
AFCVTQD
AFCVTWUQ
AFCVTLUQ
AFCVTQWU
AFCVTQLU
AFSGNJQ
AFSGNJNQ
AFSGNJXQ
AFMVXQ
AFMVQX
// 13.4 Quad-Precision Floating-Point Compare Instructions
AFEQQ
AFLEQ
AFLTQ
// 13.5 Quad-Precision Floating-Point Classify Instruction
AFCLASSQ
// Privileged ISA (Version 20190608-Priv-MSU-Ratified)
// 3.1.9: Instructions to Access CSRs
ACSRRW
ACSRRS
ACSRRC
ACSRRWI
ACSRRSI
ACSRRCI
// 3.2.1: Environment Call and Breakpoint
AECALL
ASCALL
AEBREAK
ASBREAK
// 3.2.2: Trap-Return Instructions
AMRET
ASRET
AURET
ADRET
// 3.2.3: Wait for Interrupt
AWFI
// 4.2.1: Supervisor Memory-Management Fence Instruction
ASFENCEVMA
// Hypervisor Memory-Management Instructions
AHFENCEGVMA
AHFENCEVVMA
// The escape hatch. Inserts a single 32-bit word.
AWORD
// Pseudo-instructions. These get translated by the assembler into other
// instructions, based on their operands.
ABEQZ
ABGEZ
ABGT
ABGTU
ABGTZ
ABLE
ABLEU
ABLEZ
ABLTZ
ABNEZ
AFNEGD
AFNEGS
AFNED
AFNES
AMOV
AMOVB
AMOVBU
AMOVF
AMOVD
AMOVH
AMOVHU
AMOVW
AMOVWU
ANEG
ANEGW
ANOT
ASEQZ
ASNEZ
// End marker
ALAST
)
// All unary instructions which write to their arguments (as opposed to reading
// from them) go here. The assembly parser uses this information to populate
// its AST in a semantically reasonable way.
//
// Any instructions not listed here are assumed to either be non-unary or to read
// from its argument.
var unaryDst = map[obj.As]bool{
ARDCYCLE: true,
ARDCYCLEH: true,
ARDTIME: true,
ARDTIMEH: true,
ARDINSTRET: true,
ARDINSTRETH: true,
}
// Instruction encoding masks.
const (
// ITypeImmMask is a mask including only the immediate portion of
// I-type instructions.
ITypeImmMask = 0xfff00000
// STypeImmMask is a mask including only the immediate portion of
// S-type instructions.
STypeImmMask = 0xfe000f80
// UTypeImmMask is a mask including only the immediate portion of
// U-type instructions.
UTypeImmMask = 0xfffff000
// UJTypeImmMask is a mask including only the immediate portion of
// UJ-type instructions.
UJTypeImmMask = UTypeImmMask
)

View File

@ -0,0 +1,459 @@
// Code generated by parse_opcodes -go; DO NOT EDIT.
package riscv
import "github.com/twitchyliquid64/golang-asm/obj"
type inst struct {
opcode uint32
funct3 uint32
rs2 uint32
csr int64
funct7 uint32
}
func encode(a obj.As) *inst {
switch a {
case ABEQ:
return &inst{0x63, 0x0, 0x0, 0, 0x0}
case ABNE:
return &inst{0x63, 0x1, 0x0, 0, 0x0}
case ABLT:
return &inst{0x63, 0x4, 0x0, 0, 0x0}
case ABGE:
return &inst{0x63, 0x5, 0x0, 0, 0x0}
case ABLTU:
return &inst{0x63, 0x6, 0x0, 0, 0x0}
case ABGEU:
return &inst{0x63, 0x7, 0x0, 0, 0x0}
case AJALR:
return &inst{0x67, 0x0, 0x0, 0, 0x0}
case AJAL:
return &inst{0x6f, 0x0, 0x0, 0, 0x0}
case ALUI:
return &inst{0x37, 0x0, 0x0, 0, 0x0}
case AAUIPC:
return &inst{0x17, 0x0, 0x0, 0, 0x0}
case AADDI:
return &inst{0x13, 0x0, 0x0, 0, 0x0}
case ASLLI:
return &inst{0x13, 0x1, 0x0, 0, 0x0}
case ASLTI:
return &inst{0x13, 0x2, 0x0, 0, 0x0}
case ASLTIU:
return &inst{0x13, 0x3, 0x0, 0, 0x0}
case AXORI:
return &inst{0x13, 0x4, 0x0, 0, 0x0}
case ASRLI:
return &inst{0x13, 0x5, 0x0, 0, 0x0}
case ASRAI:
return &inst{0x13, 0x5, 0x0, 1024, 0x20}
case AORI:
return &inst{0x13, 0x6, 0x0, 0, 0x0}
case AANDI:
return &inst{0x13, 0x7, 0x0, 0, 0x0}
case AADD:
return &inst{0x33, 0x0, 0x0, 0, 0x0}
case ASUB:
return &inst{0x33, 0x0, 0x0, 1024, 0x20}
case ASLL:
return &inst{0x33, 0x1, 0x0, 0, 0x0}
case ASLT:
return &inst{0x33, 0x2, 0x0, 0, 0x0}
case ASLTU:
return &inst{0x33, 0x3, 0x0, 0, 0x0}
case AXOR:
return &inst{0x33, 0x4, 0x0, 0, 0x0}
case ASRL:
return &inst{0x33, 0x5, 0x0, 0, 0x0}
case ASRA:
return &inst{0x33, 0x5, 0x0, 1024, 0x20}
case AOR:
return &inst{0x33, 0x6, 0x0, 0, 0x0}
case AAND:
return &inst{0x33, 0x7, 0x0, 0, 0x0}
case AADDIW:
return &inst{0x1b, 0x0, 0x0, 0, 0x0}
case ASLLIW:
return &inst{0x1b, 0x1, 0x0, 0, 0x0}
case ASRLIW:
return &inst{0x1b, 0x5, 0x0, 0, 0x0}
case ASRAIW:
return &inst{0x1b, 0x5, 0x0, 1024, 0x20}
case AADDW:
return &inst{0x3b, 0x0, 0x0, 0, 0x0}
case ASUBW:
return &inst{0x3b, 0x0, 0x0, 1024, 0x20}
case ASLLW:
return &inst{0x3b, 0x1, 0x0, 0, 0x0}
case ASRLW:
return &inst{0x3b, 0x5, 0x0, 0, 0x0}
case ASRAW:
return &inst{0x3b, 0x5, 0x0, 1024, 0x20}
case ALB:
return &inst{0x3, 0x0, 0x0, 0, 0x0}
case ALH:
return &inst{0x3, 0x1, 0x0, 0, 0x0}
case ALW:
return &inst{0x3, 0x2, 0x0, 0, 0x0}
case ALD:
return &inst{0x3, 0x3, 0x0, 0, 0x0}
case ALBU:
return &inst{0x3, 0x4, 0x0, 0, 0x0}
case ALHU:
return &inst{0x3, 0x5, 0x0, 0, 0x0}
case ALWU:
return &inst{0x3, 0x6, 0x0, 0, 0x0}
case ASB:
return &inst{0x23, 0x0, 0x0, 0, 0x0}
case ASH:
return &inst{0x23, 0x1, 0x0, 0, 0x0}
case ASW:
return &inst{0x23, 0x2, 0x0, 0, 0x0}
case ASD:
return &inst{0x23, 0x3, 0x0, 0, 0x0}
case AFENCE:
return &inst{0xf, 0x0, 0x0, 0, 0x0}
case AFENCEI:
return &inst{0xf, 0x1, 0x0, 0, 0x0}
case AMUL:
return &inst{0x33, 0x0, 0x0, 32, 0x1}
case AMULH:
return &inst{0x33, 0x1, 0x0, 32, 0x1}
case AMULHSU:
return &inst{0x33, 0x2, 0x0, 32, 0x1}
case AMULHU:
return &inst{0x33, 0x3, 0x0, 32, 0x1}
case ADIV:
return &inst{0x33, 0x4, 0x0, 32, 0x1}
case ADIVU:
return &inst{0x33, 0x5, 0x0, 32, 0x1}
case AREM:
return &inst{0x33, 0x6, 0x0, 32, 0x1}
case AREMU:
return &inst{0x33, 0x7, 0x0, 32, 0x1}
case AMULW:
return &inst{0x3b, 0x0, 0x0, 32, 0x1}
case ADIVW:
return &inst{0x3b, 0x4, 0x0, 32, 0x1}
case ADIVUW:
return &inst{0x3b, 0x5, 0x0, 32, 0x1}
case AREMW:
return &inst{0x3b, 0x6, 0x0, 32, 0x1}
case AREMUW:
return &inst{0x3b, 0x7, 0x0, 32, 0x1}
case AAMOADDW:
return &inst{0x2f, 0x2, 0x0, 0, 0x0}
case AAMOXORW:
return &inst{0x2f, 0x2, 0x0, 512, 0x10}
case AAMOORW:
return &inst{0x2f, 0x2, 0x0, 1024, 0x20}
case AAMOANDW:
return &inst{0x2f, 0x2, 0x0, 1536, 0x30}
case AAMOMINW:
return &inst{0x2f, 0x2, 0x0, -2048, 0x40}
case AAMOMAXW:
return &inst{0x2f, 0x2, 0x0, -1536, 0x50}
case AAMOMINUW:
return &inst{0x2f, 0x2, 0x0, -1024, 0x60}
case AAMOMAXUW:
return &inst{0x2f, 0x2, 0x0, -512, 0x70}
case AAMOSWAPW:
return &inst{0x2f, 0x2, 0x0, 128, 0x4}
case ALRW:
return &inst{0x2f, 0x2, 0x0, 256, 0x8}
case ASCW:
return &inst{0x2f, 0x2, 0x0, 384, 0xc}
case AAMOADDD:
return &inst{0x2f, 0x3, 0x0, 0, 0x0}
case AAMOXORD:
return &inst{0x2f, 0x3, 0x0, 512, 0x10}
case AAMOORD:
return &inst{0x2f, 0x3, 0x0, 1024, 0x20}
case AAMOANDD:
return &inst{0x2f, 0x3, 0x0, 1536, 0x30}
case AAMOMIND:
return &inst{0x2f, 0x3, 0x0, -2048, 0x40}
case AAMOMAXD:
return &inst{0x2f, 0x3, 0x0, -1536, 0x50}
case AAMOMINUD:
return &inst{0x2f, 0x3, 0x0, -1024, 0x60}
case AAMOMAXUD:
return &inst{0x2f, 0x3, 0x0, -512, 0x70}
case AAMOSWAPD:
return &inst{0x2f, 0x3, 0x0, 128, 0x4}
case ALRD:
return &inst{0x2f, 0x3, 0x0, 256, 0x8}
case ASCD:
return &inst{0x2f, 0x3, 0x0, 384, 0xc}
case AECALL:
return &inst{0x73, 0x0, 0x0, 0, 0x0}
case AEBREAK:
return &inst{0x73, 0x0, 0x1, 1, 0x0}
case AURET:
return &inst{0x73, 0x0, 0x2, 2, 0x0}
case ASRET:
return &inst{0x73, 0x0, 0x2, 258, 0x8}
case AMRET:
return &inst{0x73, 0x0, 0x2, 770, 0x18}
case ADRET:
return &inst{0x73, 0x0, 0x12, 1970, 0x3d}
case ASFENCEVMA:
return &inst{0x73, 0x0, 0x0, 288, 0x9}
case AWFI:
return &inst{0x73, 0x0, 0x5, 261, 0x8}
case ACSRRW:
return &inst{0x73, 0x1, 0x0, 0, 0x0}
case ACSRRS:
return &inst{0x73, 0x2, 0x0, 0, 0x0}
case ACSRRC:
return &inst{0x73, 0x3, 0x0, 0, 0x0}
case ACSRRWI:
return &inst{0x73, 0x5, 0x0, 0, 0x0}
case ACSRRSI:
return &inst{0x73, 0x6, 0x0, 0, 0x0}
case ACSRRCI:
return &inst{0x73, 0x7, 0x0, 0, 0x0}
case AHFENCEVVMA:
return &inst{0x73, 0x0, 0x0, 544, 0x11}
case AHFENCEGVMA:
return &inst{0x73, 0x0, 0x0, 1568, 0x31}
case AFADDS:
return &inst{0x53, 0x0, 0x0, 0, 0x0}
case AFSUBS:
return &inst{0x53, 0x0, 0x0, 128, 0x4}
case AFMULS:
return &inst{0x53, 0x0, 0x0, 256, 0x8}
case AFDIVS:
return &inst{0x53, 0x0, 0x0, 384, 0xc}
case AFSGNJS:
return &inst{0x53, 0x0, 0x0, 512, 0x10}
case AFSGNJNS:
return &inst{0x53, 0x1, 0x0, 512, 0x10}
case AFSGNJXS:
return &inst{0x53, 0x2, 0x0, 512, 0x10}
case AFMINS:
return &inst{0x53, 0x0, 0x0, 640, 0x14}
case AFMAXS:
return &inst{0x53, 0x1, 0x0, 640, 0x14}
case AFSQRTS:
return &inst{0x53, 0x0, 0x0, 1408, 0x2c}
case AFADDD:
return &inst{0x53, 0x0, 0x0, 32, 0x1}
case AFSUBD:
return &inst{0x53, 0x0, 0x0, 160, 0x5}
case AFMULD:
return &inst{0x53, 0x0, 0x0, 288, 0x9}
case AFDIVD:
return &inst{0x53, 0x0, 0x0, 416, 0xd}
case AFSGNJD:
return &inst{0x53, 0x0, 0x0, 544, 0x11}
case AFSGNJND:
return &inst{0x53, 0x1, 0x0, 544, 0x11}
case AFSGNJXD:
return &inst{0x53, 0x2, 0x0, 544, 0x11}
case AFMIND:
return &inst{0x53, 0x0, 0x0, 672, 0x15}
case AFMAXD:
return &inst{0x53, 0x1, 0x0, 672, 0x15}
case AFCVTSD:
return &inst{0x53, 0x0, 0x1, 1025, 0x20}
case AFCVTDS:
return &inst{0x53, 0x0, 0x0, 1056, 0x21}
case AFSQRTD:
return &inst{0x53, 0x0, 0x0, 1440, 0x2d}
case AFADDQ:
return &inst{0x53, 0x0, 0x0, 96, 0x3}
case AFSUBQ:
return &inst{0x53, 0x0, 0x0, 224, 0x7}
case AFMULQ:
return &inst{0x53, 0x0, 0x0, 352, 0xb}
case AFDIVQ:
return &inst{0x53, 0x0, 0x0, 480, 0xf}
case AFSGNJQ:
return &inst{0x53, 0x0, 0x0, 608, 0x13}
case AFSGNJNQ:
return &inst{0x53, 0x1, 0x0, 608, 0x13}
case AFSGNJXQ:
return &inst{0x53, 0x2, 0x0, 608, 0x13}
case AFMINQ:
return &inst{0x53, 0x0, 0x0, 736, 0x17}
case AFMAXQ:
return &inst{0x53, 0x1, 0x0, 736, 0x17}
case AFCVTSQ:
return &inst{0x53, 0x0, 0x3, 1027, 0x20}
case AFCVTQS:
return &inst{0x53, 0x0, 0x0, 1120, 0x23}
case AFCVTDQ:
return &inst{0x53, 0x0, 0x3, 1059, 0x21}
case AFCVTQD:
return &inst{0x53, 0x0, 0x1, 1121, 0x23}
case AFSQRTQ:
return &inst{0x53, 0x0, 0x0, 1504, 0x2f}
case AFLES:
return &inst{0x53, 0x0, 0x0, -1536, 0x50}
case AFLTS:
return &inst{0x53, 0x1, 0x0, -1536, 0x50}
case AFEQS:
return &inst{0x53, 0x2, 0x0, -1536, 0x50}
case AFLED:
return &inst{0x53, 0x0, 0x0, -1504, 0x51}
case AFLTD:
return &inst{0x53, 0x1, 0x0, -1504, 0x51}
case AFEQD:
return &inst{0x53, 0x2, 0x0, -1504, 0x51}
case AFLEQ:
return &inst{0x53, 0x0, 0x0, -1440, 0x53}
case AFLTQ:
return &inst{0x53, 0x1, 0x0, -1440, 0x53}
case AFEQQ:
return &inst{0x53, 0x2, 0x0, -1440, 0x53}
case AFCVTWS:
return &inst{0x53, 0x0, 0x0, -1024, 0x60}
case AFCVTWUS:
return &inst{0x53, 0x0, 0x1, -1023, 0x60}
case AFCVTLS:
return &inst{0x53, 0x0, 0x2, -1022, 0x60}
case AFCVTLUS:
return &inst{0x53, 0x0, 0x3, -1021, 0x60}
case AFMVXW:
return &inst{0x53, 0x0, 0x0, -512, 0x70}
case AFCLASSS:
return &inst{0x53, 0x1, 0x0, -512, 0x70}
case AFCVTWD:
return &inst{0x53, 0x0, 0x0, -992, 0x61}
case AFCVTWUD:
return &inst{0x53, 0x0, 0x1, -991, 0x61}
case AFCVTLD:
return &inst{0x53, 0x0, 0x2, -990, 0x61}
case AFCVTLUD:
return &inst{0x53, 0x0, 0x3, -989, 0x61}
case AFMVXD:
return &inst{0x53, 0x0, 0x0, -480, 0x71}
case AFCLASSD:
return &inst{0x53, 0x1, 0x0, -480, 0x71}
case AFCVTWQ:
return &inst{0x53, 0x0, 0x0, -928, 0x63}
case AFCVTWUQ:
return &inst{0x53, 0x0, 0x1, -927, 0x63}
case AFCVTLQ:
return &inst{0x53, 0x0, 0x2, -926, 0x63}
case AFCVTLUQ:
return &inst{0x53, 0x0, 0x3, -925, 0x63}
case AFMVXQ:
return &inst{0x53, 0x0, 0x0, -416, 0x73}
case AFCLASSQ:
return &inst{0x53, 0x1, 0x0, -416, 0x73}
case AFCVTSW:
return &inst{0x53, 0x0, 0x0, -768, 0x68}
case AFCVTSWU:
return &inst{0x53, 0x0, 0x1, -767, 0x68}
case AFCVTSL:
return &inst{0x53, 0x0, 0x2, -766, 0x68}
case AFCVTSLU:
return &inst{0x53, 0x0, 0x3, -765, 0x68}
case AFMVWX:
return &inst{0x53, 0x0, 0x0, -256, 0x78}
case AFCVTDW:
return &inst{0x53, 0x0, 0x0, -736, 0x69}
case AFCVTDWU:
return &inst{0x53, 0x0, 0x1, -735, 0x69}
case AFCVTDL:
return &inst{0x53, 0x0, 0x2, -734, 0x69}
case AFCVTDLU:
return &inst{0x53, 0x0, 0x3, -733, 0x69}
case AFMVDX:
return &inst{0x53, 0x0, 0x0, -224, 0x79}
case AFCVTQW:
return &inst{0x53, 0x0, 0x0, -672, 0x6b}
case AFCVTQWU:
return &inst{0x53, 0x0, 0x1, -671, 0x6b}
case AFCVTQL:
return &inst{0x53, 0x0, 0x2, -670, 0x6b}
case AFCVTQLU:
return &inst{0x53, 0x0, 0x3, -669, 0x6b}
case AFMVQX:
return &inst{0x53, 0x0, 0x0, -160, 0x7b}
case AFLW:
return &inst{0x7, 0x2, 0x0, 0, 0x0}
case AFLD:
return &inst{0x7, 0x3, 0x0, 0, 0x0}
case AFLQ:
return &inst{0x7, 0x4, 0x0, 0, 0x0}
case AFSW:
return &inst{0x27, 0x2, 0x0, 0, 0x0}
case AFSD:
return &inst{0x27, 0x3, 0x0, 0, 0x0}
case AFSQ:
return &inst{0x27, 0x4, 0x0, 0, 0x0}
case AFMADDS:
return &inst{0x43, 0x0, 0x0, 0, 0x0}
case AFMSUBS:
return &inst{0x47, 0x0, 0x0, 0, 0x0}
case AFNMSUBS:
return &inst{0x4b, 0x0, 0x0, 0, 0x0}
case AFNMADDS:
return &inst{0x4f, 0x0, 0x0, 0, 0x0}
case AFMADDD:
return &inst{0x43, 0x0, 0x0, 32, 0x1}
case AFMSUBD:
return &inst{0x47, 0x0, 0x0, 32, 0x1}
case AFNMSUBD:
return &inst{0x4b, 0x0, 0x0, 32, 0x1}
case AFNMADDD:
return &inst{0x4f, 0x0, 0x0, 32, 0x1}
case AFMADDQ:
return &inst{0x43, 0x0, 0x0, 96, 0x3}
case AFMSUBQ:
return &inst{0x47, 0x0, 0x0, 96, 0x3}
case AFNMSUBQ:
return &inst{0x4b, 0x0, 0x0, 96, 0x3}
case AFNMADDQ:
return &inst{0x4f, 0x0, 0x0, 96, 0x3}
case ASLLIRV32:
return &inst{0x13, 0x1, 0x0, 0, 0x0}
case ASRLIRV32:
return &inst{0x13, 0x5, 0x0, 0, 0x0}
case ASRAIRV32:
return &inst{0x13, 0x5, 0x0, 1024, 0x20}
case AFRFLAGS:
return &inst{0x73, 0x2, 0x1, 1, 0x0}
case AFSFLAGS:
return &inst{0x73, 0x1, 0x1, 1, 0x0}
case AFSFLAGSI:
return &inst{0x73, 0x5, 0x1, 1, 0x0}
case AFRRM:
return &inst{0x73, 0x2, 0x2, 2, 0x0}
case AFSRM:
return &inst{0x73, 0x1, 0x2, 2, 0x0}
case AFSRMI:
return &inst{0x73, 0x5, 0x2, 2, 0x0}
case AFSCSR:
return &inst{0x73, 0x1, 0x3, 3, 0x0}
case AFRCSR:
return &inst{0x73, 0x2, 0x3, 3, 0x0}
case ARDCYCLE:
return &inst{0x73, 0x2, 0x0, -1024, 0x60}
case ARDTIME:
return &inst{0x73, 0x2, 0x1, -1023, 0x60}
case ARDINSTRET:
return &inst{0x73, 0x2, 0x2, -1022, 0x60}
case ARDCYCLEH:
return &inst{0x73, 0x2, 0x0, -896, 0x64}
case ARDTIMEH:
return &inst{0x73, 0x2, 0x1, -895, 0x64}
case ARDINSTRETH:
return &inst{0x73, 0x2, 0x2, -894, 0x64}
case ASCALL:
return &inst{0x73, 0x0, 0x0, 0, 0x0}
case ASBREAK:
return &inst{0x73, 0x0, 0x1, 1, 0x0}
case AFMVXS:
return &inst{0x53, 0x0, 0x0, -512, 0x70}
case AFMVSX:
return &inst{0x53, 0x0, 0x0, -256, 0x78}
case AFENCETSO:
return &inst{0xf, 0x0, 0x13, -1997, 0x41}
}
return nil
}

View File

@ -0,0 +1,33 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package riscv
import (
"fmt"
"github.com/twitchyliquid64/golang-asm/obj"
)
func init() {
obj.RegisterRegister(obj.RBaseRISCV, REG_END, RegName)
obj.RegisterOpcode(obj.ABaseRISCV, Anames)
}
func RegName(r int) string {
switch {
case r == 0:
return "NONE"
case r == REG_G:
return "g"
case r == REG_SP:
return "SP"
case REG_X0 <= r && r <= REG_X31:
return fmt.Sprintf("X%d", r-REG_X0)
case REG_F0 <= r && r <= REG_F31:
return fmt.Sprintf("F%d", r-REG_F0)
default:
return fmt.Sprintf("Rgok(%d)", r-obj.RBaseRISCV)
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,720 @@
// Code generated by stringer -i a.out.go -o anames.go -p s390x; DO NOT EDIT.
package s390x
import "github.com/twitchyliquid64/golang-asm/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "ADD",
"ADDC",
"ADDE",
"ADDW",
"DIVW",
"DIVWU",
"DIVD",
"DIVDU",
"MODW",
"MODWU",
"MODD",
"MODDU",
"MULLW",
"MULLD",
"MULHD",
"MULHDU",
"MLGR",
"SUB",
"SUBC",
"SUBV",
"SUBE",
"SUBW",
"NEG",
"NEGW",
"MOVWBR",
"MOVB",
"MOVBZ",
"MOVH",
"MOVHBR",
"MOVHZ",
"MOVW",
"MOVWZ",
"MOVD",
"MOVDBR",
"MOVDEQ",
"MOVDGE",
"MOVDGT",
"MOVDLE",
"MOVDLT",
"MOVDNE",
"LOCR",
"LOCGR",
"FLOGR",
"POPCNT",
"AND",
"ANDW",
"OR",
"ORW",
"XOR",
"XORW",
"SLW",
"SLD",
"SRW",
"SRAW",
"SRD",
"SRAD",
"RLL",
"RLLG",
"RNSBG",
"RXSBG",
"ROSBG",
"RNSBGT",
"RXSBGT",
"ROSBGT",
"RISBG",
"RISBGN",
"RISBGZ",
"RISBGNZ",
"RISBHG",
"RISBLG",
"RISBHGZ",
"RISBLGZ",
"FABS",
"FADD",
"FADDS",
"FCMPO",
"FCMPU",
"CEBR",
"FDIV",
"FDIVS",
"FMADD",
"FMADDS",
"FMOVD",
"FMOVS",
"FMSUB",
"FMSUBS",
"FMUL",
"FMULS",
"FNABS",
"FNEG",
"FNEGS",
"LEDBR",
"LDEBR",
"LPDFR",
"LNDFR",
"FSUB",
"FSUBS",
"FSQRT",
"FSQRTS",
"FIEBR",
"FIDBR",
"CPSDR",
"LTEBR",
"LTDBR",
"TCEB",
"TCDB",
"LDGR",
"LGDR",
"CEFBRA",
"CDFBRA",
"CEGBRA",
"CDGBRA",
"CFEBRA",
"CFDBRA",
"CGEBRA",
"CGDBRA",
"CELFBR",
"CDLFBR",
"CELGBR",
"CDLGBR",
"CLFEBR",
"CLFDBR",
"CLGEBR",
"CLGDBR",
"CMP",
"CMPU",
"CMPW",
"CMPWU",
"TMHH",
"TMHL",
"TMLH",
"TMLL",
"IPM",
"SPM",
"CS",
"CSG",
"SYNC",
"BC",
"BCL",
"BRC",
"BEQ",
"BGE",
"BGT",
"BLE",
"BLT",
"BLEU",
"BLTU",
"BNE",
"BVC",
"BVS",
"SYSCALL",
"BRCT",
"BRCTG",
"CRJ",
"CGRJ",
"CLRJ",
"CLGRJ",
"CIJ",
"CGIJ",
"CLIJ",
"CLGIJ",
"CMPBEQ",
"CMPBGE",
"CMPBGT",
"CMPBLE",
"CMPBLT",
"CMPBNE",
"CMPUBEQ",
"CMPUBGE",
"CMPUBGT",
"CMPUBLE",
"CMPUBLT",
"CMPUBNE",
"MVC",
"MVCIN",
"CLC",
"XC",
"OC",
"NC",
"EXRL",
"LARL",
"LA",
"LAY",
"LAA",
"LAAG",
"LAAL",
"LAALG",
"LAN",
"LANG",
"LAX",
"LAXG",
"LAO",
"LAOG",
"LMY",
"LMG",
"STMY",
"STMG",
"STCK",
"STCKC",
"STCKE",
"STCKF",
"CLEAR",
"VA",
"VAB",
"VAH",
"VAF",
"VAG",
"VAQ",
"VACC",
"VACCB",
"VACCH",
"VACCF",
"VACCG",
"VACCQ",
"VAC",
"VACQ",
"VACCC",
"VACCCQ",
"VN",
"VNC",
"VAVG",
"VAVGB",
"VAVGH",
"VAVGF",
"VAVGG",
"VAVGL",
"VAVGLB",
"VAVGLH",
"VAVGLF",
"VAVGLG",
"VCKSM",
"VCEQ",
"VCEQB",
"VCEQH",
"VCEQF",
"VCEQG",
"VCEQBS",
"VCEQHS",
"VCEQFS",
"VCEQGS",
"VCH",
"VCHB",
"VCHH",
"VCHF",
"VCHG",
"VCHBS",
"VCHHS",
"VCHFS",
"VCHGS",
"VCHL",
"VCHLB",
"VCHLH",
"VCHLF",
"VCHLG",
"VCHLBS",
"VCHLHS",
"VCHLFS",
"VCHLGS",
"VCLZ",
"VCLZB",
"VCLZH",
"VCLZF",
"VCLZG",
"VCTZ",
"VCTZB",
"VCTZH",
"VCTZF",
"VCTZG",
"VEC",
"VECB",
"VECH",
"VECF",
"VECG",
"VECL",
"VECLB",
"VECLH",
"VECLF",
"VECLG",
"VERIM",
"VERIMB",
"VERIMH",
"VERIMF",
"VERIMG",
"VERLL",
"VERLLB",
"VERLLH",
"VERLLF",
"VERLLG",
"VERLLV",
"VERLLVB",
"VERLLVH",
"VERLLVF",
"VERLLVG",
"VESLV",
"VESLVB",
"VESLVH",
"VESLVF",
"VESLVG",
"VESL",
"VESLB",
"VESLH",
"VESLF",
"VESLG",
"VESRA",
"VESRAB",
"VESRAH",
"VESRAF",
"VESRAG",
"VESRAV",
"VESRAVB",
"VESRAVH",
"VESRAVF",
"VESRAVG",
"VESRL",
"VESRLB",
"VESRLH",
"VESRLF",
"VESRLG",
"VESRLV",
"VESRLVB",
"VESRLVH",
"VESRLVF",
"VESRLVG",
"VX",
"VFAE",
"VFAEB",
"VFAEH",
"VFAEF",
"VFAEBS",
"VFAEHS",
"VFAEFS",
"VFAEZB",
"VFAEZH",
"VFAEZF",
"VFAEZBS",
"VFAEZHS",
"VFAEZFS",
"VFEE",
"VFEEB",
"VFEEH",
"VFEEF",
"VFEEBS",
"VFEEHS",
"VFEEFS",
"VFEEZB",
"VFEEZH",
"VFEEZF",
"VFEEZBS",
"VFEEZHS",
"VFEEZFS",
"VFENE",
"VFENEB",
"VFENEH",
"VFENEF",
"VFENEBS",
"VFENEHS",
"VFENEFS",
"VFENEZB",
"VFENEZH",
"VFENEZF",
"VFENEZBS",
"VFENEZHS",
"VFENEZFS",
"VFA",
"VFADB",
"WFADB",
"WFK",
"WFKDB",
"VFCE",
"VFCEDB",
"VFCEDBS",
"WFCEDB",
"WFCEDBS",
"VFCH",
"VFCHDB",
"VFCHDBS",
"WFCHDB",
"WFCHDBS",
"VFCHE",
"VFCHEDB",
"VFCHEDBS",
"WFCHEDB",
"WFCHEDBS",
"WFC",
"WFCDB",
"VCDG",
"VCDGB",
"WCDGB",
"VCDLG",
"VCDLGB",
"WCDLGB",
"VCGD",
"VCGDB",
"WCGDB",
"VCLGD",
"VCLGDB",
"WCLGDB",
"VFD",
"VFDDB",
"WFDDB",
"VLDE",
"VLDEB",
"WLDEB",
"VLED",
"VLEDB",
"WLEDB",
"VFM",
"VFMDB",
"WFMDB",
"VFMA",
"VFMADB",
"WFMADB",
"VFMS",
"VFMSDB",
"WFMSDB",
"VFPSO",
"VFPSODB",
"WFPSODB",
"VFLCDB",
"WFLCDB",
"VFLNDB",
"WFLNDB",
"VFLPDB",
"WFLPDB",
"VFSQ",
"VFSQDB",
"WFSQDB",
"VFS",
"VFSDB",
"WFSDB",
"VFTCI",
"VFTCIDB",
"WFTCIDB",
"VGFM",
"VGFMB",
"VGFMH",
"VGFMF",
"VGFMG",
"VGFMA",
"VGFMAB",
"VGFMAH",
"VGFMAF",
"VGFMAG",
"VGEF",
"VGEG",
"VGBM",
"VZERO",
"VONE",
"VGM",
"VGMB",
"VGMH",
"VGMF",
"VGMG",
"VISTR",
"VISTRB",
"VISTRH",
"VISTRF",
"VISTRBS",
"VISTRHS",
"VISTRFS",
"VL",
"VLR",
"VLREP",
"VLREPB",
"VLREPH",
"VLREPF",
"VLREPG",
"VLC",
"VLCB",
"VLCH",
"VLCF",
"VLCG",
"VLEH",
"VLEF",
"VLEG",
"VLEB",
"VLEIH",
"VLEIF",
"VLEIG",
"VLEIB",
"VFI",
"VFIDB",
"WFIDB",
"VLGV",
"VLGVB",
"VLGVH",
"VLGVF",
"VLGVG",
"VLLEZ",
"VLLEZB",
"VLLEZH",
"VLLEZF",
"VLLEZG",
"VLM",
"VLP",
"VLPB",
"VLPH",
"VLPF",
"VLPG",
"VLBB",
"VLVG",
"VLVGB",
"VLVGH",
"VLVGF",
"VLVGG",
"VLVGP",
"VLL",
"VMX",
"VMXB",
"VMXH",
"VMXF",
"VMXG",
"VMXL",
"VMXLB",
"VMXLH",
"VMXLF",
"VMXLG",
"VMRH",
"VMRHB",
"VMRHH",
"VMRHF",
"VMRHG",
"VMRL",
"VMRLB",
"VMRLH",
"VMRLF",
"VMRLG",
"VMN",
"VMNB",
"VMNH",
"VMNF",
"VMNG",
"VMNL",
"VMNLB",
"VMNLH",
"VMNLF",
"VMNLG",
"VMAE",
"VMAEB",
"VMAEH",
"VMAEF",
"VMAH",
"VMAHB",
"VMAHH",
"VMAHF",
"VMALE",
"VMALEB",
"VMALEH",
"VMALEF",
"VMALH",
"VMALHB",
"VMALHH",
"VMALHF",
"VMALO",
"VMALOB",
"VMALOH",
"VMALOF",
"VMAL",
"VMALB",
"VMALHW",
"VMALF",
"VMAO",
"VMAOB",
"VMAOH",
"VMAOF",
"VME",
"VMEB",
"VMEH",
"VMEF",
"VMH",
"VMHB",
"VMHH",
"VMHF",
"VMLE",
"VMLEB",
"VMLEH",
"VMLEF",
"VMLH",
"VMLHB",
"VMLHH",
"VMLHF",
"VMLO",
"VMLOB",
"VMLOH",
"VMLOF",
"VML",
"VMLB",
"VMLHW",
"VMLF",
"VMO",
"VMOB",
"VMOH",
"VMOF",
"VNO",
"VNOT",
"VO",
"VPK",
"VPKH",
"VPKF",
"VPKG",
"VPKLS",
"VPKLSH",
"VPKLSF",
"VPKLSG",
"VPKLSHS",
"VPKLSFS",
"VPKLSGS",
"VPKS",
"VPKSH",
"VPKSF",
"VPKSG",
"VPKSHS",
"VPKSFS",
"VPKSGS",
"VPERM",
"VPDI",
"VPOPCT",
"VREP",
"VREPB",
"VREPH",
"VREPF",
"VREPG",
"VREPI",
"VREPIB",
"VREPIH",
"VREPIF",
"VREPIG",
"VSCEF",
"VSCEG",
"VSEL",
"VSL",
"VSLB",
"VSLDB",
"VSRA",
"VSRAB",
"VSRL",
"VSRLB",
"VSEG",
"VSEGB",
"VSEGH",
"VSEGF",
"VST",
"VSTEH",
"VSTEF",
"VSTEG",
"VSTEB",
"VSTM",
"VSTL",
"VSTRC",
"VSTRCB",
"VSTRCH",
"VSTRCF",
"VSTRCBS",
"VSTRCHS",
"VSTRCFS",
"VSTRCZB",
"VSTRCZH",
"VSTRCZF",
"VSTRCZBS",
"VSTRCZHS",
"VSTRCZFS",
"VS",
"VSB",
"VSH",
"VSF",
"VSG",
"VSQ",
"VSCBI",
"VSCBIB",
"VSCBIH",
"VSCBIF",
"VSCBIG",
"VSCBIQ",
"VSBCBI",
"VSBCBIQ",
"VSBI",
"VSBIQ",
"VSUMG",
"VSUMGH",
"VSUMGF",
"VSUMQ",
"VSUMQF",
"VSUMQG",
"VSUM",
"VSUMB",
"VSUMH",
"VTM",
"VUPH",
"VUPHB",
"VUPHH",
"VUPHF",
"VUPLH",
"VUPLHB",
"VUPLHH",
"VUPLHF",
"VUPLL",
"VUPLLB",
"VUPLLH",
"VUPLLF",
"VUPL",
"VUPLB",
"VUPLHW",
"VUPLF",
"VMSLG",
"VMSLEG",
"VMSLOG",
"VMSLEOG",
"NOPH",
"BYTE",
"WORD",
"DWORD",
"LAST",
}

View File

@ -0,0 +1,39 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package s390x
var cnamesz = []string{
"NONE",
"REG",
"FREG",
"VREG",
"AREG",
"ZCON",
"SCON",
"UCON",
"ADDCON",
"ANDCON",
"LCON",
"DCON",
"SACON",
"LACON",
"DACON",
"SBRA",
"LBRA",
"SAUTO",
"LAUTO",
"ZOREG",
"SOREG",
"LOREG",
"TLS_LE",
"TLS_IE",
"GOK",
"ADDR",
"SYMADDR",
"GOTADDR",
"TEXTSIZE",
"ANY",
"NCLASS",
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,126 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package s390x
import (
"fmt"
)
// CCMask represents a 4-bit condition code mask. Bits that
// are not part of the mask should be 0.
//
// Condition code masks represent the 4 possible values of
// the 2-bit condition code as individual bits. Since IBM Z
// is a big-endian platform bits are numbered from left to
// right. The lowest value, 0, is represented by 8 (0b1000)
// and the highest value, 3, is represented by 1 (0b0001).
//
// Note that condition code values have different semantics
// depending on the instruction that set the condition code.
// The names given here assume that the condition code was
// set by an integer or floating point comparison. Other
// instructions may use these same codes to indicate
// different results such as a carry or overflow.
type CCMask uint8
const (
Never CCMask = 0 // no-op
// 1-bit masks
Equal CCMask = 1 << 3
Less CCMask = 1 << 2
Greater CCMask = 1 << 1
Unordered CCMask = 1 << 0
// 2-bit masks
EqualOrUnordered CCMask = Equal | Unordered // not less and not greater
LessOrEqual CCMask = Less | Equal // ordered and not greater
LessOrGreater CCMask = Less | Greater // ordered and not equal
LessOrUnordered CCMask = Less | Unordered // not greater and not equal
GreaterOrEqual CCMask = Greater | Equal // ordered and not less
GreaterOrUnordered CCMask = Greater | Unordered // not less and not equal
// 3-bit masks
NotEqual CCMask = Always ^ Equal
NotLess CCMask = Always ^ Less
NotGreater CCMask = Always ^ Greater
NotUnordered CCMask = Always ^ Unordered
// 4-bit mask
Always CCMask = Equal | Less | Greater | Unordered
// useful aliases
Carry CCMask = GreaterOrUnordered
NoCarry CCMask = LessOrEqual
Borrow CCMask = NoCarry
NoBorrow CCMask = Carry
)
// Inverse returns the complement of the condition code mask.
func (c CCMask) Inverse() CCMask {
return c ^ Always
}
// ReverseComparison swaps the bits at 0b0100 and 0b0010 in the mask,
// reversing the behavior of greater than and less than conditions.
func (c CCMask) ReverseComparison() CCMask {
r := c & EqualOrUnordered
if c&Less != 0 {
r |= Greater
}
if c&Greater != 0 {
r |= Less
}
return r
}
func (c CCMask) String() string {
switch c {
// 0-bit mask
case Never:
return "Never"
// 1-bit masks
case Equal:
return "Equal"
case Less:
return "Less"
case Greater:
return "Greater"
case Unordered:
return "Unordered"
// 2-bit masks
case EqualOrUnordered:
return "EqualOrUnordered"
case LessOrEqual:
return "LessOrEqual"
case LessOrGreater:
return "LessOrGreater"
case LessOrUnordered:
return "LessOrUnordered"
case GreaterOrEqual:
return "GreaterOrEqual"
case GreaterOrUnordered:
return "GreaterOrUnordered"
// 3-bit masks
case NotEqual:
return "NotEqual"
case NotLess:
return "NotLess"
case NotGreater:
return "NotGreater"
case NotUnordered:
return "NotUnordered"
// 4-bit mask
case Always:
return "Always"
}
// invalid
return fmt.Sprintf("Invalid (%#x)", c)
}

View File

@ -0,0 +1,73 @@
// Based on cmd/internal/obj/ppc64/list9.go.
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package s390x
import (
"github.com/twitchyliquid64/golang-asm/obj"
"fmt"
)
func init() {
obj.RegisterRegister(obj.RBaseS390X, REG_R0+1024, rconv)
obj.RegisterOpcode(obj.ABaseS390X, Anames)
}
func rconv(r int) string {
if r == 0 {
return "NONE"
}
if r == REGG {
// Special case.
return "g"
}
if REG_R0 <= r && r <= REG_R15 {
return fmt.Sprintf("R%d", r-REG_R0)
}
if REG_F0 <= r && r <= REG_F15 {
return fmt.Sprintf("F%d", r-REG_F0)
}
if REG_AR0 <= r && r <= REG_AR15 {
return fmt.Sprintf("AR%d", r-REG_AR0)
}
if REG_V0 <= r && r <= REG_V31 {
return fmt.Sprintf("V%d", r-REG_V0)
}
return fmt.Sprintf("Rgok(%d)", r-obj.RBaseS390X)
}
func DRconv(a int) string {
s := "C_??"
if a >= C_NONE && a <= C_NCLASS {
s = cnamesz[a]
}
var fp string
fp += s
return fp
}

View File

@ -0,0 +1,735 @@
// Based on cmd/internal/obj/ppc64/obj9.go.
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package s390x
import (
"github.com/twitchyliquid64/golang-asm/obj"
"github.com/twitchyliquid64/golang-asm/objabi"
"github.com/twitchyliquid64/golang-asm/sys"
"math"
)
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p.From.Class = 0
p.To.Class = 0
c := ctxtz{ctxt: ctxt, newprog: newprog}
// Rewrite BR/BL to symbol as TYPE_BRANCH.
switch p.As {
case ABR, ABL, obj.ARET, obj.ADUFFZERO, obj.ADUFFCOPY:
if p.To.Sym != nil {
p.To.Type = obj.TYPE_BRANCH
}
}
// Rewrite float constants to values stored in memory unless they are +0.
switch p.As {
case AFMOVS:
if p.From.Type == obj.TYPE_FCONST {
f32 := float32(p.From.Val.(float64))
if math.Float32bits(f32) == 0 { // +0
break
}
p.From.Type = obj.TYPE_MEM
p.From.Sym = ctxt.Float32Sym(f32)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
case AFMOVD:
if p.From.Type == obj.TYPE_FCONST {
f64 := p.From.Val.(float64)
if math.Float64bits(f64) == 0 { // +0
break
}
p.From.Type = obj.TYPE_MEM
p.From.Sym = ctxt.Float64Sym(f64)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
// put constants not loadable by LOAD IMMEDIATE into memory
case AMOVD:
if p.From.Type == obj.TYPE_CONST {
val := p.From.Offset
if int64(int32(val)) != val &&
int64(uint32(val)) != val &&
int64(uint64(val)&(0xffffffff<<32)) != val {
p.From.Type = obj.TYPE_MEM
p.From.Sym = ctxt.Int64Sym(p.From.Offset)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
}
}
// Rewrite SUB constants into ADD.
switch p.As {
case ASUBC:
if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) {
p.From.Offset = -p.From.Offset
p.As = AADDC
}
case ASUB:
if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) {
p.From.Offset = -p.From.Offset
p.As = AADD
}
}
if c.ctxt.Flag_dynlink {
c.rewriteToUseGot(p)
}
}
// Rewrite p, if necessary, to access global data via the global offset table.
func (c *ctxtz) rewriteToUseGot(p *obj.Prog) {
// At the moment EXRL instructions are not emitted by the compiler and only reference local symbols in
// assembly code.
if p.As == AEXRL {
return
}
// We only care about global data: NAME_EXTERN means a global
// symbol in the Go sense, and p.Sym.Local is true for a few
// internally defined symbols.
// Rewrites must not clobber flags and therefore cannot use the
// ADD instruction.
if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
// MOVD $sym, Rx becomes MOVD sym@GOT, Rx
// MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx or REGTMP2; MOVD $<off>(Rx or REGTMP2), Rx
if p.To.Type != obj.TYPE_REG || p.As != AMOVD {
c.ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
}
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
q := p
if p.From.Offset != 0 {
target := p.To.Reg
if target == REG_R0 {
// Cannot use R0 as input to address calculation.
// REGTMP might be used by the assembler.
p.To.Reg = REGTMP2
}
q = obj.Appendp(q, c.newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_ADDR
q.From.Offset = p.From.Offset
q.From.Reg = p.To.Reg
q.To.Type = obj.TYPE_REG
q.To.Reg = target
p.From.Offset = 0
}
}
if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
var source *obj.Addr
// MOVD sym, Ry becomes MOVD sym@GOT, REGTMP2; MOVD (REGTMP2), Ry
// MOVD Ry, sym becomes MOVD sym@GOT, REGTMP2; MOVD Ry, (REGTMP2)
// An addition may be inserted between the two MOVs if there is an offset.
if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
}
source = &p.From
} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
source = &p.To
} else {
return
}
if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
return
}
if source.Sym.Type == objabi.STLSBSS {
return
}
if source.Type != obj.TYPE_MEM {
c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
p1 := obj.Appendp(p, c.newprog)
p2 := obj.Appendp(p1, c.newprog)
p1.As = AMOVD
p1.From.Type = obj.TYPE_MEM
p1.From.Sym = source.Sym
p1.From.Name = obj.NAME_GOTREF
p1.To.Type = obj.TYPE_REG
p1.To.Reg = REGTMP2
p2.As = p.As
p2.From = p.From
p2.To = p.To
if p.From.Name == obj.NAME_EXTERN {
p2.From.Reg = REGTMP2
p2.From.Name = obj.NAME_NONE
p2.From.Sym = nil
} else if p.To.Name == obj.NAME_EXTERN {
p2.To.Reg = REGTMP2
p2.To.Name = obj.NAME_NONE
p2.To.Sym = nil
} else {
return
}
obj.Nopout(p)
}
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// TODO(minux): add morestack short-cuts with small fixed frame-size.
if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
return
}
c := ctxtz{ctxt: ctxt, cursym: cursym, newprog: newprog}
p := c.cursym.Func.Text
textstksiz := p.To.Offset
if textstksiz == -8 {
// Compatibility hack.
p.From.Sym.Set(obj.AttrNoFrame, true)
textstksiz = 0
}
if textstksiz%8 != 0 {
c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
}
if p.From.Sym.NoFrame() {
if textstksiz != 0 {
c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
}
}
c.cursym.Func.Args = p.To.Val.(int32)
c.cursym.Func.Locals = int32(textstksiz)
/*
* find leaf subroutines
* strip NOPs
* expand RET
*/
var q *obj.Prog
for p := c.cursym.Func.Text; p != nil; p = p.Link {
switch p.As {
case obj.ATEXT:
q = p
p.Mark |= LEAF
case ABL, ABCL:
q = p
c.cursym.Func.Text.Mark &^= LEAF
fallthrough
case ABC,
ABRC,
ABEQ,
ABGE,
ABGT,
ABLE,
ABLT,
ABLEU,
ABLTU,
ABNE,
ABR,
ABVC,
ABVS,
ACRJ,
ACGRJ,
ACLRJ,
ACLGRJ,
ACIJ,
ACGIJ,
ACLIJ,
ACLGIJ,
ACMPBEQ,
ACMPBGE,
ACMPBGT,
ACMPBLE,
ACMPBLT,
ACMPBNE,
ACMPUBEQ,
ACMPUBGE,
ACMPUBGT,
ACMPUBLE,
ACMPUBLT,
ACMPUBNE:
q = p
p.Mark |= BRANCH
default:
q = p
}
}
autosize := int32(0)
var pLast *obj.Prog
var pPre *obj.Prog
var pPreempt *obj.Prog
wasSplit := false
for p := c.cursym.Func.Text; p != nil; p = p.Link {
pLast = p
switch p.As {
case obj.ATEXT:
autosize = int32(textstksiz)
if p.Mark&LEAF != 0 && autosize == 0 {
// A leaf function with no locals has no frame.
p.From.Sym.Set(obj.AttrNoFrame, true)
}
if !p.From.Sym.NoFrame() {
// If there is a stack frame at all, it includes
// space to save the LR.
autosize += int32(c.ctxt.FixedFrameSize())
}
if p.Mark&LEAF != 0 && autosize < objabi.StackSmall {
// A leaf function with a small stack can be marked
// NOSPLIT, avoiding a stack check.
p.From.Sym.Set(obj.AttrNoSplit, true)
}
p.To.Offset = int64(autosize)
q := p
if !p.From.Sym.NoSplit() {
p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check
pPre = p
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
wasSplit = true //need post part of split
}
if autosize != 0 {
// Make sure to save link register for non-empty frame, even if
// it is a leaf function, so that traceback works.
// Store link register before decrementing SP, so if a signal comes
// during the execution of the function prologue, the traceback
// code will not see a half-updated stack frame.
// This sequence is not async preemptible, as if we open a frame
// at the current SP, it will clobber the saved LR.
q = c.ctxt.StartUnsafePoint(p, c.newprog)
q = obj.Appendp(q, c.newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_LR
q.To.Type = obj.TYPE_MEM
q.To.Reg = REGSP
q.To.Offset = int64(-autosize)
q = obj.Appendp(q, c.newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_ADDR
q.From.Offset = int64(-autosize)
q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided
q.To.Type = obj.TYPE_REG
q.To.Reg = REGSP
q.Spadj = autosize
q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
} else if c.cursym.Func.Text.Mark&LEAF == 0 {
// A very few functions that do not return to their caller
// (e.g. gogo) are not identified as leaves but still have
// no frame.
c.cursym.Func.Text.Mark |= LEAF
}
if c.cursym.Func.Text.Mark&LEAF != 0 {
c.cursym.Set(obj.AttrLeaf, true)
break
}
if c.cursym.Func.Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOVD g_panic(g), R3
// CMP R3, $0
// BEQ end
// MOVD panic_argp(R3), R4
// ADD $(autosize+8), R1, R5
// CMP R4, R5
// BNE end
// ADD $8, R1, R6
// MOVD R6, panic_argp(R3)
// end:
// NOP
//
// The NOP is needed to give the jumps somewhere to land.
// It is a liblink NOP, not a s390x NOP: it encodes to 0 instruction bytes.
q = obj.Appendp(q, c.newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REGG
q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R3
q = obj.Appendp(q, c.newprog)
q.As = ACMP
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R3
q.To.Type = obj.TYPE_CONST
q.To.Offset = 0
q = obj.Appendp(q, c.newprog)
q.As = ABEQ
q.To.Type = obj.TYPE_BRANCH
p1 := q
q = obj.Appendp(q, c.newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REG_R3
q.From.Offset = 0 // Panic.argp
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R4
q = obj.Appendp(q, c.newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
q.Reg = REGSP
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R5
q = obj.Appendp(q, c.newprog)
q.As = ACMP
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R4
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R5
q = obj.Appendp(q, c.newprog)
q.As = ABNE
q.To.Type = obj.TYPE_BRANCH
p2 := q
q = obj.Appendp(q, c.newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = c.ctxt.FixedFrameSize()
q.Reg = REGSP
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R6
q = obj.Appendp(q, c.newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R6
q.To.Type = obj.TYPE_MEM
q.To.Reg = REG_R3
q.To.Offset = 0 // Panic.argp
q = obj.Appendp(q, c.newprog)
q.As = obj.ANOP
p1.To.SetTarget(q)
p2.To.SetTarget(q)
}
case obj.ARET:
retTarget := p.To.Sym
if c.cursym.Func.Text.Mark&LEAF != 0 {
if autosize == 0 {
p.As = ABR
p.From = obj.Addr{}
if retTarget == nil {
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_LR
} else {
p.To.Type = obj.TYPE_BRANCH
p.To.Sym = retTarget
}
p.Mark |= BRANCH
break
}
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(autosize)
p.To.Type = obj.TYPE_REG
p.To.Reg = REGSP
p.Spadj = -autosize
q = obj.Appendp(p, c.newprog)
q.As = ABR
q.From = obj.Addr{}
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_LR
q.Mark |= BRANCH
q.Spadj = autosize
break
}
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGSP
p.From.Offset = 0
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_LR
q = p
if autosize != 0 {
q = obj.Appendp(q, c.newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(autosize)
q.To.Type = obj.TYPE_REG
q.To.Reg = REGSP
q.Spadj = -autosize
}
q = obj.Appendp(q, c.newprog)
q.As = ABR
q.From = obj.Addr{}
if retTarget == nil {
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_LR
} else {
q.To.Type = obj.TYPE_BRANCH
q.To.Sym = retTarget
}
q.Mark |= BRANCH
q.Spadj = autosize
case AADD:
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
p.Spadj = int32(-p.From.Offset)
}
case obj.AGETCALLERPC:
if cursym.Leaf() {
/* MOVD LR, Rd */
p.As = AMOVD
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_LR
} else {
/* MOVD (RSP), Rd */
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGSP
}
}
}
if wasSplit {
c.stacksplitPost(pLast, pPre, pPreempt, autosize) // emit post part of split check
}
}
func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) {
var q *obj.Prog
// MOVD g_stackguard(g), R3
p = obj.Appendp(p, c.newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
if c.cursym.CFunc() {
p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
// Mark the stack bound check and morestack call async nonpreemptible.
// If we get preempted here, when resumed the preemption request is
// cleared, but we'll still call morestack, which will double the stack
// unnecessarily. See issue #35470.
p = c.ctxt.StartUnsafePoint(p, c.newprog)
q = nil
if framesize <= objabi.StackSmall {
// small stack: SP < stackguard
// CMPUBGE stackguard, SP, label-of-call-to-morestack
p = obj.Appendp(p, c.newprog)
//q1 = p
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.Reg = REGSP
p.As = ACMPUBGE
p.To.Type = obj.TYPE_BRANCH
} else if framesize <= objabi.StackBig {
// large stack: SP-framesize < stackguard-StackSmall
// ADD $-(framesize-StackSmall), SP, R4
// CMPUBGE stackguard, R4, label-of-call-to-morestack
p = obj.Appendp(p, c.newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = -(int64(framesize) - objabi.StackSmall)
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
p = obj.Appendp(p, c.newprog)
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.Reg = REG_R4
p.As = ACMPUBGE
p.To.Type = obj.TYPE_BRANCH
} else {
// Such a large stack we need to protect against wraparound.
// If SP is close to zero:
// SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
// The +StackGuard on both sides is required to keep the left side positive:
// SP is allowed to be slightly below stackguard. See stack.h.
//
// Preemption sets stackguard to StackPreempt, a very large value.
// That breaks the math above, so we have to check for that explicitly.
// // stackguard is R3
// CMP R3, $StackPreempt
// BEQ label-of-call-to-morestack
// ADD $StackGuard, SP, R4
// SUB R3, R4
// MOVD $(framesize+(StackGuard-StackSmall)), TEMP
// CMPUBGE TEMP, R4, label-of-call-to-morestack
p = obj.Appendp(p, c.newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.To.Type = obj.TYPE_CONST
p.To.Offset = objabi.StackPreempt
p = obj.Appendp(p, c.newprog)
q = p
p.As = ABEQ
p.To.Type = obj.TYPE_BRANCH
p = obj.Appendp(p, c.newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(objabi.StackGuard)
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
p = obj.Appendp(p, c.newprog)
p.As = ASUB
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
p = obj.Appendp(p, c.newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall
p.To.Type = obj.TYPE_REG
p.To.Reg = REGTMP
p = obj.Appendp(p, c.newprog)
p.From.Type = obj.TYPE_REG
p.From.Reg = REGTMP
p.Reg = REG_R4
p.As = ACMPUBGE
p.To.Type = obj.TYPE_BRANCH
}
return p, q
}
func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog {
// Now we are at the end of the function, but logically
// we are still in function prologue. We need to fix the
// SP data and PCDATA.
spfix := obj.Appendp(p, c.newprog)
spfix.As = obj.ANOP
spfix.Spadj = -framesize
pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
// MOVD LR, R5
p = obj.Appendp(pcdata, c.newprog)
pPre.To.SetTarget(p)
p.As = AMOVD
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_LR
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R5
if pPreempt != nil {
pPreempt.To.SetTarget(p)
}
// BL runtime.morestack(SB)
p = obj.Appendp(p, c.newprog)
p.As = ABL
p.To.Type = obj.TYPE_BRANCH
if c.cursym.CFunc() {
p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
} else {
p.To.Sym = c.ctxt.Lookup("runtime.morestack")
}
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
// BR start
p = obj.Appendp(p, c.newprog)
p.As = ABR
p.To.Type = obj.TYPE_BRANCH
p.To.SetTarget(c.cursym.Func.Text.Link)
return p
}
var unaryDst = map[obj.As]bool{
ASTCK: true,
ASTCKC: true,
ASTCKE: true,
ASTCKF: true,
ANEG: true,
ANEGW: true,
AVONE: true,
AVZERO: true,
}
var Links390x = obj.LinkArch{
Arch: sys.ArchS390X,
Init: buildop,
Preprocess: preprocess,
Assemble: spanz,
Progedit: progedit,
UnaryDst: unaryDst,
DWARFRegisters: S390XDWARFRegisters,
}

View File

@ -0,0 +1,47 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package s390x
// RotateParams represents the immediates required for a "rotate
// then ... selected bits instruction".
//
// The Start and End values are the indexes that represent
// the masked region. They are inclusive and are in big-
// endian order (bit 0 is the MSB, bit 63 is the LSB). They
// may wrap around.
//
// Some examples:
//
// Masked region | Start | End
// --------------------------+-------+----
// 0x00_00_00_00_00_00_00_0f | 60 | 63
// 0xf0_00_00_00_00_00_00_00 | 0 | 3
// 0xf0_00_00_00_00_00_00_0f | 60 | 3
//
// The Amount value represents the amount to rotate the
// input left by. Note that this rotation is performed
// before the masked region is used.
type RotateParams struct {
Start uint8 // big-endian start bit index [0..63]
End uint8 // big-endian end bit index [0..63]
Amount uint8 // amount to rotate left
}
func NewRotateParams(start, end, amount int64) RotateParams {
if start&^63 != 0 {
panic("start out of bounds")
}
if end&^63 != 0 {
panic("end out of bounds")
}
if amount&^63 != 0 {
panic("amount out of bounds")
}
return RotateParams{
Start: uint8(start),
End: uint8(end),
Amount: uint8(amount),
}
}

File diff suppressed because it is too large Load Diff

421
vendor/github.com/twitchyliquid64/golang-asm/obj/sym.go generated vendored Normal file
View File

@ -0,0 +1,421 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package obj
import (
"github.com/twitchyliquid64/golang-asm/goobj"
"github.com/twitchyliquid64/golang-asm/objabi"
"fmt"
"log"
"math"
"sort"
)
func Linknew(arch *LinkArch) *Link {
ctxt := new(Link)
ctxt.hash = make(map[string]*LSym)
ctxt.funchash = make(map[string]*LSym)
ctxt.statichash = make(map[string]*LSym)
ctxt.Arch = arch
ctxt.Pathname = objabi.WorkingDir()
if err := ctxt.Headtype.Set(objabi.GOOS); err != nil {
log.Fatalf("unknown goos %s", objabi.GOOS)
}
ctxt.Flag_optimize = true
return ctxt
}
// LookupDerived looks up or creates the symbol with name name derived from symbol s.
// The resulting symbol will be static iff s is.
func (ctxt *Link) LookupDerived(s *LSym, name string) *LSym {
if s.Static() {
return ctxt.LookupStatic(name)
}
return ctxt.Lookup(name)
}
// LookupStatic looks up the static symbol with name name.
// If it does not exist, it creates it.
func (ctxt *Link) LookupStatic(name string) *LSym {
s := ctxt.statichash[name]
if s == nil {
s = &LSym{Name: name, Attribute: AttrStatic}
ctxt.statichash[name] = s
}
return s
}
// LookupABI looks up a symbol with the given ABI.
// If it does not exist, it creates it.
func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
return ctxt.LookupABIInit(name, abi, nil)
}
// LookupABI looks up a symbol with the given ABI.
// If it does not exist, it creates it and
// passes it to init for one-time initialization.
func (ctxt *Link) LookupABIInit(name string, abi ABI, init func(s *LSym)) *LSym {
var hash map[string]*LSym
switch abi {
case ABI0:
hash = ctxt.hash
case ABIInternal:
hash = ctxt.funchash
default:
panic("unknown ABI")
}
ctxt.hashmu.Lock()
s := hash[name]
if s == nil {
s = &LSym{Name: name}
s.SetABI(abi)
hash[name] = s
if init != nil {
init(s)
}
}
ctxt.hashmu.Unlock()
return s
}
// Lookup looks up the symbol with name name.
// If it does not exist, it creates it.
func (ctxt *Link) Lookup(name string) *LSym {
return ctxt.LookupInit(name, nil)
}
// LookupInit looks up the symbol with name name.
// If it does not exist, it creates it and
// passes it to init for one-time initialization.
func (ctxt *Link) LookupInit(name string, init func(s *LSym)) *LSym {
ctxt.hashmu.Lock()
s := ctxt.hash[name]
if s == nil {
s = &LSym{Name: name}
ctxt.hash[name] = s
if init != nil {
init(s)
}
}
ctxt.hashmu.Unlock()
return s
}
func (ctxt *Link) Float32Sym(f float32) *LSym {
i := math.Float32bits(f)
name := fmt.Sprintf("$f32.%08x", i)
return ctxt.LookupInit(name, func(s *LSym) {
s.Size = 4
s.WriteFloat32(ctxt, 0, f)
s.Type = objabi.SRODATA
s.Set(AttrLocal, true)
s.Set(AttrContentAddressable, true)
ctxt.constSyms = append(ctxt.constSyms, s)
})
}
func (ctxt *Link) Float64Sym(f float64) *LSym {
i := math.Float64bits(f)
name := fmt.Sprintf("$f64.%016x", i)
return ctxt.LookupInit(name, func(s *LSym) {
s.Size = 8
s.WriteFloat64(ctxt, 0, f)
s.Type = objabi.SRODATA
s.Set(AttrLocal, true)
s.Set(AttrContentAddressable, true)
ctxt.constSyms = append(ctxt.constSyms, s)
})
}
func (ctxt *Link) Int64Sym(i int64) *LSym {
name := fmt.Sprintf("$i64.%016x", uint64(i))
return ctxt.LookupInit(name, func(s *LSym) {
s.Size = 8
s.WriteInt(ctxt, 0, 8, i)
s.Type = objabi.SRODATA
s.Set(AttrLocal, true)
s.Set(AttrContentAddressable, true)
ctxt.constSyms = append(ctxt.constSyms, s)
})
}
// Assign index to symbols.
// asm is set to true if this is called by the assembler (i.e. not the compiler),
// in which case all the symbols are non-package (for now).
func (ctxt *Link) NumberSyms() {
if ctxt.Headtype == objabi.Haix {
// Data must be sorted to keep a constant order in TOC symbols.
// As they are created during Progedit, two symbols can be switched between
// two different compilations. Therefore, BuildID will be different.
// TODO: find a better place and optimize to only sort TOC symbols
sort.Slice(ctxt.Data, func(i, j int) bool {
return ctxt.Data[i].Name < ctxt.Data[j].Name
})
}
// Constant symbols are created late in the concurrent phase. Sort them
// to ensure a deterministic order.
sort.Slice(ctxt.constSyms, func(i, j int) bool {
return ctxt.constSyms[i].Name < ctxt.constSyms[j].Name
})
ctxt.Data = append(ctxt.Data, ctxt.constSyms...)
ctxt.constSyms = nil
ctxt.pkgIdx = make(map[string]int32)
ctxt.defs = []*LSym{}
ctxt.hashed64defs = []*LSym{}
ctxt.hasheddefs = []*LSym{}
ctxt.nonpkgdefs = []*LSym{}
var idx, hashedidx, hashed64idx, nonpkgidx int32
ctxt.traverseSyms(traverseDefs, func(s *LSym) {
// if Pkgpath is unknown, cannot hash symbols with relocations, as it
// may reference named symbols whose names are not fully expanded.
if s.ContentAddressable() && (ctxt.Pkgpath != "" || len(s.R) == 0) {
if len(s.P) <= 8 && len(s.R) == 0 { // we can use short hash only for symbols without relocations
s.PkgIdx = goobj.PkgIdxHashed64
s.SymIdx = hashed64idx
if hashed64idx != int32(len(ctxt.hashed64defs)) {
panic("bad index")
}
ctxt.hashed64defs = append(ctxt.hashed64defs, s)
hashed64idx++
} else {
s.PkgIdx = goobj.PkgIdxHashed
s.SymIdx = hashedidx
if hashedidx != int32(len(ctxt.hasheddefs)) {
panic("bad index")
}
ctxt.hasheddefs = append(ctxt.hasheddefs, s)
hashedidx++
}
} else if isNonPkgSym(ctxt, s) {
s.PkgIdx = goobj.PkgIdxNone
s.SymIdx = nonpkgidx
if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
panic("bad index")
}
ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
nonpkgidx++
} else {
s.PkgIdx = goobj.PkgIdxSelf
s.SymIdx = idx
if idx != int32(len(ctxt.defs)) {
panic("bad index")
}
ctxt.defs = append(ctxt.defs, s)
idx++
}
s.Set(AttrIndexed, true)
})
ipkg := int32(1) // 0 is invalid index
nonpkgdef := nonpkgidx
ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
if rs.PkgIdx != goobj.PkgIdxInvalid {
return
}
if !ctxt.Flag_linkshared {
// Assign special index for builtin symbols.
// Don't do it when linking against shared libraries, as the runtime
// may be in a different library.
if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
rs.PkgIdx = goobj.PkgIdxBuiltin
rs.SymIdx = int32(i)
rs.Set(AttrIndexed, true)
return
}
}
pkg := rs.Pkg
if rs.ContentAddressable() {
// for now, only support content-addressable symbols that are always locally defined.
panic("hashed refs unsupported for now")
}
if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
rs.PkgIdx = goobj.PkgIdxNone
rs.SymIdx = nonpkgidx
rs.Set(AttrIndexed, true)
if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
panic("bad index")
}
ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
nonpkgidx++
return
}
if k, ok := ctxt.pkgIdx[pkg]; ok {
rs.PkgIdx = k
return
}
rs.PkgIdx = ipkg
ctxt.pkgIdx[pkg] = ipkg
ipkg++
})
}
// Returns whether s is a non-package symbol, which needs to be referenced
// by name instead of by index.
func isNonPkgSym(ctxt *Link, s *LSym) bool {
if ctxt.IsAsm && !s.Static() {
// asm symbols are referenced by name only, except static symbols
// which are file-local and can be referenced by index.
return true
}
if ctxt.Flag_linkshared {
// The referenced symbol may be in a different shared library so
// the linker cannot see its index.
return true
}
if s.Pkg == "_" {
// The frontend uses package "_" to mark symbols that should not
// be referenced by index, e.g. linkname'd symbols.
return true
}
if s.DuplicateOK() {
// Dupok symbol needs to be dedup'd by name.
return true
}
return false
}
// StaticNamePref is the prefix the front end applies to static temporary
// variables. When turned into LSyms, these can be tagged as static so
// as to avoid inserting them into the linker's name lookup tables.
const StaticNamePref = ".stmp_"
type traverseFlag uint32
const (
traverseDefs traverseFlag = 1 << iota
traverseRefs
traverseAux
traverseAll = traverseDefs | traverseRefs | traverseAux
)
// Traverse symbols based on flag, call fn for each symbol.
func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
for _, list := range lists {
for _, s := range list {
if flag&traverseDefs != 0 {
fn(s)
}
if flag&traverseRefs != 0 {
for _, r := range s.R {
if r.Sym != nil {
fn(r.Sym)
}
}
}
if flag&traverseAux != 0 {
if s.Gotype != nil {
fn(s.Gotype)
}
if s.Type == objabi.STEXT {
f := func(parent *LSym, aux *LSym) {
fn(aux)
}
ctxt.traverseFuncAux(flag, s, f)
}
}
}
}
}
func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym)) {
pc := &fsym.Func.Pcln
if flag&traverseAux == 0 {
// NB: should it become necessary to walk aux sym reloc references
// without walking the aux syms themselves, this can be changed.
panic("should not be here")
}
for _, d := range pc.Funcdata {
if d != nil {
fn(fsym, d)
}
}
files := ctxt.PosTable.FileTable()
usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles))
for f := range pc.UsedFiles {
usedFiles = append(usedFiles, f)
}
sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] })
for _, f := range usedFiles {
if filesym := ctxt.Lookup(files[f]); filesym != nil {
fn(fsym, filesym)
}
}
for _, call := range pc.InlTree.nodes {
if call.Func != nil {
fn(fsym, call.Func)
}
f, _ := linkgetlineFromPos(ctxt, call.Pos)
if filesym := ctxt.Lookup(f); filesym != nil {
fn(fsym, filesym)
}
}
dwsyms := []*LSym{fsym.Func.dwarfRangesSym, fsym.Func.dwarfLocSym, fsym.Func.dwarfDebugLinesSym, fsym.Func.dwarfInfoSym}
for _, dws := range dwsyms {
if dws == nil || dws.Size == 0 {
continue
}
fn(fsym, dws)
if flag&traverseRefs != 0 {
for _, r := range dws.R {
if r.Sym != nil {
fn(dws, r.Sym)
}
}
}
}
}
// Traverse aux symbols, calling fn for each sym/aux pair.
func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) {
lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
for _, list := range lists {
for _, s := range list {
if s.Gotype != nil {
if flag&traverseDefs != 0 {
fn(s, s.Gotype)
}
}
if s.Type != objabi.STEXT {
continue
}
ctxt.traverseFuncAux(flag, s, fn)
}
}
}

View File

@ -0,0 +1,54 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file defines flags attached to various functions
// and data objects. The compilers, assemblers, and linker must
// all agree on these values.
package obj
const (
// Don't profile the marked routine.
//
// Deprecated: Not implemented, do not use.
NOPROF = 1
// It is ok for the linker to get multiple of these symbols. It will
// pick one of the duplicates to use.
DUPOK = 2
// Don't insert stack check preamble.
NOSPLIT = 4
// Put this data in a read-only section.
RODATA = 8
// This data contains no pointers.
NOPTR = 16
// This is a wrapper function and should not count as disabling 'recover'.
WRAPPER = 32
// This function uses its incoming context register.
NEEDCTXT = 64
// When passed to ggloblsym, causes Local to be set to true on the LSym it creates.
LOCAL = 128
// Allocate a word of thread local storage and store the offset from the
// thread local base to the thread local storage in this variable.
TLSBSS = 256
// Do not insert instructions to allocate a stack frame for this function.
// Only valid on functions that declare a frame size of 0.
// TODO(mwhudson): only implemented for ppc64x at present.
NOFRAME = 512
// Function can call reflect.Type.Method or reflect.Type.MethodByName.
REFLECTMETHOD = 1024
// Function is the top of the call stack. Call stack unwinders should stop
// at this function.
TOPFRAME = 2048
)

View File

@ -0,0 +1,598 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package obj
import (
"bytes"
"github.com/twitchyliquid64/golang-asm/objabi"
"fmt"
"io"
"strings"
)
const REG_NONE = 0
// Line returns a string containing the filename and line number for p
func (p *Prog) Line() string {
return p.Ctxt.OutermostPos(p.Pos).Format(false, true)
}
func (p *Prog) InnermostLine(w io.Writer) {
p.Ctxt.InnermostPos(p.Pos).WriteTo(w, false, true)
}
// InnermostLineNumber returns a string containing the line number for the
// innermost inlined function (if any inlining) at p's position
func (p *Prog) InnermostLineNumber() string {
return p.Ctxt.InnermostPos(p.Pos).LineNumber()
}
// InnermostLineNumberHTML returns a string containing the line number for the
// innermost inlined function (if any inlining) at p's position
func (p *Prog) InnermostLineNumberHTML() string {
return p.Ctxt.InnermostPos(p.Pos).LineNumberHTML()
}
// InnermostFilename returns a string containing the innermost
// (in inlining) filename at p's position
func (p *Prog) InnermostFilename() string {
// TODO For now, this is only used for debugging output, and if we need more/better information, it might change.
// An example of what we might want to see is the full stack of positions for inlined code, so we get some visibility into what is recorded there.
pos := p.Ctxt.InnermostPos(p.Pos)
if !pos.IsKnown() {
return "<unknown file name>"
}
return pos.Filename()
}
var armCondCode = []string{
".EQ",
".NE",
".CS",
".CC",
".MI",
".PL",
".VS",
".VC",
".HI",
".LS",
".GE",
".LT",
".GT",
".LE",
"",
".NV",
}
/* ARM scond byte */
const (
C_SCOND = (1 << 4) - 1
C_SBIT = 1 << 4
C_PBIT = 1 << 5
C_WBIT = 1 << 6
C_FBIT = 1 << 7
C_UBIT = 1 << 7
C_SCOND_XOR = 14
)
// CConv formats opcode suffix bits (Prog.Scond).
func CConv(s uint8) string {
if s == 0 {
return ""
}
for i := range opSuffixSpace {
sset := &opSuffixSpace[i]
if sset.arch == objabi.GOARCH {
return sset.cconv(s)
}
}
return fmt.Sprintf("SC???%d", s)
}
// CConvARM formats ARM opcode suffix bits (mostly condition codes).
func CConvARM(s uint8) string {
// TODO: could be great to move suffix-related things into
// ARM asm backends some day.
// obj/x86 can be used as an example.
sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
if s&C_SBIT != 0 {
sc += ".S"
}
if s&C_PBIT != 0 {
sc += ".P"
}
if s&C_WBIT != 0 {
sc += ".W"
}
if s&C_UBIT != 0 { /* ambiguous with FBIT */
sc += ".U"
}
return sc
}
func (p *Prog) String() string {
if p == nil {
return "<nil Prog>"
}
if p.Ctxt == nil {
return "<Prog without ctxt>"
}
return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.Line(), p.InstructionString())
}
func (p *Prog) InnermostString(w io.Writer) {
if p == nil {
io.WriteString(w, "<nil Prog>")
return
}
if p.Ctxt == nil {
io.WriteString(w, "<Prog without ctxt>")
return
}
fmt.Fprintf(w, "%.5d (", p.Pc)
p.InnermostLine(w)
io.WriteString(w, ")\t")
p.WriteInstructionString(w)
}
// InstructionString returns a string representation of the instruction without preceding
// program counter or file and line number.
func (p *Prog) InstructionString() string {
buf := new(bytes.Buffer)
p.WriteInstructionString(buf)
return buf.String()
}
// WriteInstructionString writes a string representation of the instruction without preceding
// program counter or file and line number.
func (p *Prog) WriteInstructionString(w io.Writer) {
if p == nil {
io.WriteString(w, "<nil Prog>")
return
}
if p.Ctxt == nil {
io.WriteString(w, "<Prog without ctxt>")
return
}
sc := CConv(p.Scond)
io.WriteString(w, p.As.String())
io.WriteString(w, sc)
sep := "\t"
if p.From.Type != TYPE_NONE {
io.WriteString(w, sep)
WriteDconv(w, p, &p.From)
sep = ", "
}
if p.Reg != REG_NONE {
// Should not happen but might as well show it if it does.
fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.Reg)))
sep = ", "
}
for i := range p.RestArgs {
io.WriteString(w, sep)
WriteDconv(w, p, &p.RestArgs[i])
sep = ", "
}
if p.As == ATEXT {
// If there are attributes, print them. Otherwise, skip the comma.
// In short, print one of these two:
// TEXT foo(SB), DUPOK|NOSPLIT, $0
// TEXT foo(SB), $0
s := p.From.Sym.Attribute.TextAttrString()
if s != "" {
fmt.Fprintf(w, "%s%s", sep, s)
sep = ", "
}
}
if p.To.Type != TYPE_NONE {
io.WriteString(w, sep)
WriteDconv(w, p, &p.To)
}
if p.RegTo2 != REG_NONE {
fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.RegTo2)))
}
}
func (ctxt *Link) NewProg() *Prog {
p := new(Prog)
p.Ctxt = ctxt
return p
}
func (ctxt *Link) CanReuseProgs() bool {
return ctxt.Debugasm == 0
}
func Dconv(p *Prog, a *Addr) string {
buf := new(bytes.Buffer)
WriteDconv(buf, p, a)
return buf.String()
}
func WriteDconv(w io.Writer, p *Prog, a *Addr) {
switch a.Type {
default:
fmt.Fprintf(w, "type=%d", a.Type)
case TYPE_NONE:
if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
a.WriteNameTo(w)
fmt.Fprintf(w, "(%v)(NONE)", Rconv(int(a.Reg)))
}
case TYPE_REG:
// TODO(rsc): This special case is for x86 instructions like
// PINSRQ CX,$1,X6
// where the $1 is included in the p->to Addr.
// Move into a new field.
if a.Offset != 0 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) {
fmt.Fprintf(w, "$%d,%v", a.Offset, Rconv(int(a.Reg)))
return
}
if a.Name != NAME_NONE || a.Sym != nil {
a.WriteNameTo(w)
fmt.Fprintf(w, "(%v)(REG)", Rconv(int(a.Reg)))
} else {
io.WriteString(w, Rconv(int(a.Reg)))
}
if (RBaseARM64+1<<10+1<<9) /* arm64.REG_ELEM */ <= a.Reg &&
a.Reg < (RBaseARM64+1<<11) /* arm64.REG_ELEM_END */ {
fmt.Fprintf(w, "[%d]", a.Index)
}
case TYPE_BRANCH:
if a.Sym != nil {
fmt.Fprintf(w, "%s(SB)", a.Sym.Name)
} else if a.Target() != nil {
fmt.Fprint(w, a.Target().Pc)
} else {
fmt.Fprintf(w, "%d(PC)", a.Offset)
}
case TYPE_INDIR:
io.WriteString(w, "*")
a.WriteNameTo(w)
case TYPE_MEM:
a.WriteNameTo(w)
if a.Index != REG_NONE {
if a.Scale == 0 {
// arm64 shifted or extended register offset, scale = 0.
fmt.Fprintf(w, "(%v)", Rconv(int(a.Index)))
} else {
fmt.Fprintf(w, "(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
}
}
case TYPE_CONST:
io.WriteString(w, "$")
a.WriteNameTo(w)
if a.Reg != 0 {
fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
}
case TYPE_TEXTSIZE:
if a.Val.(int32) == objabi.ArgsSizeUnknown {
fmt.Fprintf(w, "$%d", a.Offset)
} else {
fmt.Fprintf(w, "$%d-%d", a.Offset, a.Val.(int32))
}
case TYPE_FCONST:
str := fmt.Sprintf("%.17g", a.Val.(float64))
// Make sure 1 prints as 1.0
if !strings.ContainsAny(str, ".e") {
str += ".0"
}
fmt.Fprintf(w, "$(%s)", str)
case TYPE_SCONST:
fmt.Fprintf(w, "$%q", a.Val.(string))
case TYPE_ADDR:
io.WriteString(w, "$")
a.WriteNameTo(w)
case TYPE_SHIFT:
v := int(a.Offset)
ops := "<<>>->@>"
switch objabi.GOARCH {
case "arm":
op := ops[((v>>5)&3)<<1:]
if v&(1<<4) != 0 {
fmt.Fprintf(w, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
} else {
fmt.Fprintf(w, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
}
if a.Reg != 0 {
fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
}
case "arm64":
op := ops[((v>>22)&3)<<1:]
r := (v >> 16) & 31
fmt.Fprintf(w, "%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63)
default:
panic("TYPE_SHIFT is not supported on " + objabi.GOARCH)
}
case TYPE_REGREG:
fmt.Fprintf(w, "(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
case TYPE_REGREG2:
fmt.Fprintf(w, "%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg)))
case TYPE_REGLIST:
io.WriteString(w, RLconv(a.Offset))
}
}
func (a *Addr) WriteNameTo(w io.Writer) {
switch a.Name {
default:
fmt.Fprintf(w, "name=%d", a.Name)
case NAME_NONE:
switch {
case a.Reg == REG_NONE:
fmt.Fprint(w, a.Offset)
case a.Offset == 0:
fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
case a.Offset != 0:
fmt.Fprintf(w, "%d(%v)", a.Offset, Rconv(int(a.Reg)))
}
// Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type.
case NAME_EXTERN:
reg := "SB"
if a.Reg != REG_NONE {
reg = Rconv(int(a.Reg))
}
if a.Sym != nil {
fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
} else {
fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
}
case NAME_GOTREF:
reg := "SB"
if a.Reg != REG_NONE {
reg = Rconv(int(a.Reg))
}
if a.Sym != nil {
fmt.Fprintf(w, "%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg)
} else {
fmt.Fprintf(w, "%s@GOT(%s)", offConv(a.Offset), reg)
}
case NAME_STATIC:
reg := "SB"
if a.Reg != REG_NONE {
reg = Rconv(int(a.Reg))
}
if a.Sym != nil {
fmt.Fprintf(w, "%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
} else {
fmt.Fprintf(w, "<>%s(%s)", offConv(a.Offset), reg)
}
case NAME_AUTO:
reg := "SP"
if a.Reg != REG_NONE {
reg = Rconv(int(a.Reg))
}
if a.Sym != nil {
fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
} else {
fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
}
case NAME_PARAM:
reg := "FP"
if a.Reg != REG_NONE {
reg = Rconv(int(a.Reg))
}
if a.Sym != nil {
fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
} else {
fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
}
case NAME_TOCREF:
reg := "SB"
if a.Reg != REG_NONE {
reg = Rconv(int(a.Reg))
}
if a.Sym != nil {
fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
} else {
fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
}
}
}
func offConv(off int64) string {
if off == 0 {
return ""
}
return fmt.Sprintf("%+d", off)
}
// opSuffixSet is like regListSet, but for opcode suffixes.
//
// Unlike some other similar structures, uint8 space is not
// divided by its own values set (because there are only 256 of them).
// Instead, every arch may interpret/format all 8 bits as they like,
// as long as they register proper cconv function for it.
type opSuffixSet struct {
arch string
cconv func(suffix uint8) string
}
var opSuffixSpace []opSuffixSet
// RegisterOpSuffix assigns cconv function for formatting opcode suffixes
// when compiling for GOARCH=arch.
//
// cconv is never called with 0 argument.
func RegisterOpSuffix(arch string, cconv func(uint8) string) {
opSuffixSpace = append(opSuffixSpace, opSuffixSet{
arch: arch,
cconv: cconv,
})
}
type regSet struct {
lo int
hi int
Rconv func(int) string
}
// Few enough architectures that a linear scan is fastest.
// Not even worth sorting.
var regSpace []regSet
/*
Each architecture defines a register space as a unique
integer range.
Here is the list of architectures and the base of their register spaces.
*/
const (
// Because of masking operations in the encodings, each register
// space should start at 0 modulo some power of 2.
RBase386 = 1 * 1024
RBaseAMD64 = 2 * 1024
RBaseARM = 3 * 1024
RBasePPC64 = 4 * 1024 // range [4k, 8k)
RBaseARM64 = 8 * 1024 // range [8k, 13k)
RBaseMIPS = 13 * 1024 // range [13k, 14k)
RBaseS390X = 14 * 1024 // range [14k, 15k)
RBaseRISCV = 15 * 1024 // range [15k, 16k)
RBaseWasm = 16 * 1024
)
// RegisterRegister binds a pretty-printer (Rconv) for register
// numbers to a given register number range. Lo is inclusive,
// hi exclusive (valid registers are lo through hi-1).
func RegisterRegister(lo, hi int, Rconv func(int) string) {
regSpace = append(regSpace, regSet{lo, hi, Rconv})
}
func Rconv(reg int) string {
if reg == REG_NONE {
return "NONE"
}
for i := range regSpace {
rs := &regSpace[i]
if rs.lo <= reg && reg < rs.hi {
return rs.Rconv(reg)
}
}
return fmt.Sprintf("R???%d", reg)
}
type regListSet struct {
lo int64
hi int64
RLconv func(int64) string
}
var regListSpace []regListSet
// Each architecture is allotted a distinct subspace: [Lo, Hi) for declaring its
// arch-specific register list numbers.
const (
RegListARMLo = 0
RegListARMHi = 1 << 16
// arm64 uses the 60th bit to differentiate from other archs
RegListARM64Lo = 1 << 60
RegListARM64Hi = 1<<61 - 1
// x86 uses the 61th bit to differentiate from other archs
RegListX86Lo = 1 << 61
RegListX86Hi = 1<<62 - 1
)
// RegisterRegisterList binds a pretty-printer (RLconv) for register list
// numbers to a given register list number range. Lo is inclusive,
// hi exclusive (valid register list are lo through hi-1).
func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) {
regListSpace = append(regListSpace, regListSet{lo, hi, rlconv})
}
func RLconv(list int64) string {
for i := range regListSpace {
rls := &regListSpace[i]
if rls.lo <= list && list < rls.hi {
return rls.RLconv(list)
}
}
return fmt.Sprintf("RL???%d", list)
}
type opSet struct {
lo As
names []string
}
// Not even worth sorting
var aSpace []opSet
// RegisterOpcode binds a list of instruction names
// to a given instruction number range.
func RegisterOpcode(lo As, Anames []string) {
if len(Anames) > AllowedOpCodes {
panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
}
aSpace = append(aSpace, opSet{lo, Anames})
}
func (a As) String() string {
if 0 <= a && int(a) < len(Anames) {
return Anames[a]
}
for i := range aSpace {
as := &aSpace[i]
if as.lo <= a && int(a-as.lo) < len(as.names) {
return as.names[a-as.lo]
}
}
return fmt.Sprintf("A???%d", a)
}
var Anames = []string{
"XXX",
"CALL",
"DUFFCOPY",
"DUFFZERO",
"END",
"FUNCDATA",
"JMP",
"NOP",
"PCALIGN",
"PCDATA",
"RET",
"GETCALLERPC",
"TEXT",
"UNDEF",
}
func Bool2int(b bool) int {
// The compiler currently only optimizes this form.
// See issue 6011.
var i int
if b {
i = 1
} else {
i = 0
}
return i
}

View File

@ -0,0 +1,331 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wasm
import "github.com/twitchyliquid64/golang-asm/obj"
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p wasm
const (
/* mark flags */
DONE = 1 << iota
PRESERVEFLAGS // not allowed to clobber flags
)
/*
* wasm
*/
const (
ACallImport = obj.ABaseWasm + obj.A_ARCHSPECIFIC + iota
AGet
ASet
ATee
ANot // alias for I32Eqz
// The following are low-level WebAssembly instructions.
// Their order matters, since it matches the opcode encoding.
// Gaps in the encoding are indicated by comments.
AUnreachable // opcode 0x00
ANop
ABlock
ALoop
AIf
AElse
AEnd // opcode 0x0B
ABr
ABrIf
ABrTable
// ACall and AReturn are WebAssembly instructions. obj.ACALL and obj.ARET are higher level instructions
// with Go semantics, e.g. they manipulate the Go stack on the linear memory.
AReturn
ACall
ACallIndirect
ADrop // opcode 0x1A
ASelect
ALocalGet // opcode 0x20
ALocalSet
ALocalTee
AGlobalGet
AGlobalSet
AI32Load // opcode 0x28
AI64Load
AF32Load
AF64Load
AI32Load8S
AI32Load8U
AI32Load16S
AI32Load16U
AI64Load8S
AI64Load8U
AI64Load16S
AI64Load16U
AI64Load32S
AI64Load32U
AI32Store
AI64Store
AF32Store
AF64Store
AI32Store8
AI32Store16
AI64Store8
AI64Store16
AI64Store32
ACurrentMemory
AGrowMemory
AI32Const
AI64Const
AF32Const
AF64Const
AI32Eqz
AI32Eq
AI32Ne
AI32LtS
AI32LtU
AI32GtS
AI32GtU
AI32LeS
AI32LeU
AI32GeS
AI32GeU
AI64Eqz
AI64Eq
AI64Ne
AI64LtS
AI64LtU
AI64GtS
AI64GtU
AI64LeS
AI64LeU
AI64GeS
AI64GeU
AF32Eq
AF32Ne
AF32Lt
AF32Gt
AF32Le
AF32Ge
AF64Eq
AF64Ne
AF64Lt
AF64Gt
AF64Le
AF64Ge
AI32Clz
AI32Ctz
AI32Popcnt
AI32Add
AI32Sub
AI32Mul
AI32DivS
AI32DivU
AI32RemS
AI32RemU
AI32And
AI32Or
AI32Xor
AI32Shl
AI32ShrS
AI32ShrU
AI32Rotl
AI32Rotr
AI64Clz
AI64Ctz
AI64Popcnt
AI64Add
AI64Sub
AI64Mul
AI64DivS
AI64DivU
AI64RemS
AI64RemU
AI64And
AI64Or
AI64Xor
AI64Shl
AI64ShrS
AI64ShrU
AI64Rotl
AI64Rotr
AF32Abs
AF32Neg
AF32Ceil
AF32Floor
AF32Trunc
AF32Nearest
AF32Sqrt
AF32Add
AF32Sub
AF32Mul
AF32Div
AF32Min
AF32Max
AF32Copysign
AF64Abs
AF64Neg
AF64Ceil
AF64Floor
AF64Trunc
AF64Nearest
AF64Sqrt
AF64Add
AF64Sub
AF64Mul
AF64Div
AF64Min
AF64Max
AF64Copysign
AI32WrapI64
AI32TruncF32S
AI32TruncF32U
AI32TruncF64S
AI32TruncF64U
AI64ExtendI32S
AI64ExtendI32U
AI64TruncF32S
AI64TruncF32U
AI64TruncF64S
AI64TruncF64U
AF32ConvertI32S
AF32ConvertI32U
AF32ConvertI64S
AF32ConvertI64U
AF32DemoteF64
AF64ConvertI32S
AF64ConvertI32U
AF64ConvertI64S
AF64ConvertI64U
AF64PromoteF32
AI32ReinterpretF32
AI64ReinterpretF64
AF32ReinterpretI32
AF64ReinterpretI64
AI32Extend8S
AI32Extend16S
AI64Extend8S
AI64Extend16S
AI64Extend32S
AI32TruncSatF32S // opcode 0xFC 0x00
AI32TruncSatF32U
AI32TruncSatF64S
AI32TruncSatF64U
AI64TruncSatF32S
AI64TruncSatF32U
AI64TruncSatF64S
AI64TruncSatF64U
ALast // Sentinel: End of low-level WebAssembly instructions.
ARESUMEPOINT
// ACALLNORESUME is a call which is not followed by a resume point.
// It is allowed inside of WebAssembly blocks, whereas obj.ACALL is not.
// However, it is not allowed to switch goroutines while inside of an ACALLNORESUME call.
ACALLNORESUME
ARETUNWIND
AMOVB
AMOVH
AMOVW
AMOVD
AWORD
ALAST
)
const (
REG_NONE = 0
)
const (
// globals
REG_SP = obj.RBaseWasm + iota // SP is currently 32-bit, until 64-bit memory operations are available
REG_CTXT
REG_g
// RET* are used by runtime.return0 and runtime.reflectcall. These functions pass return values in registers.
REG_RET0
REG_RET1
REG_RET2
REG_RET3
REG_PAUSE
// i32 locals
REG_R0
REG_R1
REG_R2
REG_R3
REG_R4
REG_R5
REG_R6
REG_R7
REG_R8
REG_R9
REG_R10
REG_R11
REG_R12
REG_R13
REG_R14
REG_R15
// f32 locals
REG_F0
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_F8
REG_F9
REG_F10
REG_F11
REG_F12
REG_F13
REG_F14
REG_F15
// f64 locals
REG_F16
REG_F17
REG_F18
REG_F19
REG_F20
REG_F21
REG_F22
REG_F23
REG_F24
REG_F25
REG_F26
REG_F27
REG_F28
REG_F29
REG_F30
REG_F31
REG_PC_B // also first parameter, i32
MAXREG
MINREG = REG_SP
REGSP = REG_SP
REGCTXT = REG_CTXT
REGG = REG_g
)

View File

@ -0,0 +1,208 @@
// Code generated by stringer -i a.out.go -o anames.go -p wasm; DO NOT EDIT.
package wasm
import "github.com/twitchyliquid64/golang-asm/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "CallImport",
"Get",
"Set",
"Tee",
"Not",
"Unreachable",
"Nop",
"Block",
"Loop",
"If",
"Else",
"End",
"Br",
"BrIf",
"BrTable",
"Return",
"Call",
"CallIndirect",
"Drop",
"Select",
"LocalGet",
"LocalSet",
"LocalTee",
"GlobalGet",
"GlobalSet",
"I32Load",
"I64Load",
"F32Load",
"F64Load",
"I32Load8S",
"I32Load8U",
"I32Load16S",
"I32Load16U",
"I64Load8S",
"I64Load8U",
"I64Load16S",
"I64Load16U",
"I64Load32S",
"I64Load32U",
"I32Store",
"I64Store",
"F32Store",
"F64Store",
"I32Store8",
"I32Store16",
"I64Store8",
"I64Store16",
"I64Store32",
"CurrentMemory",
"GrowMemory",
"I32Const",
"I64Const",
"F32Const",
"F64Const",
"I32Eqz",
"I32Eq",
"I32Ne",
"I32LtS",
"I32LtU",
"I32GtS",
"I32GtU",
"I32LeS",
"I32LeU",
"I32GeS",
"I32GeU",
"I64Eqz",
"I64Eq",
"I64Ne",
"I64LtS",
"I64LtU",
"I64GtS",
"I64GtU",
"I64LeS",
"I64LeU",
"I64GeS",
"I64GeU",
"F32Eq",
"F32Ne",
"F32Lt",
"F32Gt",
"F32Le",
"F32Ge",
"F64Eq",
"F64Ne",
"F64Lt",
"F64Gt",
"F64Le",
"F64Ge",
"I32Clz",
"I32Ctz",
"I32Popcnt",
"I32Add",
"I32Sub",
"I32Mul",
"I32DivS",
"I32DivU",
"I32RemS",
"I32RemU",
"I32And",
"I32Or",
"I32Xor",
"I32Shl",
"I32ShrS",
"I32ShrU",
"I32Rotl",
"I32Rotr",
"I64Clz",
"I64Ctz",
"I64Popcnt",
"I64Add",
"I64Sub",
"I64Mul",
"I64DivS",
"I64DivU",
"I64RemS",
"I64RemU",
"I64And",
"I64Or",
"I64Xor",
"I64Shl",
"I64ShrS",
"I64ShrU",
"I64Rotl",
"I64Rotr",
"F32Abs",
"F32Neg",
"F32Ceil",
"F32Floor",
"F32Trunc",
"F32Nearest",
"F32Sqrt",
"F32Add",
"F32Sub",
"F32Mul",
"F32Div",
"F32Min",
"F32Max",
"F32Copysign",
"F64Abs",
"F64Neg",
"F64Ceil",
"F64Floor",
"F64Trunc",
"F64Nearest",
"F64Sqrt",
"F64Add",
"F64Sub",
"F64Mul",
"F64Div",
"F64Min",
"F64Max",
"F64Copysign",
"I32WrapI64",
"I32TruncF32S",
"I32TruncF32U",
"I32TruncF64S",
"I32TruncF64U",
"I64ExtendI32S",
"I64ExtendI32U",
"I64TruncF32S",
"I64TruncF32U",
"I64TruncF64S",
"I64TruncF64U",
"F32ConvertI32S",
"F32ConvertI32U",
"F32ConvertI64S",
"F32ConvertI64U",
"F32DemoteF64",
"F64ConvertI32S",
"F64ConvertI32U",
"F64ConvertI64S",
"F64ConvertI64U",
"F64PromoteF32",
"I32ReinterpretF32",
"I64ReinterpretF64",
"F32ReinterpretI32",
"F64ReinterpretI64",
"I32Extend8S",
"I32Extend16S",
"I64Extend8S",
"I64Extend16S",
"I64Extend32S",
"I32TruncSatF32S",
"I32TruncSatF32U",
"I32TruncSatF64S",
"I32TruncSatF64U",
"I64TruncSatF32S",
"I64TruncSatF32U",
"I64TruncSatF64S",
"I64TruncSatF64U",
"Last",
"RESUMEPOINT",
"CALLNORESUME",
"RETUNWIND",
"MOVB",
"MOVH",
"MOVW",
"MOVD",
"WORD",
"LAST",
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,423 @@
// Inferno utils/6c/6.out.h
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6c/6.out.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package x86
import "github.com/twitchyliquid64/golang-asm/obj"
const (
REG_NONE = 0
)
const (
REG_AL = obj.RBaseAMD64 + iota
REG_CL
REG_DL
REG_BL
REG_SPB
REG_BPB
REG_SIB
REG_DIB
REG_R8B
REG_R9B
REG_R10B
REG_R11B
REG_R12B
REG_R13B
REG_R14B
REG_R15B
REG_AX
REG_CX
REG_DX
REG_BX
REG_SP
REG_BP
REG_SI
REG_DI
REG_R8
REG_R9
REG_R10
REG_R11
REG_R12
REG_R13
REG_R14
REG_R15
REG_AH
REG_CH
REG_DH
REG_BH
REG_F0
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_M0
REG_M1
REG_M2
REG_M3
REG_M4
REG_M5
REG_M6
REG_M7
REG_K0
REG_K1
REG_K2
REG_K3
REG_K4
REG_K5
REG_K6
REG_K7
REG_X0
REG_X1
REG_X2
REG_X3
REG_X4
REG_X5
REG_X6
REG_X7
REG_X8
REG_X9
REG_X10
REG_X11
REG_X12
REG_X13
REG_X14
REG_X15
REG_X16
REG_X17
REG_X18
REG_X19
REG_X20
REG_X21
REG_X22
REG_X23
REG_X24
REG_X25
REG_X26
REG_X27
REG_X28
REG_X29
REG_X30
REG_X31
REG_Y0
REG_Y1
REG_Y2
REG_Y3
REG_Y4
REG_Y5
REG_Y6
REG_Y7
REG_Y8
REG_Y9
REG_Y10
REG_Y11
REG_Y12
REG_Y13
REG_Y14
REG_Y15
REG_Y16
REG_Y17
REG_Y18
REG_Y19
REG_Y20
REG_Y21
REG_Y22
REG_Y23
REG_Y24
REG_Y25
REG_Y26
REG_Y27
REG_Y28
REG_Y29
REG_Y30
REG_Y31
REG_Z0
REG_Z1
REG_Z2
REG_Z3
REG_Z4
REG_Z5
REG_Z6
REG_Z7
REG_Z8
REG_Z9
REG_Z10
REG_Z11
REG_Z12
REG_Z13
REG_Z14
REG_Z15
REG_Z16
REG_Z17
REG_Z18
REG_Z19
REG_Z20
REG_Z21
REG_Z22
REG_Z23
REG_Z24
REG_Z25
REG_Z26
REG_Z27
REG_Z28
REG_Z29
REG_Z30
REG_Z31
REG_CS
REG_SS
REG_DS
REG_ES
REG_FS
REG_GS
REG_GDTR // global descriptor table register
REG_IDTR // interrupt descriptor table register
REG_LDTR // local descriptor table register
REG_MSW // machine status word
REG_TASK // task register
REG_CR0
REG_CR1
REG_CR2
REG_CR3
REG_CR4
REG_CR5
REG_CR6
REG_CR7
REG_CR8
REG_CR9
REG_CR10
REG_CR11
REG_CR12
REG_CR13
REG_CR14
REG_CR15
REG_DR0
REG_DR1
REG_DR2
REG_DR3
REG_DR4
REG_DR5
REG_DR6
REG_DR7
REG_TR0
REG_TR1
REG_TR2
REG_TR3
REG_TR4
REG_TR5
REG_TR6
REG_TR7
REG_TLS
MAXREG
REG_CR = REG_CR0
REG_DR = REG_DR0
REG_TR = REG_TR0
REGARG = -1
REGRET = REG_AX
FREGRET = REG_X0
REGSP = REG_SP
REGCTXT = REG_DX
REGEXT = REG_R15 // compiler allocates external registers R15 down
FREGMIN = REG_X0 + 5 // first register variable
FREGEXT = REG_X0 + 15 // first external register
T_TYPE = 1 << 0
T_INDEX = 1 << 1
T_OFFSET = 1 << 2
T_FCONST = 1 << 3
T_SYM = 1 << 4
T_SCONST = 1 << 5
T_64 = 1 << 6
T_GOTYPE = 1 << 7
)
// https://www.uclibc.org/docs/psABI-x86_64.pdf, figure 3.36
var AMD64DWARFRegisters = map[int16]int16{
REG_AX: 0,
REG_DX: 1,
REG_CX: 2,
REG_BX: 3,
REG_SI: 4,
REG_DI: 5,
REG_BP: 6,
REG_SP: 7,
REG_R8: 8,
REG_R9: 9,
REG_R10: 10,
REG_R11: 11,
REG_R12: 12,
REG_R13: 13,
REG_R14: 14,
REG_R15: 15,
// 16 is "Return Address RA", whatever that is.
// 17-24 vector registers (X/Y/Z).
REG_X0: 17,
REG_X1: 18,
REG_X2: 19,
REG_X3: 20,
REG_X4: 21,
REG_X5: 22,
REG_X6: 23,
REG_X7: 24,
// 25-32 extended vector registers (X/Y/Z).
REG_X8: 25,
REG_X9: 26,
REG_X10: 27,
REG_X11: 28,
REG_X12: 29,
REG_X13: 30,
REG_X14: 31,
REG_X15: 32,
// ST registers. %stN => FN.
REG_F0: 33,
REG_F1: 34,
REG_F2: 35,
REG_F3: 36,
REG_F4: 37,
REG_F5: 38,
REG_F6: 39,
REG_F7: 40,
// MMX registers. %mmN => MN.
REG_M0: 41,
REG_M1: 42,
REG_M2: 43,
REG_M3: 44,
REG_M4: 45,
REG_M5: 46,
REG_M6: 47,
REG_M7: 48,
// 48 is flags, which doesn't have a name.
REG_ES: 50,
REG_CS: 51,
REG_SS: 52,
REG_DS: 53,
REG_FS: 54,
REG_GS: 55,
// 58 and 59 are {fs,gs}base, which don't have names.
REG_TR: 62,
REG_LDTR: 63,
// 64-66 are mxcsr, fcw, fsw, which don't have names.
// 67-82 upper vector registers (X/Y/Z).
REG_X16: 67,
REG_X17: 68,
REG_X18: 69,
REG_X19: 70,
REG_X20: 71,
REG_X21: 72,
REG_X22: 73,
REG_X23: 74,
REG_X24: 75,
REG_X25: 76,
REG_X26: 77,
REG_X27: 78,
REG_X28: 79,
REG_X29: 80,
REG_X30: 81,
REG_X31: 82,
// 118-125 vector mask registers. %kN => KN.
REG_K0: 118,
REG_K1: 119,
REG_K2: 120,
REG_K3: 121,
REG_K4: 122,
REG_K5: 123,
REG_K6: 124,
REG_K7: 125,
}
// https://www.uclibc.org/docs/psABI-i386.pdf, table 2.14
var X86DWARFRegisters = map[int16]int16{
REG_AX: 0,
REG_CX: 1,
REG_DX: 2,
REG_BX: 3,
REG_SP: 4,
REG_BP: 5,
REG_SI: 6,
REG_DI: 7,
// 8 is "Return Address RA", whatever that is.
// 9 is flags, which doesn't have a name.
// ST registers. %stN => FN.
REG_F0: 11,
REG_F1: 12,
REG_F2: 13,
REG_F3: 14,
REG_F4: 15,
REG_F5: 16,
REG_F6: 17,
REG_F7: 18,
// XMM registers. %xmmN => XN.
REG_X0: 21,
REG_X1: 22,
REG_X2: 23,
REG_X3: 24,
REG_X4: 25,
REG_X5: 26,
REG_X6: 27,
REG_X7: 28,
// MMX registers. %mmN => MN.
REG_M0: 29,
REG_M1: 30,
REG_M2: 31,
REG_M3: 32,
REG_M4: 33,
REG_M5: 34,
REG_M6: 35,
REG_M7: 36,
// 39 is mxcsr, which doesn't have a name.
REG_ES: 40,
REG_CS: 41,
REG_SS: 42,
REG_DS: 43,
REG_FS: 44,
REG_GS: 45,
REG_TR: 48,
REG_LDTR: 49,
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,382 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x86
import (
"github.com/twitchyliquid64/golang-asm/obj"
"errors"
"fmt"
"strings"
)
// evexBits stores EVEX prefix info that is used during instruction encoding.
type evexBits struct {
b1 byte // [W1mmLLpp]
b2 byte // [NNNbbZRS]
// Associated instruction opcode.
opcode byte
}
// newEVEXBits creates evexBits object from enc bytes at z position.
func newEVEXBits(z int, enc *opBytes) evexBits {
return evexBits{
b1: enc[z+0],
b2: enc[z+1],
opcode: enc[z+2],
}
}
// P returns EVEX.pp value.
func (evex evexBits) P() byte { return (evex.b1 & evexP) >> 0 }
// L returns EVEX.L'L value.
func (evex evexBits) L() byte { return (evex.b1 & evexL) >> 2 }
// M returns EVEX.mm value.
func (evex evexBits) M() byte { return (evex.b1 & evexM) >> 4 }
// W returns EVEX.W value.
func (evex evexBits) W() byte { return (evex.b1 & evexW) >> 7 }
// BroadcastEnabled reports whether BCST suffix is permitted.
func (evex evexBits) BroadcastEnabled() bool {
return evex.b2&evexBcst != 0
}
// ZeroingEnabled reports whether Z suffix is permitted.
func (evex evexBits) ZeroingEnabled() bool {
return (evex.b2&evexZeroing)>>2 != 0
}
// RoundingEnabled reports whether RN_SAE, RZ_SAE, RD_SAE and RU_SAE suffixes
// are permitted.
func (evex evexBits) RoundingEnabled() bool {
return (evex.b2&evexRounding)>>1 != 0
}
// SaeEnabled reports whether SAE suffix is permitted.
func (evex evexBits) SaeEnabled() bool {
return (evex.b2&evexSae)>>0 != 0
}
// DispMultiplier returns displacement multiplier that is calculated
// based on tuple type, EVEX.W and input size.
// If embedded broadcast is used, bcst should be true.
func (evex evexBits) DispMultiplier(bcst bool) int32 {
if bcst {
switch evex.b2 & evexBcst {
case evexBcstN4:
return 4
case evexBcstN8:
return 8
}
return 1
}
switch evex.b2 & evexN {
case evexN1:
return 1
case evexN2:
return 2
case evexN4:
return 4
case evexN8:
return 8
case evexN16:
return 16
case evexN32:
return 32
case evexN64:
return 64
case evexN128:
return 128
}
return 1
}
// EVEX is described by using 2-byte sequence.
// See evexBits for more details.
const (
evexW = 0x80 // b1[W... ....]
evexWIG = 0 << 7
evexW0 = 0 << 7
evexW1 = 1 << 7
evexM = 0x30 // b2[..mm ...]
evex0F = 1 << 4
evex0F38 = 2 << 4
evex0F3A = 3 << 4
evexL = 0x0C // b1[.... LL..]
evexLIG = 0 << 2
evex128 = 0 << 2
evex256 = 1 << 2
evex512 = 2 << 2
evexP = 0x03 // b1[.... ..pp]
evex66 = 1 << 0
evexF3 = 2 << 0
evexF2 = 3 << 0
// Precalculated Disp8 N value.
// N acts like a multiplier for 8bit displacement.
// Note that some N are not used, but their bits are reserved.
evexN = 0xE0 // b2[NNN. ....]
evexN1 = 0 << 5
evexN2 = 1 << 5
evexN4 = 2 << 5
evexN8 = 3 << 5
evexN16 = 4 << 5
evexN32 = 5 << 5
evexN64 = 6 << 5
evexN128 = 7 << 5
// Disp8 for broadcasts.
evexBcst = 0x18 // b2[...b b...]
evexBcstN4 = 1 << 3
evexBcstN8 = 2 << 3
// Flags that permit certain AVX512 features.
// It's semantically illegal to combine evexZeroing and evexSae.
evexZeroing = 0x4 // b2[.... .Z..]
evexZeroingEnabled = 1 << 2
evexRounding = 0x2 // b2[.... ..R.]
evexRoundingEnabled = 1 << 1
evexSae = 0x1 // b2[.... ...S]
evexSaeEnabled = 1 << 0
)
// compressedDisp8 calculates EVEX compressed displacement, if applicable.
func compressedDisp8(disp, elemSize int32) (disp8 byte, ok bool) {
if disp%elemSize == 0 {
v := disp / elemSize
if v >= -128 && v <= 127 {
return byte(v), true
}
}
return 0, false
}
// evexZcase reports whether given Z-case belongs to EVEX group.
func evexZcase(zcase uint8) bool {
return zcase > Zevex_first && zcase < Zevex_last
}
// evexSuffixBits carries instruction EVEX suffix set flags.
//
// Examples:
// "RU_SAE.Z" => {rounding: 3, zeroing: true}
// "Z" => {zeroing: true}
// "BCST" => {broadcast: true}
// "SAE.Z" => {sae: true, zeroing: true}
type evexSuffix struct {
rounding byte
sae bool
zeroing bool
broadcast bool
}
// Rounding control values.
// Match exact value for EVEX.L'L field (with exception of rcUnset).
const (
rcRNSAE = 0 // Round towards nearest
rcRDSAE = 1 // Round towards -Inf
rcRUSAE = 2 // Round towards +Inf
rcRZSAE = 3 // Round towards zero
rcUnset = 4
)
// newEVEXSuffix returns proper zero value for evexSuffix.
func newEVEXSuffix() evexSuffix {
return evexSuffix{rounding: rcUnset}
}
// evexSuffixMap maps obj.X86suffix to its decoded version.
// Filled during init().
var evexSuffixMap [255]evexSuffix
func init() {
// Decode all valid suffixes for later use.
for i := range opSuffixTable {
suffix := newEVEXSuffix()
parts := strings.Split(opSuffixTable[i], ".")
for j := range parts {
switch parts[j] {
case "Z":
suffix.zeroing = true
case "BCST":
suffix.broadcast = true
case "SAE":
suffix.sae = true
case "RN_SAE":
suffix.rounding = rcRNSAE
case "RD_SAE":
suffix.rounding = rcRDSAE
case "RU_SAE":
suffix.rounding = rcRUSAE
case "RZ_SAE":
suffix.rounding = rcRZSAE
}
}
evexSuffixMap[i] = suffix
}
}
// toDisp8 tries to convert disp to proper 8-bit displacement value.
func toDisp8(disp int32, p *obj.Prog, asmbuf *AsmBuf) (disp8 byte, ok bool) {
if asmbuf.evexflag {
bcst := evexSuffixMap[p.Scond].broadcast
elemSize := asmbuf.evex.DispMultiplier(bcst)
return compressedDisp8(disp, elemSize)
}
return byte(disp), disp >= -128 && disp < 128
}
// EncodeRegisterRange packs [reg0-reg1] list into 64-bit value that
// is intended to be stored inside obj.Addr.Offset with TYPE_REGLIST.
func EncodeRegisterRange(reg0, reg1 int16) int64 {
return (int64(reg0) << 0) |
(int64(reg1) << 16) |
obj.RegListX86Lo
}
// decodeRegisterRange unpacks [reg0-reg1] list from 64-bit value created by EncodeRegisterRange.
func decodeRegisterRange(list int64) (reg0, reg1 int) {
return int((list >> 0) & 0xFFFF),
int((list >> 16) & 0xFFFF)
}
// ParseSuffix handles the special suffix for the 386/AMD64.
// Suffix bits are stored into p.Scond.
//
// Leading "." in cond is ignored.
func ParseSuffix(p *obj.Prog, cond string) error {
cond = strings.TrimPrefix(cond, ".")
suffix := newOpSuffix(cond)
if !suffix.IsValid() {
return inferSuffixError(cond)
}
p.Scond = uint8(suffix)
return nil
}
// inferSuffixError returns non-nil error that describes what could be
// the cause of suffix parse failure.
//
// At the point this function is executed there is already assembly error,
// so we can burn some clocks to construct good error message.
//
// Reported issues:
// - duplicated suffixes
// - illegal rounding/SAE+broadcast combinations
// - unknown suffixes
// - misplaced suffix (e.g. wrong Z suffix position)
func inferSuffixError(cond string) error {
suffixSet := make(map[string]bool) // Set for duplicates detection.
unknownSet := make(map[string]bool) // Set of unknown suffixes.
hasBcst := false
hasRoundSae := false
var msg []string // Error message parts
suffixes := strings.Split(cond, ".")
for i, suffix := range suffixes {
switch suffix {
case "Z":
if i != len(suffixes)-1 {
msg = append(msg, "Z suffix should be the last")
}
case "BCST":
hasBcst = true
case "SAE", "RN_SAE", "RZ_SAE", "RD_SAE", "RU_SAE":
hasRoundSae = true
default:
if !unknownSet[suffix] {
msg = append(msg, fmt.Sprintf("unknown suffix %q", suffix))
}
unknownSet[suffix] = true
}
if suffixSet[suffix] {
msg = append(msg, fmt.Sprintf("duplicate suffix %q", suffix))
}
suffixSet[suffix] = true
}
if hasBcst && hasRoundSae {
msg = append(msg, "can't combine rounding/SAE and broadcast")
}
if len(msg) == 0 {
return errors.New("bad suffix combination")
}
return errors.New(strings.Join(msg, "; "))
}
// opSuffixTable is a complete list of possible opcode suffix combinations.
// It "maps" uint8 suffix bits to their string representation.
// With the exception of first and last elements, order is not important.
var opSuffixTable = [...]string{
"", // Map empty suffix to empty string.
"Z",
"SAE",
"SAE.Z",
"RN_SAE",
"RZ_SAE",
"RD_SAE",
"RU_SAE",
"RN_SAE.Z",
"RZ_SAE.Z",
"RD_SAE.Z",
"RU_SAE.Z",
"BCST",
"BCST.Z",
"<bad suffix>",
}
// opSuffix represents instruction opcode suffix.
// Compound (multi-part) suffixes expressed with single opSuffix value.
//
// uint8 type is used to fit obj.Prog.Scond.
type opSuffix uint8
// badOpSuffix is used to represent all invalid suffix combinations.
const badOpSuffix = opSuffix(len(opSuffixTable) - 1)
// newOpSuffix returns opSuffix object that matches suffixes string.
//
// If no matching suffix is found, special "invalid" suffix is returned.
// Use IsValid method to check against this case.
func newOpSuffix(suffixes string) opSuffix {
for i := range opSuffixTable {
if opSuffixTable[i] == suffixes {
return opSuffix(i)
}
}
return badOpSuffix
}
// IsValid reports whether suffix is valid.
// Empty suffixes are valid.
func (suffix opSuffix) IsValid() bool {
return suffix != badOpSuffix
}
// String returns suffix printed representation.
//
// It matches the string that was used to create suffix with NewX86Suffix()
// for valid suffixes.
// For all invalid suffixes, special marker is returned.
func (suffix opSuffix) String() string {
return opSuffixTable[suffix]
}

View File

@ -0,0 +1,264 @@
// Inferno utils/6c/list.c
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6c/list.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package x86
import (
"github.com/twitchyliquid64/golang-asm/obj"
"fmt"
)
var Register = []string{
"AL", // [D_AL]
"CL",
"DL",
"BL",
"SPB",
"BPB",
"SIB",
"DIB",
"R8B",
"R9B",
"R10B",
"R11B",
"R12B",
"R13B",
"R14B",
"R15B",
"AX", // [D_AX]
"CX",
"DX",
"BX",
"SP",
"BP",
"SI",
"DI",
"R8",
"R9",
"R10",
"R11",
"R12",
"R13",
"R14",
"R15",
"AH",
"CH",
"DH",
"BH",
"F0", // [D_F0]
"F1",
"F2",
"F3",
"F4",
"F5",
"F6",
"F7",
"M0",
"M1",
"M2",
"M3",
"M4",
"M5",
"M6",
"M7",
"K0",
"K1",
"K2",
"K3",
"K4",
"K5",
"K6",
"K7",
"X0",
"X1",
"X2",
"X3",
"X4",
"X5",
"X6",
"X7",
"X8",
"X9",
"X10",
"X11",
"X12",
"X13",
"X14",
"X15",
"X16",
"X17",
"X18",
"X19",
"X20",
"X21",
"X22",
"X23",
"X24",
"X25",
"X26",
"X27",
"X28",
"X29",
"X30",
"X31",
"Y0",
"Y1",
"Y2",
"Y3",
"Y4",
"Y5",
"Y6",
"Y7",
"Y8",
"Y9",
"Y10",
"Y11",
"Y12",
"Y13",
"Y14",
"Y15",
"Y16",
"Y17",
"Y18",
"Y19",
"Y20",
"Y21",
"Y22",
"Y23",
"Y24",
"Y25",
"Y26",
"Y27",
"Y28",
"Y29",
"Y30",
"Y31",
"Z0",
"Z1",
"Z2",
"Z3",
"Z4",
"Z5",
"Z6",
"Z7",
"Z8",
"Z9",
"Z10",
"Z11",
"Z12",
"Z13",
"Z14",
"Z15",
"Z16",
"Z17",
"Z18",
"Z19",
"Z20",
"Z21",
"Z22",
"Z23",
"Z24",
"Z25",
"Z26",
"Z27",
"Z28",
"Z29",
"Z30",
"Z31",
"CS", // [D_CS]
"SS",
"DS",
"ES",
"FS",
"GS",
"GDTR", // [D_GDTR]
"IDTR", // [D_IDTR]
"LDTR", // [D_LDTR]
"MSW", // [D_MSW]
"TASK", // [D_TASK]
"CR0", // [D_CR]
"CR1",
"CR2",
"CR3",
"CR4",
"CR5",
"CR6",
"CR7",
"CR8",
"CR9",
"CR10",
"CR11",
"CR12",
"CR13",
"CR14",
"CR15",
"DR0", // [D_DR]
"DR1",
"DR2",
"DR3",
"DR4",
"DR5",
"DR6",
"DR7",
"TR0", // [D_TR]
"TR1",
"TR2",
"TR3",
"TR4",
"TR5",
"TR6",
"TR7",
"TLS", // [D_TLS]
"MAXREG", // [MAXREG]
}
func init() {
obj.RegisterRegister(REG_AL, REG_AL+len(Register), rconv)
obj.RegisterOpcode(obj.ABaseAMD64, Anames)
obj.RegisterRegisterList(obj.RegListX86Lo, obj.RegListX86Hi, rlconv)
obj.RegisterOpSuffix("386", opSuffixString)
obj.RegisterOpSuffix("amd64", opSuffixString)
}
func rconv(r int) string {
if REG_AL <= r && r-REG_AL < len(Register) {
return Register[r-REG_AL]
}
return fmt.Sprintf("Rgok(%d)", r-obj.RBaseAMD64)
}
func rlconv(bits int64) string {
reg0, reg1 := decodeRegisterRange(bits)
return fmt.Sprintf("[%s-%s]", rconv(reg0), rconv(reg1))
}
func opSuffixString(s uint8) string {
return "." + opSuffix(s).String()
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x86
// argListMax specifies upper arg count limit expected to be carried by obj.Prog.
// Max len(obj.Prog.RestArgs) can be inferred from this to be 4.
const argListMax int = 6
type argList [argListMax]uint8
type ytab struct {
zcase uint8
zoffset uint8
// Last arg is usually destination.
// For unary instructions unaryDst is used to determine
// if single argument is a source or destination.
args argList
}
// Returns true if yt is compatible with args.
//
// Elements from args and yt.args are used
// to index ycover table like `ycover[args[i]+yt.args[i]]`.
// This means that args should contain values that already
// multiplied by Ymax.
func (yt *ytab) match(args []int) bool {
// Trailing Yxxx check is required to avoid a case
// where shorter arg list is matched.
// If we had exact yt.args length, it could be `yt.argc != len(args)`.
if len(args) < len(yt.args) && yt.args[len(args)] != Yxxx {
return false
}
for i := range args {
if ycover[args[i]+int(yt.args[i])] == 0 {
return false
}
}
return true
}

View File

@ -0,0 +1,38 @@
// Derived from Inferno utils/6l/l.h and related files.
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package objabi
// Auto.name
const (
A_AUTO = 1 + iota
A_PARAM
A_DELETED_AUTO
)

View File

@ -0,0 +1,162 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package objabi
import (
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"strconv"
"strings"
)
func Flagcount(name, usage string, val *int) {
flag.Var((*count)(val), name, usage)
}
func Flagfn1(name, usage string, f func(string)) {
flag.Var(fn1(f), name, usage)
}
func Flagprint(w io.Writer) {
flag.CommandLine.SetOutput(w)
flag.PrintDefaults()
}
func Flagparse(usage func()) {
flag.Usage = usage
os.Args = expandArgs(os.Args)
flag.Parse()
}
// expandArgs expands "response files" arguments in the provided slice.
//
// A "response file" argument starts with '@' and the rest of that
// argument is a filename with CR-or-CRLF-separated arguments. Each
// argument in the named files can also contain response file
// arguments. See Issue 18468.
//
// The returned slice 'out' aliases 'in' iff the input did not contain
// any response file arguments.
//
// TODO: handle relative paths of recursive expansions in different directories?
// Is there a spec for this? Are relative paths allowed?
func expandArgs(in []string) (out []string) {
// out is nil until we see a "@" argument.
for i, s := range in {
if strings.HasPrefix(s, "@") {
if out == nil {
out = make([]string, 0, len(in)*2)
out = append(out, in[:i]...)
}
slurp, err := ioutil.ReadFile(s[1:])
if err != nil {
log.Fatal(err)
}
args := strings.Split(strings.TrimSpace(strings.Replace(string(slurp), "\r", "", -1)), "\n")
out = append(out, expandArgs(args)...)
} else if out != nil {
out = append(out, s)
}
}
if out == nil {
return in
}
return
}
func AddVersionFlag() {
flag.Var(versionFlag{}, "V", "print version and exit")
}
var buildID string // filled in by linker
type versionFlag struct{}
func (versionFlag) IsBoolFlag() bool { return true }
func (versionFlag) Get() interface{} { return nil }
func (versionFlag) String() string { return "" }
func (versionFlag) Set(s string) error {
name := os.Args[0]
name = name[strings.LastIndex(name, `/`)+1:]
name = name[strings.LastIndex(name, `\`)+1:]
name = strings.TrimSuffix(name, ".exe")
// If there's an active experiment, include that,
// to distinguish go1.10.2 with an experiment
// from go1.10.2 without an experiment.
p := Expstring()
if p == DefaultExpstring() {
p = ""
}
sep := ""
if p != "" {
sep = " "
}
// The go command invokes -V=full to get a unique identifier
// for this tool. It is assumed that the release version is sufficient
// for releases, but during development we include the full
// build ID of the binary, so that if the compiler is changed and
// rebuilt, we notice and rebuild all packages.
if s == "full" {
if strings.HasPrefix(Version, "devel") {
p += " buildID=" + buildID
}
}
fmt.Printf("%s version %s%s%s\n", name, Version, sep, p)
os.Exit(0)
return nil
}
// count is a flag.Value that is like a flag.Bool and a flag.Int.
// If used as -name, it increments the count, but -name=x sets the count.
// Used for verbose flag -v.
type count int
func (c *count) String() string {
return fmt.Sprint(int(*c))
}
func (c *count) Set(s string) error {
switch s {
case "true":
*c++
case "false":
*c = 0
default:
n, err := strconv.Atoi(s)
if err != nil {
return fmt.Errorf("invalid count %q", s)
}
*c = count(n)
}
return nil
}
func (c *count) Get() interface{} {
return int(*c)
}
func (c *count) IsBoolFlag() bool {
return true
}
func (c *count) IsCountFlag() bool {
return true
}
type fn1 func(string)
func (f fn1) Set(s string) error {
f(s)
return nil
}
func (f fn1) String() string { return "" }

View File

@ -0,0 +1,54 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package objabi
// This file defines the IDs for PCDATA and FUNCDATA instructions
// in Go binaries.
//
// These must agree with ../../../runtime/funcdata.h and
// ../../../runtime/symtab.go.
const (
PCDATA_RegMapIndex = 0 // if !go115ReduceLiveness
PCDATA_UnsafePoint = 0 // if go115ReduceLiveness
PCDATA_StackMapIndex = 1
PCDATA_InlTreeIndex = 2
FUNCDATA_ArgsPointerMaps = 0
FUNCDATA_LocalsPointerMaps = 1
FUNCDATA_RegPointerMaps = 2 // if !go115ReduceLiveness
FUNCDATA_StackObjects = 3
FUNCDATA_InlTree = 4
FUNCDATA_OpenCodedDeferInfo = 5
// ArgsSizeUnknown is set in Func.argsize to mark all functions
// whose argument size is unknown (C vararg functions, and
// assembly code without an explicit specification).
// This value is generated by the compiler, assembler, or linker.
ArgsSizeUnknown = -0x80000000
)
// Special PCDATA values.
const (
// PCDATA_RegMapIndex values.
//
// Only if !go115ReduceLiveness.
PCDATA_RegMapUnsafe = PCDATA_UnsafePointUnsafe // Unsafe for async preemption
// PCDATA_UnsafePoint values.
PCDATA_UnsafePointSafe = -1 // Safe for async preemption
PCDATA_UnsafePointUnsafe = -2 // Unsafe for async preemption
// PCDATA_Restart1(2) apply on a sequence of instructions, within
// which if an async preemption happens, we should back off the PC
// to the start of the sequence when resuming.
// We need two so we can distinguish the start/end of the sequence
// in case that two sequences are next to each other.
PCDATA_Restart1 = -3
PCDATA_Restart2 = -4
// Like PCDATA_Restart1, but back to function entry if async preempted.
PCDATA_RestartAtEntry = -5
)

View File

@ -0,0 +1,100 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package objabi
// A FuncID identifies particular functions that need to be treated
// specially by the runtime.
// Note that in some situations involving plugins, there may be multiple
// copies of a particular special runtime function.
// Note: this list must match the list in runtime/symtab.go.
type FuncID uint8
const (
FuncID_normal FuncID = iota // not a special function
FuncID_runtime_main
FuncID_goexit
FuncID_jmpdefer
FuncID_mcall
FuncID_morestack
FuncID_mstart
FuncID_rt0_go
FuncID_asmcgocall
FuncID_sigpanic
FuncID_runfinq
FuncID_gcBgMarkWorker
FuncID_systemstack_switch
FuncID_systemstack
FuncID_cgocallback_gofunc
FuncID_gogo
FuncID_externalthreadhandler
FuncID_debugCallV1
FuncID_gopanic
FuncID_panicwrap
FuncID_handleAsyncEvent
FuncID_asyncPreempt
FuncID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.)
)
// Get the function ID for the named function in the named file.
// The function should be package-qualified.
func GetFuncID(name string, isWrapper bool) FuncID {
if isWrapper {
return FuncID_wrapper
}
switch name {
case "runtime.main":
return FuncID_runtime_main
case "runtime.goexit":
return FuncID_goexit
case "runtime.jmpdefer":
return FuncID_jmpdefer
case "runtime.mcall":
return FuncID_mcall
case "runtime.morestack":
return FuncID_morestack
case "runtime.mstart":
return FuncID_mstart
case "runtime.rt0_go":
return FuncID_rt0_go
case "runtime.asmcgocall":
return FuncID_asmcgocall
case "runtime.sigpanic":
return FuncID_sigpanic
case "runtime.runfinq":
return FuncID_runfinq
case "runtime.gcBgMarkWorker":
return FuncID_gcBgMarkWorker
case "runtime.systemstack_switch":
return FuncID_systemstack_switch
case "runtime.systemstack":
return FuncID_systemstack
case "runtime.cgocallback_gofunc":
return FuncID_cgocallback_gofunc
case "runtime.gogo":
return FuncID_gogo
case "runtime.externalthreadhandler":
return FuncID_externalthreadhandler
case "runtime.debugCallV1":
return FuncID_debugCallV1
case "runtime.gopanic":
return FuncID_gopanic
case "runtime.panicwrap":
return FuncID_panicwrap
case "runtime.handleAsyncEvent":
return FuncID_handleAsyncEvent
case "runtime.asyncPreempt":
return FuncID_asyncPreempt
case "runtime.deferreturn":
// Don't show in the call stack (used when invoking defer functions)
return FuncID_wrapper
case "runtime.runOpenDeferFrame":
// Don't show in the call stack (used when invoking defer functions)
return FuncID_wrapper
case "runtime.reflectcallSave":
// Don't show in the call stack (used when invoking defer functions)
return FuncID_wrapper
}
return FuncID_normal
}

View File

@ -0,0 +1,109 @@
// Derived from Inferno utils/6l/l.h and related files.
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package objabi
import "fmt"
// HeadType is the executable header type.
type HeadType uint8
const (
Hunknown HeadType = iota
Hdarwin
Hdragonfly
Hfreebsd
Hjs
Hlinux
Hnetbsd
Hopenbsd
Hplan9
Hsolaris
Hwindows
Haix
)
func (h *HeadType) Set(s string) error {
switch s {
case "aix":
*h = Haix
case "darwin":
*h = Hdarwin
case "dragonfly":
*h = Hdragonfly
case "freebsd":
*h = Hfreebsd
case "js":
*h = Hjs
case "linux", "android":
*h = Hlinux
case "netbsd":
*h = Hnetbsd
case "openbsd":
*h = Hopenbsd
case "plan9":
*h = Hplan9
case "illumos", "solaris":
*h = Hsolaris
case "windows":
*h = Hwindows
default:
return fmt.Errorf("invalid headtype: %q", s)
}
return nil
}
func (h *HeadType) String() string {
switch *h {
case Haix:
return "aix"
case Hdarwin:
return "darwin"
case Hdragonfly:
return "dragonfly"
case Hfreebsd:
return "freebsd"
case Hjs:
return "js"
case Hlinux:
return "linux"
case Hnetbsd:
return "netbsd"
case Hopenbsd:
return "openbsd"
case Hplan9:
return "plan9"
case Hsolaris:
return "solaris"
case Hwindows:
return "windows"
}
return fmt.Sprintf("HeadType(%d)", *h)
}

View File

@ -0,0 +1,114 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package objabi
import (
"os"
"path/filepath"
"strings"
)
// WorkingDir returns the current working directory
// (or "/???" if the directory cannot be identified),
// with "/" as separator.
func WorkingDir() string {
var path string
path, _ = os.Getwd()
if path == "" {
path = "/???"
}
return filepath.ToSlash(path)
}
// AbsFile returns the absolute filename for file in the given directory,
// as rewritten by the rewrites argument.
// For unrewritten paths, AbsFile rewrites a leading $GOROOT prefix to the literal "$GOROOT".
// If the resulting path is the empty string, the result is "??".
//
// The rewrites argument is a ;-separated list of rewrites.
// Each rewrite is of the form "prefix" or "prefix=>replace",
// where prefix must match a leading sequence of path elements
// and is either removed entirely or replaced by the replacement.
func AbsFile(dir, file, rewrites string) string {
abs := file
if dir != "" && !filepath.IsAbs(file) {
abs = filepath.Join(dir, file)
}
start := 0
for i := 0; i <= len(rewrites); i++ {
if i == len(rewrites) || rewrites[i] == ';' {
if new, ok := applyRewrite(abs, rewrites[start:i]); ok {
abs = new
goto Rewritten
}
start = i + 1
}
}
if hasPathPrefix(abs, GOROOT) {
abs = "$GOROOT" + abs[len(GOROOT):]
}
Rewritten:
if abs == "" {
abs = "??"
}
return abs
}
// applyRewrite applies the rewrite to the path,
// returning the rewritten path and a boolean
// indicating whether the rewrite applied at all.
func applyRewrite(path, rewrite string) (string, bool) {
prefix, replace := rewrite, ""
if j := strings.LastIndex(rewrite, "=>"); j >= 0 {
prefix, replace = rewrite[:j], rewrite[j+len("=>"):]
}
if prefix == "" || !hasPathPrefix(path, prefix) {
return path, false
}
if len(path) == len(prefix) {
return replace, true
}
if replace == "" {
return path[len(prefix)+1:], true
}
return replace + path[len(prefix):], true
}
// Does s have t as a path prefix?
// That is, does s == t or does s begin with t followed by a slash?
// For portability, we allow ASCII case folding, so that hasPathPrefix("a/b/c", "A/B") is true.
// Similarly, we allow slash folding, so that hasPathPrefix("a/b/c", "a\\b") is true.
// We do not allow full Unicode case folding, for fear of causing more confusion
// or harm than good. (For an example of the kinds of things that can go wrong,
// see http://article.gmane.org/gmane.linux.kernel/1853266.)
func hasPathPrefix(s string, t string) bool {
if len(t) > len(s) {
return false
}
var i int
for i = 0; i < len(t); i++ {
cs := int(s[i])
ct := int(t[i])
if 'A' <= cs && cs <= 'Z' {
cs += 'a' - 'A'
}
if 'A' <= ct && ct <= 'Z' {
ct += 'a' - 'A'
}
if cs == '\\' {
cs = '/'
}
if ct == '\\' {
ct = '/'
}
if cs != ct {
return false
}
}
return i >= len(s) || s[i] == '/' || s[i] == '\\'
}

View File

@ -0,0 +1,41 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package objabi
import "strings"
// PathToPrefix converts raw string to the prefix that will be used in the
// symbol table. All control characters, space, '%' and '"', as well as
// non-7-bit clean bytes turn into %xx. The period needs escaping only in the
// last segment of the path, and it makes for happier users if we escape that as
// little as possible.
func PathToPrefix(s string) string {
slash := strings.LastIndex(s, "/")
// check for chars that need escaping
n := 0
for r := 0; r < len(s); r++ {
if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
n++
}
}
// quick exit
if n == 0 {
return s
}
// escape
const hex = "0123456789abcdef"
p := make([]byte, 0, len(s)+2*n)
for r := 0; r < len(s); r++ {
if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
p = append(p, '%', hex[c>>4], hex[c&0xF])
} else {
p = append(p, c)
}
}
return string(p)
}

View File

@ -0,0 +1,269 @@
// Derived from Inferno utils/6l/l.h and related files.
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package objabi
type RelocType int16
//go:generate stringer -type=RelocType
const (
R_ADDR RelocType = 1 + iota
// R_ADDRPOWER relocates a pair of "D-form" instructions (instructions with 16-bit
// immediates in the low half of the instruction word), usually addis followed by
// another add or a load, inserting the "high adjusted" 16 bits of the address of
// the referenced symbol into the immediate field of the first instruction and the
// low 16 bits into that of the second instruction.
R_ADDRPOWER
// R_ADDRARM64 relocates an adrp, add pair to compute the address of the
// referenced symbol.
R_ADDRARM64
// R_ADDRMIPS (only used on mips/mips64) resolves to the low 16 bits of an external
// address, by encoding it into the instruction.
R_ADDRMIPS
// R_ADDROFF resolves to a 32-bit offset from the beginning of the section
// holding the data being relocated to the referenced symbol.
R_ADDROFF
// R_WEAKADDROFF resolves just like R_ADDROFF but is a weak relocation.
// A weak relocation does not make the symbol it refers to reachable,
// and is only honored by the linker if the symbol is in some other way
// reachable.
R_WEAKADDROFF
R_SIZE
R_CALL
R_CALLARM
R_CALLARM64
R_CALLIND
R_CALLPOWER
// R_CALLMIPS (only used on mips64) resolves to non-PC-relative target address
// of a CALL (JAL) instruction, by encoding the address into the instruction.
R_CALLMIPS
// R_CALLRISCV marks RISC-V CALLs for stack checking.
R_CALLRISCV
R_CONST
R_PCREL
// R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the
// thread-local symbol from the thread local base and is used to implement the
// "local exec" model for tls access (r.Sym is not set on intel platforms but is
// set to a TLS symbol -- runtime.tlsg -- in the linker when externally linking).
R_TLS_LE
// R_TLS_IE, used 386, amd64, and ARM resolves to the PC-relative offset to a GOT
// slot containing the offset from the thread-local symbol from the thread local
// base and is used to implemented the "initial exec" model for tls access (r.Sym
// is not set on intel platforms but is set to a TLS symbol -- runtime.tlsg -- in
// the linker when externally linking).
R_TLS_IE
R_GOTOFF
R_PLT0
R_PLT1
R_PLT2
R_USEFIELD
// R_USETYPE resolves to an *rtype, but no relocation is created. The
// linker uses this as a signal that the pointed-to type information
// should be linked into the final binary, even if there are no other
// direct references. (This is used for types reachable by reflection.)
R_USETYPE
// R_METHODOFF resolves to a 32-bit offset from the beginning of the section
// holding the data being relocated to the referenced symbol.
// It is a variant of R_ADDROFF used when linking from the uncommonType of a
// *rtype, and may be set to zero by the linker if it determines the method
// text is unreachable by the linked program.
R_METHODOFF
R_POWER_TOC
R_GOTPCREL
// R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address
// of a JMP instruction, by encoding the address into the instruction.
// The stack nosplit check ignores this since it is not a function call.
R_JMPMIPS
// R_DWARFSECREF resolves to the offset of the symbol from its section.
// Target of relocation must be size 4 (in current implementation).
R_DWARFSECREF
// R_DWARFFILEREF resolves to an index into the DWARF .debug_line
// file table for the specified file symbol. Must be applied to an
// attribute of form DW_FORM_data4.
R_DWARFFILEREF
// Platform dependent relocations. Architectures with fixed width instructions
// have the inherent issue that a 32-bit (or 64-bit!) displacement cannot be
// stuffed into a 32-bit instruction, so an address needs to be spread across
// several instructions, and in turn this requires a sequence of relocations, each
// updating a part of an instruction. This leads to relocation codes that are
// inherently processor specific.
// Arm64.
// Set a MOV[NZ] immediate field to bits [15:0] of the offset from the thread
// local base to the thread local variable defined by the referenced (thread
// local) symbol. Error if the offset does not fit into 16 bits.
R_ARM64_TLS_LE
// Relocates an ADRP; LD64 instruction sequence to load the offset between
// the thread local base and the thread local variable defined by the
// referenced (thread local) symbol from the GOT.
R_ARM64_TLS_IE
// R_ARM64_GOTPCREL relocates an adrp, ld64 pair to compute the address of the GOT
// slot of the referenced symbol.
R_ARM64_GOTPCREL
// R_ARM64_GOT resolves a GOT-relative instruction sequence, usually an adrp
// followed by another ld instruction.
R_ARM64_GOT
// R_ARM64_PCREL resolves a PC-relative addresses instruction sequence, usually an
// adrp followed by another add instruction.
R_ARM64_PCREL
// R_ARM64_LDST8 sets a LD/ST immediate value to bits [11:0] of a local address.
R_ARM64_LDST8
// R_ARM64_LDST32 sets a LD/ST immediate value to bits [11:2] of a local address.
R_ARM64_LDST32
// R_ARM64_LDST64 sets a LD/ST immediate value to bits [11:3] of a local address.
R_ARM64_LDST64
// R_ARM64_LDST128 sets a LD/ST immediate value to bits [11:4] of a local address.
R_ARM64_LDST128
// PPC64.
// R_POWER_TLS_LE is used to implement the "local exec" model for tls
// access. It resolves to the offset of the thread-local symbol from the
// thread pointer (R13) and inserts this value into the low 16 bits of an
// instruction word.
R_POWER_TLS_LE
// R_POWER_TLS_IE is used to implement the "initial exec" model for tls access. It
// relocates a D-form, DS-form instruction sequence like R_ADDRPOWER_DS. It
// inserts to the offset of GOT slot for the thread-local symbol from the TOC (the
// GOT slot is filled by the dynamic linker with the offset of the thread-local
// symbol from the thread pointer (R13)).
R_POWER_TLS_IE
// R_POWER_TLS marks an X-form instruction such as "MOVD 0(R13)(R31*1), g" as
// accessing a particular thread-local symbol. It does not affect code generation
// but is used by the system linker when relaxing "initial exec" model code to
// "local exec" model code.
R_POWER_TLS
// R_ADDRPOWER_DS is similar to R_ADDRPOWER above, but assumes the second
// instruction is a "DS-form" instruction, which has an immediate field occupying
// bits [15:2] of the instruction word. Bits [15:2] of the address of the
// relocated symbol are inserted into this field; it is an error if the last two
// bits of the address are not 0.
R_ADDRPOWER_DS
// R_ADDRPOWER_PCREL relocates a D-form, DS-form instruction sequence like
// R_ADDRPOWER_DS but inserts the offset of the GOT slot for the referenced symbol
// from the TOC rather than the symbol's address.
R_ADDRPOWER_GOT
// R_ADDRPOWER_PCREL relocates two D-form instructions like R_ADDRPOWER, but
// inserts the displacement from the place being relocated to the address of the
// relocated symbol instead of just its address.
R_ADDRPOWER_PCREL
// R_ADDRPOWER_TOCREL relocates two D-form instructions like R_ADDRPOWER, but
// inserts the offset from the TOC to the address of the relocated symbol
// rather than the symbol's address.
R_ADDRPOWER_TOCREL
// R_ADDRPOWER_TOCREL relocates a D-form, DS-form instruction sequence like
// R_ADDRPOWER_DS but inserts the offset from the TOC to the address of the
// relocated symbol rather than the symbol's address.
R_ADDRPOWER_TOCREL_DS
// RISC-V.
// R_RISCV_PCREL_ITYPE resolves a 32-bit PC-relative address using an
// AUIPC + I-type instruction pair.
R_RISCV_PCREL_ITYPE
// R_RISCV_PCREL_STYPE resolves a 32-bit PC-relative address using an
// AUIPC + S-type instruction pair.
R_RISCV_PCREL_STYPE
// R_PCRELDBL relocates s390x 2-byte aligned PC-relative addresses.
// TODO(mundaym): remove once variants can be serialized - see issue 14218.
R_PCRELDBL
// R_ADDRMIPSU (only used on mips/mips64) resolves to the sign-adjusted "upper" 16
// bits (bit 16-31) of an external address, by encoding it into the instruction.
R_ADDRMIPSU
// R_ADDRMIPSTLS (only used on mips64) resolves to the low 16 bits of a TLS
// address (offset from thread pointer), by encoding it into the instruction.
R_ADDRMIPSTLS
// R_ADDRCUOFF resolves to a pointer-sized offset from the start of the
// symbol's DWARF compile unit.
R_ADDRCUOFF
// R_WASMIMPORT resolves to the index of the WebAssembly function import.
R_WASMIMPORT
// R_XCOFFREF (only used on aix/ppc64) prevents garbage collection by ld
// of a symbol. This isn't a real relocation, it can be placed in anywhere
// in a symbol and target any symbols.
R_XCOFFREF
)
// IsDirectCall reports whether r is a relocation for a direct call.
// A direct call is a CALL instruction that takes the target address
// as an immediate. The address is embedded into the instruction, possibly
// with limited width. An indirect call is a CALL instruction that takes
// the target address in register or memory.
func (r RelocType) IsDirectCall() bool {
switch r {
case R_CALL, R_CALLARM, R_CALLARM64, R_CALLMIPS, R_CALLPOWER, R_CALLRISCV:
return true
}
return false
}
// IsDirectJump reports whether r is a relocation for a direct jump.
// A direct jump is a JMP instruction that takes the target address
// as an immediate. The address is embedded into the instruction, possibly
// with limited width. An indirect jump is a JMP instruction that takes
// the target address in register or memory.
func (r RelocType) IsDirectJump() bool {
switch r {
case R_JMPMIPS:
return true
}
return false
}
// IsDirectCallOrJump reports whether r is a relocation for a direct
// call or a direct jump.
func (r RelocType) IsDirectCallOrJump() bool {
return r.IsDirectCall() || r.IsDirectJump()
}

View File

@ -0,0 +1,17 @@
// Code generated by "stringer -type=RelocType"; DO NOT EDIT.
package objabi
import "strconv"
const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 219, 230, 240, 249, 262, 276, 290, 304, 320, 331, 344, 357, 371, 385, 400, 414, 428, 439, 453, 468, 485, 503, 524, 543, 562, 572, 583, 596, 607, 619, 629}
func (i RelocType) String() string {
i -= 1
if i < 0 || i >= RelocType(len(_RelocType_index)-1) {
return "RelocType(" + strconv.FormatInt(int64(i+1), 10) + ")"
}
return _RelocType_name[_RelocType_index[i]:_RelocType_index[i+1]]
}

View File

@ -0,0 +1,33 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package objabi
// For the linkers. Must match Go definitions.
const (
STACKSYSTEM = 0
StackSystem = STACKSYSTEM
StackBig = 4096
StackSmall = 128
)
const (
StackPreempt = -1314 // 0xfff...fade
)
// Initialize StackGuard and StackLimit according to target system.
var StackGuard = 928*stackGuardMultiplier() + StackSystem
var StackLimit = StackGuard - StackSystem - StackSmall
// stackGuardMultiplier returns a multiplier to apply to the default
// stack guard size. Larger multipliers are used for non-optimized
// builds that have larger stack frames or for specific targets.
func stackGuardMultiplier() int {
// On AIX, a larger stack is needed for syscalls.
if GOOS == "aix" {
return 2
}
return 1
}

View File

@ -0,0 +1,79 @@
// Derived from Inferno utils/6l/l.h and related files.
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package objabi
// A SymKind describes the kind of memory represented by a symbol.
type SymKind uint8
// Defined SymKind values.
// These are used to index into cmd/link/internal/sym/AbiSymKindToSymKind
//
// TODO(rsc): Give idiomatic Go names.
//go:generate stringer -type=SymKind
const (
// An otherwise invalid zero value for the type
Sxxx SymKind = iota
// Executable instructions
STEXT
// Read only static data
SRODATA
// Static data that does not contain any pointers
SNOPTRDATA
// Static data
SDATA
// Statically data that is initially all 0s
SBSS
// Statically data that is initially all 0s and does not contain pointers
SNOPTRBSS
// Thread-local data that is initially all 0s
STLSBSS
// Debugging data
SDWARFCUINFO
SDWARFCONST
SDWARFFCN
SDWARFABSFCN
SDWARFTYPE
SDWARFVAR
SDWARFRANGE
SDWARFLOC
SDWARFLINES
// ABI alias. An ABI alias symbol is an empty symbol with a
// single relocation with 0 size that references the native
// function implementation symbol.
//
// TODO(austin): Remove this and all uses once the compiler
// generates real ABI wrappers rather than symbol aliases.
SABIALIAS
// Coverage instrumentation counter for libfuzzer.
SLIBFUZZER_EXTRA_COUNTER
// Update cmd/link/internal/sym/AbiSymKindToSymKind for new SymKind values.
)

View File

@ -0,0 +1,41 @@
// Code generated by "stringer -type=SymKind"; DO NOT EDIT.
package objabi
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Sxxx-0]
_ = x[STEXT-1]
_ = x[SRODATA-2]
_ = x[SNOPTRDATA-3]
_ = x[SDATA-4]
_ = x[SBSS-5]
_ = x[SNOPTRBSS-6]
_ = x[STLSBSS-7]
_ = x[SDWARFCUINFO-8]
_ = x[SDWARFCONST-9]
_ = x[SDWARFFCN-10]
_ = x[SDWARFABSFCN-11]
_ = x[SDWARFTYPE-12]
_ = x[SDWARFVAR-13]
_ = x[SDWARFRANGE-14]
_ = x[SDWARFLOC-15]
_ = x[SDWARFLINES-16]
_ = x[SABIALIAS-17]
_ = x[SLIBFUZZER_EXTRA_COUNTER-18]
}
const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINESSABIALIASSLIBFUZZER_EXTRA_COUNTER"
var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 63, 74, 83, 95, 105, 114, 125, 134, 145, 154, 178}
func (i SymKind) String() string {
if i >= SymKind(len(_SymKind_index)-1) {
return "SymKind(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _SymKind_name[_SymKind_index[i]:_SymKind_index[i+1]]
}

View File

@ -0,0 +1,40 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package objabi
// Must match runtime and reflect.
// Included by cmd/gc.
const (
KindBool = 1 + iota
KindInt
KindInt8
KindInt16
KindInt32
KindInt64
KindUint
KindUint8
KindUint16
KindUint32
KindUint64
KindUintptr
KindFloat32
KindFloat64
KindComplex64
KindComplex128
KindArray
KindChan
KindFunc
KindInterface
KindMap
KindPtr
KindSlice
KindString
KindStruct
KindUnsafePointer
KindDirectIface = 1 << 5
KindGCProg = 1 << 6
KindMask = (1 << 5) - 1
)

Some files were not shown because too many files have changed in this diff Show More