From 3a21ef192628f6952eaa981bcdf718a35a4b43c7 Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Wed, 13 Dec 2017 10:43:58 -0800 Subject: convert to go buildpack --- .../google/gops/internal/obj/addrtype_string.go | 27 + .../google/gops/internal/obj/arm/a.out.go | 338 ++ .../google/gops/internal/obj/arm/anames.go | 108 + .../google/gops/internal/obj/arm/anames5.go | 73 + .../google/gops/internal/obj/arm/asm5.go | 2846 ++++++++++++ .../google/gops/internal/obj/arm/list5.go | 84 + .../google/gops/internal/obj/arm/obj5.go | 1055 +++++ .../google/gops/internal/obj/arm64/a.out.go | 719 +++ .../google/gops/internal/obj/arm64/anames.go | 370 ++ .../google/gops/internal/obj/arm64/anames7.go | 70 + .../google/gops/internal/obj/arm64/asm7.go | 4374 ++++++++++++++++++ .../google/gops/internal/obj/arm64/list7.go | 115 + .../google/gops/internal/obj/arm64/obj7.go | 1005 +++++ vendor/github.com/google/gops/internal/obj/data.go | 190 + vendor/github.com/google/gops/internal/obj/flag.go | 115 + .../google/gops/internal/obj/funcdata.go | 48 + vendor/github.com/google/gops/internal/obj/go.go | 86 + vendor/github.com/google/gops/internal/obj/ld.go | 92 + .../google/gops/internal/obj/line_test.go | 49 + vendor/github.com/google/gops/internal/obj/link.go | 974 ++++ .../google/gops/internal/obj/mips/a.out.go | 375 ++ .../google/gops/internal/obj/mips/anames.go | 113 + .../google/gops/internal/obj/mips/anames0.go | 44 + .../google/gops/internal/obj/mips/asm0.go | 1783 ++++++++ .../google/gops/internal/obj/mips/list0.go | 85 + .../google/gops/internal/obj/mips/obj0.go | 1497 ++++++ vendor/github.com/google/gops/internal/obj/obj.go | 306 ++ .../github.com/google/gops/internal/obj/objfile.go | 606 +++ vendor/github.com/google/gops/internal/obj/pass.go | 217 + vendor/github.com/google/gops/internal/obj/pcln.go | 281 ++ .../github.com/google/gops/internal/obj/plist.go | 208 + .../google/gops/internal/obj/ppc64/a.out.go | 941 ++++ .../google/gops/internal/obj/ppc64/anames.go | 549 +++ .../google/gops/internal/obj/ppc64/anames9.go | 49 + .../google/gops/internal/obj/ppc64/asm9.go | 4552 +++++++++++++++++++ .../google/gops/internal/obj/ppc64/list9.go | 105 + .../google/gops/internal/obj/ppc64/obj9.go | 1251 +++++ .../google/gops/internal/obj/reloctype_string.go | 17 + .../google/gops/internal/obj/s390x/a.out.go | 926 ++++ .../google/gops/internal/obj/s390x/anames.go | 675 +++ .../google/gops/internal/obj/s390x/anamesz.go | 39 + .../google/gops/internal/obj/s390x/asmz.go | 4766 ++++++++++++++++++++ .../google/gops/internal/obj/s390x/listz.go | 74 + .../google/gops/internal/obj/s390x/objz.go | 1029 +++++ .../google/gops/internal/obj/s390x/vector.go | 1061 +++++ .../google/gops/internal/obj/sizeof_test.go | 40 + .../github.com/google/gops/internal/obj/stack.go | 21 + .../google/gops/internal/obj/stringer.go | 104 + vendor/github.com/google/gops/internal/obj/sym.go | 88 + .../google/gops/internal/obj/symkind_string.go | 16 + .../google/gops/internal/obj/textflag.go | 50 + .../google/gops/internal/obj/typekind.go | 41 + vendor/github.com/google/gops/internal/obj/util.go | 499 ++ .../google/gops/internal/obj/x86/a.out.go | 1009 +++++ .../google/gops/internal/obj/x86/anames.go | 769 ++++ .../google/gops/internal/obj/x86/asm6.go | 4536 +++++++++++++++++++ .../google/gops/internal/obj/x86/list6.go | 181 + .../google/gops/internal/obj/x86/obj6.go | 1481 ++++++ .../google/gops/internal/obj/zbootstrap.go | 15 + 59 files changed, 43137 insertions(+) create mode 100644 vendor/github.com/google/gops/internal/obj/addrtype_string.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm/a.out.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm/anames.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm/anames5.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm/asm5.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm/list5.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm/obj5.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm64/a.out.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm64/anames.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm64/anames7.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm64/asm7.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm64/list7.go create mode 100644 vendor/github.com/google/gops/internal/obj/arm64/obj7.go create mode 100644 vendor/github.com/google/gops/internal/obj/data.go create mode 100644 vendor/github.com/google/gops/internal/obj/flag.go create mode 100644 vendor/github.com/google/gops/internal/obj/funcdata.go create mode 100644 vendor/github.com/google/gops/internal/obj/go.go create mode 100644 vendor/github.com/google/gops/internal/obj/ld.go create mode 100644 vendor/github.com/google/gops/internal/obj/line_test.go create mode 100644 vendor/github.com/google/gops/internal/obj/link.go create mode 100644 vendor/github.com/google/gops/internal/obj/mips/a.out.go create mode 100644 vendor/github.com/google/gops/internal/obj/mips/anames.go create mode 100644 vendor/github.com/google/gops/internal/obj/mips/anames0.go create mode 100644 vendor/github.com/google/gops/internal/obj/mips/asm0.go create mode 100644 vendor/github.com/google/gops/internal/obj/mips/list0.go create mode 100644 vendor/github.com/google/gops/internal/obj/mips/obj0.go create mode 100644 vendor/github.com/google/gops/internal/obj/obj.go create mode 100644 vendor/github.com/google/gops/internal/obj/objfile.go create mode 100644 vendor/github.com/google/gops/internal/obj/pass.go create mode 100644 vendor/github.com/google/gops/internal/obj/pcln.go create mode 100644 vendor/github.com/google/gops/internal/obj/plist.go create mode 100644 vendor/github.com/google/gops/internal/obj/ppc64/a.out.go create mode 100644 vendor/github.com/google/gops/internal/obj/ppc64/anames.go create mode 100644 vendor/github.com/google/gops/internal/obj/ppc64/anames9.go create mode 100644 vendor/github.com/google/gops/internal/obj/ppc64/asm9.go create mode 100644 vendor/github.com/google/gops/internal/obj/ppc64/list9.go create mode 100644 vendor/github.com/google/gops/internal/obj/ppc64/obj9.go create mode 100644 vendor/github.com/google/gops/internal/obj/reloctype_string.go create mode 100644 vendor/github.com/google/gops/internal/obj/s390x/a.out.go create mode 100644 vendor/github.com/google/gops/internal/obj/s390x/anames.go create mode 100644 vendor/github.com/google/gops/internal/obj/s390x/anamesz.go create mode 100644 vendor/github.com/google/gops/internal/obj/s390x/asmz.go create mode 100644 vendor/github.com/google/gops/internal/obj/s390x/listz.go create mode 100644 vendor/github.com/google/gops/internal/obj/s390x/objz.go create mode 100644 vendor/github.com/google/gops/internal/obj/s390x/vector.go create mode 100644 vendor/github.com/google/gops/internal/obj/sizeof_test.go create mode 100644 vendor/github.com/google/gops/internal/obj/stack.go create mode 100644 vendor/github.com/google/gops/internal/obj/stringer.go create mode 100644 vendor/github.com/google/gops/internal/obj/sym.go create mode 100644 vendor/github.com/google/gops/internal/obj/symkind_string.go create mode 100644 vendor/github.com/google/gops/internal/obj/textflag.go create mode 100644 vendor/github.com/google/gops/internal/obj/typekind.go create mode 100644 vendor/github.com/google/gops/internal/obj/util.go create mode 100644 vendor/github.com/google/gops/internal/obj/x86/a.out.go create mode 100644 vendor/github.com/google/gops/internal/obj/x86/anames.go create mode 100644 vendor/github.com/google/gops/internal/obj/x86/asm6.go create mode 100644 vendor/github.com/google/gops/internal/obj/x86/list6.go create mode 100644 vendor/github.com/google/gops/internal/obj/x86/obj6.go create mode 100644 vendor/github.com/google/gops/internal/obj/zbootstrap.go (limited to 'vendor/github.com/google/gops/internal/obj') diff --git a/vendor/github.com/google/gops/internal/obj/addrtype_string.go b/vendor/github.com/google/gops/internal/obj/addrtype_string.go new file mode 100644 index 0000000..48d498d --- /dev/null +++ b/vendor/github.com/google/gops/internal/obj/addrtype_string.go @@ -0,0 +1,27 @@ +// Code generated by "stringer -type AddrType cmd/internal/obj"; DO NOT EDIT + +package obj + +import "fmt" + +const ( + _AddrType_name_0 = "TYPE_NONE" + _AddrType_name_1 = "TYPE_BRANCHTYPE_TEXTSIZETYPE_MEMTYPE_CONSTTYPE_FCONSTTYPE_SCONSTTYPE_REGTYPE_ADDRTYPE_SHIFTTYPE_REGREGTYPE_REGREG2TYPE_INDIRTYPE_REGLIST" +) + +var ( + _AddrType_index_0 = [...]uint8{0, 9} + _AddrType_index_1 = [...]uint8{0, 11, 24, 32, 42, 53, 64, 72, 81, 91, 102, 114, 124, 136} +) + +func (i AddrType) String() string { + switch { + case i == 0: + return _AddrType_name_0 + case 6 <= i && i <= 18: + i -= 6 + return _AddrType_name_1[_AddrType_index_1[i]:_AddrType_index_1[i+1]] + default: + return fmt.Sprintf("AddrType(%d)", i) + } +} diff --git a/vendor/github.com/google/gops/internal/obj/arm/a.out.go b/vendor/github.com/google/gops/internal/obj/arm/a.out.go new file mode 100644 index 0000000..a3e0c18 --- /dev/null +++ b/vendor/github.com/google/gops/internal/obj/arm/a.out.go @@ -0,0 +1,338 @@ +// Inferno utils/5c/5.out.h +// https://bitbucket.org/inferno-os/inferno-os/src/default/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/google/gops/internal/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 + + MAXREG + 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 +) + +const ( + C_NONE = iota + C_REG + C_REGREG + C_REGREG2 + C_REGLIST + C_SHIFT + C_FREG + C_PSR + C_FCR + + C_RCON /* 0xff rotated */ + C_NCON /* ~RCON */ + 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 + ADIVF + ADIVD + ASQRTF + ASQRTD + AABSF + AABSD + ANEGF + ANEGD + + ASRL + ASRA + ASLL + AMULU + ADIVU + AMUL + ADIV + AMOD + AMODU + + AMOVB + AMOVBS + AMOVBU + AMOVH + AMOVHS + AMOVHU + AMOVW + AMOVM + ASWPBU + ASWPW + + ARFE + ASWI + AMULA + + AWORD + + AMULL + AMULAL + AMULLU + AMULALU + + ABX + ABXRET + ADWORD + + ALDREX + ASTREX + ALDREXD + ASTREXD + + APLD + + ACLZ + + AMULWT + AMULWB + AMULAWT + AMULAWB + + ADATABUNDLE + ADATABUNDLEEND + + 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 +) diff --git a/vendor/github.com/google/gops/internal/obj/arm/anames.go b/vendor/github.com/google/gops/internal/obj/arm/anames.go new file mode 100644 index 0000000..42abc94 --- /dev/null +++ b/vendor/github.com/google/gops/internal/obj/arm/anames.go @@ -0,0 +1,108 @@ +// Generated by stringer -i a.out.go -o anames.go -p arm +// Do not edit. + +package arm + +import "github.com/google/gops/internal/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", + "DIVF", + "DIVD", + "SQRTF", + "SQRTD", + "ABSF", + "ABSD", + "NEGF", + "NEGD", + "SRL", + "SRA", + "SLL", + "MULU", + "DIVU", + "MUL", + "DIV", + "MOD", + "MODU", + "MOVB", + "MOVBS", + "MOVBU", + "MOVH", + "MOVHS", + "MOVHU", + "MOVW", + "MOVM", + "SWPBU", + "SWPW", + "RFE", + "SWI", + "MULA", + "WORD", + "MULL", + "MULAL", + "MULLU", + "MULALU", + "BX", + "BXRET", + "DWORD", + "LDREX", + "STREX", + "LDREXD", + "STREXD", + "PLD", + "CLZ", + "MULWT", + "MULWB", + "MULAWT", + "MULAWB", + "DATABUNDLE", + "DATABUNDLEEND", + "MRC", + "LAST", +} diff --git a/vendor/github.com/google/gops/internal/obj/arm/anames5.go b/vendor/github.com/google/gops/internal/obj/arm/anames5.go new file mode 100644 index 0000000..7fdd962 --- /dev/null +++ b/vendor/github.com/google/gops/internal/obj/arm/anames5.go @@ -0,0 +1,73 @@ +// 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", + "FREG", + "PSR", + "FCR", + "RCON", + "NCON", + "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", +} diff --git a/vendor/github.com/google/gops/internal/obj/arm/asm5.go b/vendor/github.com/google/gops/internal/obj/arm/asm5.go new file mode 100644 index 0000000..aa8149d --- /dev/null +++ b/vendor/github.com/google/gops/internal/obj/arm/asm5.go @@ -0,0 +1,2846 @@ +// Inferno utils/5l/span.c +// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/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 arm + +import ( + "fmt" + "log" + "math" + "sort" + + "github.com/google/gops/internal/obj" +) + +type Optab struct { + as obj.As + a1 uint8 + a2 int8 + a3 uint8 + type_ uint8 + size int8 + param int16 + flag int8 + pcrelsiz uint8 +} + +type Opcross [32][2][32]uint8 + +const ( + LFROM = 1 << 0 + LTO = 1 << 1 + LPOOL = 1 << 2 + LPCREL = 1 << 3 +) + +var optab = []Optab{ + /* struct Optab: + OPCODE, from, prog->reg, to, type,size,param,flag */ + {obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0}, + {AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0}, + {AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AMVN, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0}, + {AADD, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0}, + {AADD, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0}, + {AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0}, + {AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0}, + {ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0, 0, 0}, + {AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0}, + {AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0}, + {AMOVW, C_RACON, C_NONE, C_REG, 4, 4, REGSP, 0, 0}, + {AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL, 0}, + {ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, + {ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0, 0, 0}, + {ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, + {ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // prediction hinted form, hint ignored + + {AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL, 0}, + {ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0, 0, 0}, + {ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0, 0, 0}, + {ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0, 0, 0}, + {ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0, 0, 0}, + {ASLL, C_RCON, C_REG, C_REG, 8, 4, 0, 0, 0}, + {ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0, 0, 0}, + {ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0}, + {ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0}, + {ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0}, + {ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0, 0, 0}, + {ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_TLS_LE, 103, 4, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_TLS_IE, 104, 4, 0, 0, 0}, + {AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0}, + {AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0}, + {AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4}, + {AADD, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0}, + {AADD, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0}, + {AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0}, + {ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0, 0, 0}, + {AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0}, + {AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0}, + {AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0}, + {ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0}, + {AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0}, + {AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0}, + {AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0}, + {AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0}, + {ADIV, C_REG, C_REG, C_REG, 16, 4, 0, 0, 0}, + {ADIV, C_REG, C_NONE, C_REG, 16, 4, 0, 0, 0}, + {AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0}, + {AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0}, + {AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0}, + {AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0}, + {AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0}, + {AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0}, + {AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0}, + {AMOVW, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVW, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVBU, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVBU, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + {AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4}, + {AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + {AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4}, + {AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + {AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4}, + {AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + {AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4}, + {AMOVW, C_TLS_LE, C_NONE, C_REG, 101, 4, 0, LFROM, 0}, + {AMOVW, C_TLS_IE, C_NONE, C_REG, 102, 8, 0, LFROM, 0}, + {AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0}, + {AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0}, + {AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4}, + {AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0}, + {AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0}, + {AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4}, + {AMOVW, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0}, + {AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0, 0, 0}, + {AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0, 0, 0}, + {AMOVM, C_REGLIST, C_NONE, C_SOREG, 38, 4, 0, 0, 0}, + {AMOVM, C_SOREG, C_NONE, C_REGLIST, 39, 4, 0, 0, 0}, + {ASWPW, C_SOREG, C_REG, C_REG, 40, 4, 0, 0, 0}, + {ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0}, + {AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP, 0, 0}, + {AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0, 0, 0}, + {AMOVF, C_FAUTO, C_NONE, C_FREG, 51, 4, REGSP, 0, 0}, + {AMOVF, C_FOREG, C_NONE, C_FREG, 51, 4, 0, 0, 0}, + {AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO, 0}, + {AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO, 0}, + {AMOVF, C_LAUTO, C_NONE, C_FREG, 53, 12, REGSP, LFROM, 0}, + {AMOVF, C_LOREG, C_NONE, C_FREG, 53, 12, 0, LFROM, 0}, + {AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4}, + {AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4}, + {AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0, 0, 0}, + {AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0, 0, 0}, + {AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0, 0, 0}, + {AMOVW, C_SHIFT, C_NONE, C_REG, 59, 4, 0, 0, 0}, + {AMOVBU, C_SHIFT, C_NONE, C_REG, 59, 4, 0, 0, 0}, + {AMOVB, C_SHIFT, C_NONE, C_REG, 60, 4, 0, 0, 0}, + {AMOVBS, C_SHIFT, C_NONE, C_REG, 60, 4, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0}, + {AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0}, + {AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0}, + {AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0}, + {AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0}, + {AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0}, + {AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0}, + {AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0}, + {AMOVB, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0}, + {AMOVB, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0}, + {AMOVBS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0}, + {AMOVBS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0}, + {AMOVH, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0}, + {AMOVH, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0}, + {AMOVHS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0}, + {AMOVHS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0}, + {AMOVHU, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0}, + {AMOVHU, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0}, + {AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0}, + {AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4}, + {AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0}, + {AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0}, + {AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4}, + {AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0}, + {AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0}, + {AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4}, + {AMOVB, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0}, + {AMOVB, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0}, + {AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4}, + {AMOVBS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0}, + {AMOVBS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0}, + {AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4}, + {AMOVH, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0}, + {AMOVH, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0}, + {AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4}, + {AMOVHS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0}, + {AMOVHS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0}, + {AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4}, + {AMOVHU, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0}, + {AMOVHU, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0}, + {AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4}, + {ALDREX, C_SOREG, C_NONE, C_REG, 77, 4, 0, 0, 0}, + {ASTREX, C_SOREG, C_REG, C_REG, 78, 4, 0, 0, 0}, + {AMOVF, C_ZFCON, C_NONE, C_FREG, 80, 8, 0, 0, 0}, + {AMOVF, C_SFCON, C_NONE, C_FREG, 81, 4, 0, 0, 0}, + {ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0, 0, 0}, + {ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0, 0, 0}, + {AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0, 0, 0}, + {AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0, 0, 0}, + {AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0, 0, 0}, + {AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0, 0, 0}, + {AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0, 0, 0}, + {ATST, C_REG, C_NONE, C_NONE, 90, 4, 0, 0, 0}, + {ALDREXD, C_SOREG, C_NONE, C_REG, 91, 4, 0, 0, 0}, + {ASTREXD, C_SOREG, C_REG, C_REG, 92, 4, 0, 0, 0}, + {APLD, C_SOREG, C_NONE, C_NONE, 95, 4, 0, 0, 0}, + {obj.AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0, 0, 0}, + {ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0}, + {AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0}, + {AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0}, + {obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0, 0}, + {obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0}, + {obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0}, + {obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, + {obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as ABL + {obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as ABL + + {ADATABUNDLE, C_NONE, C_NONE, C_NONE, 100, 4, 0, 0, 0}, + {ADATABUNDLEEND, C_NONE, C_NONE, C_NONE, 100, 0, 0, 0, 0}, + {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0}, +} + +var pool struct { + start uint32 + size uint32 + extra uint32 +} + +var oprange [ALAST & obj.AMask][]Optab + +var xcmp [C_GOK + 1][C_GOK + 1]bool + +var deferreturn *obj.LSym + +// Note about encoding: Prog.scond holds the condition encoding, +// but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0. +// The code that shifts the value << 28 has the responsibility +// for XORing with C_SCOND_XOR too. + +// asmoutnacl assembles the instruction p. It replaces asmout for NaCl. +// It returns the total number of bytes put in out, and it can change +// p->pc if extra padding is necessary. +// In rare cases, asmoutnacl might split p into two instructions. +// origPC is the PC for this Prog (no padding is taken into account). +func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint32) int { + size := int(o.size) + + // instruction specific + switch p.As { + default: + if out != nil { + asmout(ctxt, p, o, out) + } + + case ADATABUNDLE, // align to 16-byte boundary + ADATABUNDLEEND: // zero width instruction, just to align next instruction to 16-byte boundary + p.Pc = (p.Pc + 15) &^ 15 + + if out != nil { + asmout(ctxt, p, o, out) + } + + case obj.AUNDEF, + APLD: + size = 4 + if out != nil { + switch p.As { + case obj.AUNDEF: + out[0] = 0xe7fedef0 // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0) + + case APLD: + out[0] = 0xe1a01001 // (MOVW R1, R1) + } + } + + case AB, ABL: + if p.To.Type != obj.TYPE_MEM { + if out != nil { + asmout(ctxt, p, o, out) + } + } else { + if p.To.Offset != 0 || size != 4 || p.To.Reg > REG_R15 || p.To.Reg < REG_R0 { + ctxt.Diag("unsupported instruction: %v", p) + } + if p.Pc&15 == 12 { + p.Pc += 4 + } + if out != nil { + out[0] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03c0013f | (uint32(p.To.Reg)&15)<<12 | (uint32(p.To.Reg)&15)<<16 // BIC $0xc000000f, Rx + if p.As == AB { + out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff10 | (uint32(p.To.Reg)&15)<<0 // BX Rx + } else { // ABL + out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff30 | (uint32(p.To.Reg)&15)<<0 // BLX Rx + } + } + + size = 8 + } + + // align the last instruction (the actual BL) to the last instruction in a bundle + if p.As == ABL { + if deferreturn == nil { + deferreturn = obj.Linklookup(ctxt, "runtime.deferreturn", 0) + } + if p.To.Sym == deferreturn { + p.Pc = ((int64(origPC) + 15) &^ 15) + 16 - int64(size) + } else { + p.Pc += (16 - ((p.Pc + int64(size)) & 15)) & 15 + } + } + + case ALDREX, + ALDREXD, + AMOVB, + AMOVBS, + AMOVBU, + AMOVD, + AMOVF, + AMOVH, + AMOVHS, + AMOVHU, + AMOVM, + AMOVW, + ASTREX, + ASTREXD: + if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 && p.From.Reg == REG_R13 { // MOVW.W x(R13), PC + if out != nil { + asmout(ctxt, p, o, out) + } + if size == 4 { + if out != nil { + // Note: 5c and 5g reg.c know that DIV/MOD smashes R12 + // so that this return instruction expansion is valid. + out[0] = out[0] &^ 0x3000 // change PC to R12 + out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03ccc13f // BIC $0xc000000f, R12 + out[2] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff1c // BX R12 + } + + size += 8 + if (p.Pc+int64(size))&15 == 4 { + p.Pc += 4 + } + break + } else { + // if the instruction used more than 4 bytes, then it must have used a very large + // offset to update R13, so we need to additionally mask R13. + if out != nil { + out[size/4-1] &^= 0x3000 // change PC to R12 + out[size/4] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03cdd103 // BIC $0xc0000000, R13 + out[size/4+1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03ccc13f // BIC $0xc000000f, R12 + out[size/4+2] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff1c // BX R12 + } + + // p->pc+size is only ok at 4 or 12 mod 16. + if (p.Pc+int64(size))%8 == 0 { + p.Pc += 4 + } + size += 12 + break + } + } + + if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 { + ctxt.Diag("unsupported instruction (move to another register and use indirect jump instead): %v", p) + } + + if p.To.Type == obj.TYPE_MEM && p.To.Reg == REG_R13 && (p.Scond&C_WBIT != 0) && size > 4 { + // function prolog with very large frame size: MOVW.W R14,-100004(R13) + // split it into two instructions: + // ADD $-100004, R13 + // MOVW R14, 0(R13) + q := ctxt.NewProg() + + p.Scond &^= C_WBIT + *q = *p + a := &p.To + var a2 *obj.Addr + if p.To.Type == obj.TYPE_MEM { + a2 = &q.To + } else { + a2 = &q.From + } + nocache(q) + nocache(p) + + // insert q after p + q.Link = p.Link + + p.Link = q + q.Pcond = nil + + // make p into ADD $X, R13 + p.As = AADD + + p.From = *a + p.From.Reg = 0 + p.From.Type = obj.TYPE_CONST + p.To = obj.Addr{} + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R13 + + // make q into p but load/store from 0(R13) + q.Spadj = 0 + + *a2 = obj.Addr{} + a2.Type = obj.TYPE_MEM + a2.Reg = REG_R13 + a2.Sym = nil + a2.Offset = 0 + size = int(oplook(ctxt, p).size) + break + } + + if (p.To.Type == obj.TYPE_MEM && p.To.Reg != REG_R9) || // MOVW Rx, X(Ry), y != 9 + (p.From.Type == obj.TYPE_MEM && p.From.Reg != REG_R9) { // MOVW X(Rx), Ry, x != 9 + var a *obj.Addr + if p.To.Type == obj.TYPE_MEM { + a = &p.To + } else { + a = &p.From + } + reg := int(a.Reg) + if size == 4 { + // if addr.reg == 0, then it is probably load from x(FP) with small x, no need to modify. + if reg == 0 { + if out != nil { + asmout(ctxt, p, o, out) + } + } else { + if out != nil { + out[0] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03c00103 | (uint32(reg)&15)<<16 | (uint32(reg)&15)<<12 // BIC $0xc0000000, Rx + } + if p.Pc&15 == 12 { + p.Pc += 4 + } + size += 4 + if out != nil { + asmout(ctxt, p, o, out[1:]) + } + } + + break + } else { + // if a load/store instruction takes more than 1 word to implement, then + // we need to separate the instruction into two: + // 1. explicitly load the address into R11. + // 2. load/store from R11. + // This won't handle .W/.P, so we should reject such code. + if p.Scond&(C_PBIT|C_WBIT) != 0 { + ctxt.Diag("unsupported instruction (.P/.W): %v", p) + } + q := ctxt.NewProg() + *q = *p + var a2 *obj.Addr + if p.To.Type == obj.TYPE_MEM { + a2 = &q.To + } else { + a2 = &q.From + } + nocache(q) + nocache(p) + + // insert q after p + q.Link = p.Link + + p.Link = q + q.Pcond = nil + + // make p into MOVW $X(R), R11 + p.As = AMOVW + + p.From = *a + p.From.Type = obj.TYPE_ADDR + p.To = obj.Addr{} + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R11 + + // make q into p but load/store from 0(R11) + *a2 = obj.Addr{} + + a2.Type = obj.TYPE_MEM + a2.Reg = REG_R11 + a2.Sym = nil + a2.Offset = 0 + size = int(oplook(ctxt, p).size) + break + } + } else if out != nil { + asmout(ctxt, p, o, out) + } + } + + // destination register specific + if p.To.Type == obj.TYPE_REG { + switch p.To.Reg { + case REG_R9: + ctxt.Diag("invalid instruction, cannot write to R9: %v", p) + + case REG_R13: + if out != nil { + out[size/4] = 0xe3cdd103 // BIC $0xc0000000, R13 + } + if (p.Pc+int64(size))&15 == 0 { + p.Pc += 4 + } + size += 4 + } + } + + return size +} + +func span5(ctxt *obj.Link, cursym *obj.LSym) { + var p *obj.Prog + var op *obj.Prog + + p = cursym.Text + if p == nil || p.Link == nil { // handle external functions and ELF section symbols + return + } + + if oprange[AAND&obj.AMask] == nil { + buildop(ctxt) + } + + ctxt.Cursym = cursym + + ctxt.Autosize = int32(p.To.Offset + 4) + c := int32(0) + + op = p + p = p.Link + var i int + var m int + var o *Optab + for ; p != nil || ctxt.Blitrl != nil; op, p = p, p.Link { + if p == nil { + if checkpool(ctxt, op, 0) { + p = op + continue + } + + // can't happen: blitrl is not nil, but checkpool didn't flushpool + ctxt.Diag("internal inconsistency") + + break + } + + ctxt.Curp = p + p.Pc = int64(c) + o = oplook(ctxt, p) + if ctxt.Headtype != obj.Hnacl { + m = int(o.size) + } else { + m = asmoutnacl(ctxt, c, p, o, nil) + c = int32(p.Pc) // asmoutnacl might change pc for alignment + o = oplook(ctxt, p) // asmoutnacl might change p in rare cases + } + + if m%4 != 0 || p.Pc%4 != 0 { + ctxt.Diag("!pc invalid: %v size=%d", p, m) + } + + // must check literal pool here in case p generates many instructions + if ctxt.Blitrl != nil { + i = m + if checkpool(ctxt, op, i) { + p = op + continue + } + } + + if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) { + ctxt.Diag("zero-width instruction\n%v", p) + continue + } + + switch o.flag & (LFROM | LTO | LPOOL) { + case LFROM: + addpool(ctxt, p, &p.From) + + case LTO: + addpool(ctxt, p, &p.To) + + case LPOOL: + if p.Scond&C_SCOND == C_SCOND_NONE { + flushpool(ctxt, p, 0, 0) + } + } + + if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE { + flushpool(ctxt, p, 0, 0) + } + c += int32(m) + } + + cursym.Size = int64(c) + + /* + * if any procedure is large enough to + * generate a large SBRA branch, then + * generate extra passes putting branches + * around jmps to fix. this is rare. + */ + times := 0 + + var bflag int + var opc int32 + var out [6 + 3]uint32 + for { + if ctxt.Debugvlog != 0 { + ctxt.Logf("%5.2f span1\n", obj.Cputime()) + } + bflag = 0 + c = 0 + times++ + cursym.Text.Pc = 0 // force re-layout the code. + for p = cursym.Text; p != nil; p = p.Link { + ctxt.Curp = p + o = oplook(ctxt, p) + if int64(c) > p.Pc { + p.Pc = int64(c) + } + + /* very large branches + if(o->type == 6 && p->pcond) { + otxt = p->pcond->pc - c; + if(otxt < 0) + otxt = -otxt; + if(otxt >= (1L<<17) - 10) { + q = emallocz(sizeof(Prog)); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = TYPE_BRANCH; + q->pcond = p->pcond; + p->pcond = q; + q = emallocz(sizeof(Prog)); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = TYPE_BRANCH; + q->pcond = q->link->link; + bflag = 1; + } + } + */ + opc = int32(p.Pc) + + if ctxt.Headtype != obj.Hnacl { + m = int(o.size) + } else { + m = asmoutnacl(ctxt, c, p, o, nil) + } + if p.Pc != int64(opc) { + bflag = 1 + } + + //print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times); + c = int32(p.Pc + int64(m)) + + if m%4 != 0 || p.Pc%4 != 0 { + ctxt.Diag("pc invalid: %v size=%d", p, m) + } + + if m/4 > len(out) { + ctxt.Diag("instruction size too large: %d > %d", m/4, len(out)) + } + if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) { + if p.As == obj.ATEXT { + ctxt.Autosize = int32(p.To.Offset + 4) + continue + } + + ctxt.Diag("zero-width instruction\n%v", p) + continue + } + } + + cursym.Size = int64(c) + if bflag == 0 { + break + } + } + + if c%4 != 0 { + ctxt.Diag("sym->size=%d, invalid", c) + } + + /* + * lay out the code. all the pc-relative code references, + * even cross-function, are resolved now; + * only data references need to be relocated. + * with more work we could leave cross-function + * code references to be relocated too, and then + * perhaps we'd be able to parallelize the span loop above. + */ + + p = cursym.Text + ctxt.Autosize = int32(p.To.Offset + 4) + cursym.Grow(cursym.Size) + + bp := cursym.P + c = int32(p.Pc) // even p->link might need extra padding + var v int + for p = p.Link; p != nil; p = p.Link { + ctxt.Pc = p.Pc + ctxt.Curp = p + o = oplook(ctxt, p) + opc = int32(p.Pc) + if ctxt.Headtype != obj.Hnacl { + asmout(ctxt, p, o, out[:]) + m = int(o.size) + } else { + m = asmoutnacl(ctxt, c, p, o, out[:]) + if int64(opc) != p.Pc { + ctxt.Diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %v", opc, int32(p.Pc), p) + } + } + + if m%4 != 0 || p.Pc%4 != 0 { + ctxt.Diag("final stage: pc invalid: %v size=%d", p, m) + } + + if int64(c) > p.Pc { + ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, c, p) + } + for int64(c) != p.Pc { + // emit 0xe1a00000 (MOVW R0, R0) + bp[0] = 0x00 + bp = bp[1:] + + bp[0] = 0x00 + bp = bp[1:] + bp[0] = 0xa0 + bp = bp[1:] + bp[0] = 0xe1 + bp = bp[1:] + c += 4 + } + + for i = 0; i < m/4; i++ { + v = int(out[i]) + bp[0] = byte(v) + bp = bp[1:] + bp[0] = byte(v >> 8) + bp = bp[1:] + bp[0] = byte(v >> 16) + bp = bp[1:] + bp[0] = byte(v >> 24) + bp = bp[1:] + } + + c += int32(m) + } +} + +/* + * when the first reference to the literal pool threatens + * to go out of range of a 12-bit PC-relative offset, + * drop the pool now, and branch round it. + * this happens only in extended basic blocks that exceed 4k. + */ +func checkpool(ctxt *obj.Link, p *obj.Prog, sz int) bool { + if pool.size >= 0xff0 || immaddr(int32((p.Pc+int64(sz)+4)+4+int64(12+pool.size)-int64(pool.start+8))) == 0 { + return flushpool(ctxt, p, 1, 0) + } else if p.Link == nil { + return flushpool(ctxt, p, 2, 0) + } + return false +} + +func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool { + if ctxt.Blitrl != nil { + if skip != 0 { + if false && skip == 1 { + fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start) + } + q := ctxt.NewProg() + q.As = AB + q.To.Type = obj.TYPE_BRANCH + q.Pcond = p.Link + q.Link = ctxt.Blitrl + q.Lineno = p.Lineno + ctxt.Blitrl = q + } else if force == 0 && (p.Pc+int64(12+pool.size)-int64(pool.start) < 2048) { // 12 take into account the maximum nacl literal pool alignment padding size + return false + } + if ctxt.Headtype == obj.Hnacl && pool.size%16 != 0 { + // if pool is not multiple of 16 bytes, add an alignment marker + q := ctxt.NewProg() + + q.As = ADATABUNDLEEND + ctxt.Elitrl.Link = q + ctxt.Elitrl = q + } + + // The line number for constant pool entries doesn't really matter. + // We set it to the line number of the preceding instruction so that + // there are no deltas to encode in the pc-line tables. + for q := ctxt.Blitrl; q != nil; q = q.Link { + q.Lineno = p.Lineno + } + + ctxt.Elitrl.Link = p.Link + p.Link = ctxt.Blitrl + + ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */ + ctxt.Elitrl = nil + pool.size = 0 + pool.start = 0 + pool.extra = 0 + return true + } + + return false +} + +func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { + var t obj.Prog + + c := aclass(ctxt, a) + + t.Ctxt = ctxt + t.As = AWORD + + switch c { + default: + t.To.Offset = a.Offset + t.To.Sym = a.Sym + t.To.Type = a.Type + t.To.Name = a.Name + + if ctxt.Flag_shared && t.To.Sym != nil { + t.Rel = p + } + + case C_SROREG, + C_LOREG, + C_ROREG, + C_FOREG, + C_SOREG, + C_HOREG, + C_FAUTO, + C_SAUTO, + C_LAUTO, + C_LACON: + t.To.Type = obj.TYPE_CONST + t.To.Offset = ctxt.Instoffset + } + + if t.Rel == nil { + for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */ + if q.Rel == nil && q.To == t.To { + p.Pcond = q + return + } + } + } + + if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 { + // start a new data bundle + q := ctxt.NewProg() + q.As = ADATABUNDLE + q.Pc = int64(pool.size) + pool.size += 4 + if ctxt.Blitrl == nil { + ctxt.Blitrl = q + pool.start = uint32(p.Pc) + } else { + ctxt.Elitrl.Link = q + } + + ctxt.Elitrl = q + } + + q := ctxt.NewProg() + *q = t + q.Pc = int64(pool.size) + + if ctxt.Blitrl == nil { + ctxt.Blitrl = q + pool.start = uint32(p.Pc) + } else { + ctxt.Elitrl.Link = q + } + ctxt.Elitrl = q + pool.size += 4 + + p.Pcond = q +} + +func regoff(ctxt *obj.Link, a *obj.Addr) int32 { + ctxt.Instoffset = 0 + aclass(ctxt, a) + return int32(ctxt.Instoffset) +} + +func immrot(v uint32) int32 { + for i := 0; i < 16; i++ { + if v&^0xff == 0 { + return int32(uint32(int32(i)<<8) | v | 1<<25) + } + v = v<<2 | v>>30 + } + + return 0 +} + +func immaddr(v int32) int32 { + if v >= 0 && v <= 0xfff { + return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */ + } + if v >= -0xfff && v < 0 { + return -v&0xfff | 1<<24 /* pre indexing */ + } + return 0 +} + +func immfloat(v int32) bool { + return v&0xC03 == 0 /* offset will fit in floating-point load/store */ +} + +func immhalf(v int32) bool { + if v >= 0 && v <= 0xff { + return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */ + } + if v >= -0xff && v < 0 { + return -v&0xff|1<<24 != 0 /* pre indexing */ + } + return false +} + +func aclass(ctxt *obj.Link, a *obj.Addr) int { + switch a.Type { + case obj.TYPE_NONE: + return C_NONE + + case obj.TYPE_REG: + ctxt.Instoffset = 0 + if REG_R0 <= a.Reg && a.Reg <= REG_R15 { + return C_REG + } + if REG_F0 <= a.Reg && a.Reg <= REG_F15 { + return C_FREG + } + if a.Reg == REG_FPSR || a.Reg == REG_FPCR { + return C_FCR + } + if a.Reg == REG_CPSR || a.Reg == REG_SPSR { + return C_PSR + } + return C_GOK + + case obj.TYPE_REGREG: + return C_REGREG + + case obj.TYPE_REGREG2: + return C_REGREG2 + + case obj.TYPE_REGLIST: + return C_REGLIST + + case obj.TYPE_SHIFT: + return C_SHIFT + + case obj.TYPE_MEM: + switch a.Name { + case obj.NAME_EXTERN, + obj.NAME_GOTREF, + obj.NAME_STATIC: + if a.Sym == nil || a.Sym.Name == "" { + fmt.Printf("null sym external\n") + return C_GOK + } + + ctxt.Instoffset = 0 // s.b. unused but just in case + if a.Sym.Type == obj.STLSBSS { + if ctxt.Flag_shared { + return C_TLS_IE + } else { + return C_TLS_LE + } + } + + return C_ADDR + + case obj.NAME_AUTO: + ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + if t := immaddr(int32(ctxt.Instoffset)); t != 0 { + if immhalf(int32(ctxt.Instoffset)) { + if immfloat(t) { + return C_HFAUTO + } + return C_HAUTO + } + + if immfloat(t) { + return C_FAUTO + } + return C_SAUTO + } + + return C_LAUTO + + case obj.NAME_PARAM: + ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4 + if t := immaddr(int32(ctxt.Instoffset)); t != 0 { + if immhalf(int32(ctxt.Instoffset)) { + if immfloat(t) { + return C_HFAUTO + } + return C_HAUTO + } + + if immfloat(t) { + return C_FAUTO + } + return C_SAUTO + } + + return C_LAUTO + + case obj.NAME_NONE: + ctxt.Instoffset = a.Offset + if t := immaddr(int32(ctxt.Instoffset)); t != 0 { + if immhalf(int32(ctxt.Instoffset)) { /* n.b. that it will also satisfy immrot */ + if immfloat(t) { + return C_HFOREG + } + return C_HOREG + } + + if immfloat(t) { + return C_FOREG /* n.b. that it will also satisfy immrot */ + } + if immrot(uint32(ctxt.Instoffset)) != 0 { + return C_SROREG + } + if immhalf(int32(ctxt.Instoffset)) { + return C_HOREG + } + return C_SOREG + } + + if immrot(uint32(ctxt.Instoffset)) != 0 { + return C_ROREG + } + return C_LOREG + } + + return C_GOK + + case obj.TYPE_FCONST: + if chipzero5(ctxt, a.Val.(float64)) >= 0 { + return C_ZFCON + } + if chipfloat5(ctxt, a.Val.(float64)) >= 0 { + return C_SFCON + } + return C_LFCON + + case obj.TYPE_TEXTSIZE: + return C_TEXTSIZE + + case obj.TYPE_CONST, + obj.TYPE_ADDR: + switch a.Name { + case obj.NAME_NONE: + ctxt.Instoffset = a.Offset + if a.Reg != 0 { + return aconsize(ctxt) + } + + if immrot(uint32(ctxt.Instoffset)) != 0 { + return C_RCON + } + if immrot(^uint32(ctxt.Instoffset)) != 0 { + return C_NCON + } + return C_LCON + + case obj.NAME_EXTERN, + obj.NAME_GOTREF, + obj.NAME_STATIC: + s := a.Sym + if s == nil { + break + } + ctxt.Instoffset = 0 // s.b. unused but just in case + return C_LCONADDR + + case obj.NAME_AUTO: + ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + return aconsize(ctxt) + + case obj.NAME_PARAM: + ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4 + return aconsize(ctxt) + } + + return C_GOK + + case obj.TYPE_BRANCH: + return C_SBRA + } + + return C_GOK +} + +func aconsize(ctxt *obj.Link) int { + if immrot(uint32(ctxt.Instoffset)) != 0 { + return C_RACON + } + if immrot(uint32(-ctxt.Instoffset)) != 0 { + return C_RACON + } + return C_LACON +} + +func prasm(p *obj.Prog) { + fmt.Printf("%v\n", p) +} + +func oplook(ctxt *obj.Link, p *obj.Prog) *Optab { + a1 := int(p.Optab) + if a1 != 0 { + return &optab[a1-1] + } + a1 = int(p.From.Class) + if a1 == 0 { + a1 = aclass(ctxt, &p.From) + 1 + p.From.Class = int8(a1) + } + + a1-- + a3 := int(p.To.Class) + if a3 == 0 { + a3 = aclass(ctxt, &p.To) + 1 + p.To.Class = int8(a3) + } + + a3-- + a2 := C_NONE + if p.Reg != 0 { + a2 = C_REG + } + + if false { /*debug['O']*/ + fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3)) + fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type) + } + + ops := oprange[p.As&obj.AMask] + c1 := &xcmp[a1] + c3 := &xcmp[a3] + for i := range ops { + op := &ops[i] + if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] { + p.Optab = uint16(cap(optab) - cap(ops) + i + 1) + return op + } + } + + ctxt.Diag("illegal combination %v; %v %v %v, %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.To.Type) + ctxt.Diag("from %d %d to %d %d\n", p.From.Type, p.From.Name, p.To.Type, p.To.Name) + prasm(p) + if ops == nil { + ops = optab + } + return &ops[0] +} + +func cmp(a int, b int) bool { + if a == b { + return true + } + switch a { + case C_LCON: + if b == C_RCON || b == C_NCON { + return true + } + + case C_LACON: + if b == C_RACON { + return true + } + + case C_LFCON: + if b == C_ZFCON || b == C_SFCON { + return true + } + + case C_HFAUTO: + return b == C_HAUTO || b == C_FAUTO + + case C_FAUTO, C_HAUTO: + return b == C_HFAUTO + + case C_SAUTO: + return cmp(C_HFAUTO, b) + + case C_LAUTO: + return cmp(C_SAUTO, b) + + case C_HFOREG: + return b == C_HOREG || b == C_FOREG + + case C_FOREG, C_HOREG: + return b == C_HFOREG + + case C_SROREG: + return cmp(C_SOREG, b) || cmp(C_ROREG, b) + + case C_SOREG, C_ROREG: + return b == C_SROREG || cmp(C_HFOREG, b) + + case C_LOREG: + return cmp(C_SROREG, b) + + case C_LBRA: + if b == C_SBRA { + return true + } + + case C_HREG: + return cmp(C_SP, b) || cmp(C_PC, b) + } + + return false +} + +type ocmp []Optab + +func (x ocmp) Len() int { + return len(x) +} + +func (x ocmp) Swap(i, j int) { + x[i], x[j] = x[j], x[i] +} + +func (x ocmp) Less(i, j int) bool { + p1 := &x[i] + p2 := &x[j] + n := int(p1.as) - int(p2.as) + if n != 0 { + return n < 0 + } + n = int(p1.a1) - int(p2.a1) + if n != 0 { + return n < 0 + } + n = int(p1.a2) - int(p2.a2) + if n != 0 { + return n < 0 + } + n = int(p1.a3) - int(p2.a3) + if n != 0 { + return n < 0 + } + return false +} + +func opset(a, b0 obj.As) { + oprange[a&obj.AMask] = oprange[b0] +} + +func buildop(ctxt *obj.Link) { + var n int + + for i := 0; i < C_GOK; i++ { + for n = 0; n < C_GOK; n++ { + if cmp(n, i) { + xcmp[i][n] = true + } + } + } + for n = 0; optab[n].as != obj.AXXX; n++ { + if optab[n].flag&LPCREL != 0 { + if ctxt.Flag_shared { + optab[n].size += int8(optab[n].pcrelsiz) + } else { + optab[n].flag &^= LPCREL + } + } + } + + sort.Sort(ocmp(optab[:n])) + for i := 0; i < n; i++ { + r := optab[i].as + r0 := r & obj.AMask + start := i + for optab[i].as == r { + i++ + } + oprange[r0] = optab[start:i] + i-- + + switch r { + default: + ctxt.Diag("unknown op in build: %v", r) + log.Fatalf("bad code") + + case AADD: + opset(AAND, r0) + opset(AEOR, r0) + opset(ASUB, r0) + opset(ARSB, r0) + opset(AADC, r0) + opset(ASBC, r0) + opset(ARSC, r0) + opset(AORR, r0) + opset(ABIC, r0) + + case ACMP: + opset(ATEQ, r0) + opset(ACMN, r0) + + case AMVN: + break + + case ABEQ: + opset(ABNE, r0) + opset(ABCS, r0) + opset(ABHS, r0) + opset(ABCC, r0) + opset(ABLO, r0) + opset(ABMI, r0) + opset(ABPL, r0) + opset(ABVS, r0) + opset(ABVC, r0) + opset(ABHI, r0) + opset(ABLS, r0) + opset(ABGE, r0) + opset(ABLT, r0) + opset(ABGT, r0) + opset(ABLE, r0) + + case ASLL: + opset(ASRL, r0) + opset(ASRA, r0) + + case AMUL: + opset(AMULU, r0) + + case ADIV: + opset(AMOD, r0) + opset(AMODU, r0) + opset(ADIVU, r0) + + case AMOVW, + AMOVB, + AMOVBS, + AMOVBU, + AMOVH, + AMOVHS, + AMOVHU: + break + + case ASWPW: + opset(ASWPBU, r0) + + case AB, + ABL, + ABX, + ABXRET, + obj.ADUFFZERO, + obj.ADUFFCOPY, + ASWI, + AWORD, + AMOVM, + ARFE, + obj.ATEXT, + obj.AUSEFIELD, + obj.ATYPE: + break + + case AADDF: + opset(AADDD, r0) + opset(ASUBF, r0) + opset(ASUBD, r0) + opset(AMULF, r0) + opset(AMULD, r0) + opset(ADIVF, r0) + opset(ADIVD, r0) + opset(ASQRTF, r0) + opset(ASQRTD, r0) + opset(AMOVFD, r0) + opset(AMOVDF, r0) + opset(AABSF, r0) + opset(AABSD, r0) + opset(ANEGF, r0) + opset(ANEGD, r0) + + case ACMPF: + opset(ACMPD, r0) + + case AMOVF: + opset(AMOVD, r0) + + case AMOVFW: + opset(AMOVDW, r0) + + case AMOVWF: + opset(AMOVWD, r0) + + case AMULL: + opset(AMULAL, r0) + opset(AMULLU, r0) + opset(AMULALU, r0) + + case AMULWT: + opset(AMULWB, r0) + + case AMULAWT: + opset(AMULAWB, r0) + + case AMULA, + ALDREX, + ASTREX, + ALDREXD, + ASTREXD, + ATST, + APLD, + obj.AUNDEF, + ACLZ, + obj.AFUNCDATA, + obj.APCDATA, + obj.ANOP, + ADATABUNDLE, + ADATABUNDLEEND: + break + } + } +} + +func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { + ctxt.Printp = p + o1 := uint32(0) + o2 := uint32(0) + o3 := uint32(0) + o4 := uint32(0) + o5 := uint32(0) + o6 := uint32(0) + ctxt.Armsize += int32(o.size) + if false { /*debug['P']*/ + fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_) + } + switch o.type_ { + default: + ctxt.Diag("unknown asm %d", o.type_) + prasm(p) + + case 0: /* pseudo ops */ + if false { /*debug['G']*/ + fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name) + } + + case 1: /* op R,[R],R */ + o1 = oprrr(ctxt, p.As, int(p.Scond)) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = 0 + } + if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN { + r = 0 + } else if r == 0 { + r = rt + } + o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 + + case 2: /* movbu $I,[R],R */ + aclass(ctxt, &p.From) + + o1 = oprrr(ctxt, p.As, int(p.Scond)) + o1 |= uint32(immrot(uint32(ctxt.Instoffset))) + rt := int(p.To.Reg) + r := int(p.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = 0 + } + if p.As == AMOVW || p.As == AMVN { + r = 0 + } else if r == 0 { + r = rt + } + o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 + + case 3: /* add R<<[IR],[R],R */ + o1 = mov(ctxt, p) + + case 4: /* MOVW $off(R), R -> add $off,[R],R */ + aclass(ctxt, &p.From) + if ctxt.Instoffset < 0 { + o1 = oprrr(ctxt, ASUB, int(p.Scond)) + o1 |= uint32(immrot(uint32(-ctxt.Instoffset))) + } else { + o1 = oprrr(ctxt, AADD, int(p.Scond)) + o1 |= uint32(immrot(uint32(ctxt.Instoffset))) + } + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o1 |= (uint32(r) & 15) << 16 + o1 |= (uint32(p.To.Reg) & 15) << 12 + + case 5: /* bra s */ + o1 = opbra(ctxt, p, p.As, int(p.Scond)) + + v := int32(-8) + if p.To.Sym != nil { + rel := obj.Addrel(ctxt.Cursym) + rel.Off = int32(ctxt.Pc) + rel.Siz = 4 + rel.Sym = p.To.Sym + v += int32(p.To.Offset) + rel.Add = int64(o1) | (int64(v)>>2)&0xffffff + rel.Type = obj.R_CALLARM + break + } + + if p.Pcond != nil { + v = int32((p.Pcond.Pc - ctxt.Pc) - 8) + } + o1 |= (uint32(v) >> 2) & 0xffffff + + case 6: /* b ,O(R) -> add $O,R,PC */ + aclass(ctxt, &p.To) + + o1 = oprrr(ctxt, AADD, int(p.Scond)) + o1 |= uint32(immrot(uint32(ctxt.Instoffset))) + o1 |= (uint32(p.To.Reg) & 15) << 16 + o1 |= (REGPC & 15) << 12 + + case 7: /* bl (R) -> blx R */ + aclass(ctxt, &p.To) + + if ctxt.Instoffset != 0 { + ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, ctxt.Instoffset) + } + o1 = oprrr(ctxt, ABL, int(p.Scond)) + o1 |= (uint32(p.To.Reg) & 15) << 0 + rel := obj.Addrel(ctxt.Cursym) + rel.Off = int32(ctxt.Pc) + rel.Siz = 0 + rel.Type = obj.R_CALLIND + + case 8: /* sll $c,[R],R -> mov (R<<$c),R */ + aclass(ctxt, &p.From) + + o1 = oprrr(ctxt, p.As, int(p.Scond)) + r := int(p.Reg) + if r == 0 { + r = int(p.To.Reg) + } + o1 |= (uint32(r) & 15) << 0 + o1 |= uint32((ctxt.Instoffset & 31) << 7) + o1 |= (uint32(p.To.Reg) & 15) << 12 + + case 9: /* sll R,[R],R -> mov (R< lr */ + aclass(ctxt, &p.From) + + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o1 = olr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond)) + if p.As != AMOVW { + o1 |= 1 << 22 + } + + case 30: /* mov/movb/movbu R,L(R) */ + o1 = omvl(ctxt, p, &p.To, REGTMP) + + if o1 == 0 { + break + } + r := int(p.To.Reg) + if r == 0 { + r = int(o.param) + } + o2 = osrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond)) + if p.As != AMOVW { + o2 |= 1 << 22 + } + + case 31: /* mov/movbu L(R),R -> lr[b] */ + o1 = omvl(ctxt, p, &p.From, REGTMP) + + if o1 == 0 { + break + } + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o2 = olrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond)) + if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { + o2 |= 1 << 22 + } + + case 34: /* mov $lacon,R */ + o1 = omvl(ctxt, p, &p.From, REGTMP) + + if o1 == 0 { + break + } + + o2 = oprrr(ctxt, AADD, int(p.Scond)) + o2 |= REGTMP & 15 + r := int(p.From.Reg) + if r == 0 { + r = int(o.