diff options
Diffstat (limited to 'bfd/libhppa.h')
-rw-r--r-- | bfd/libhppa.h | 700 |
1 files changed, 700 insertions, 0 deletions
diff --git a/bfd/libhppa.h b/bfd/libhppa.h new file mode 100644 index 0000000..35b40ef --- /dev/null +++ b/bfd/libhppa.h @@ -0,0 +1,700 @@ +/* HP PA-RISC SOM object file format: definitions internal to BFD. + Copyright (C) 1990, 91, 92, 93, 94 , 95, 1996 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _HPPA_H +#define _HPPA_H + +#define BYTES_IN_WORD 4 +#define PA_PAGESIZE 0x1000 + +#ifndef INLINE +#ifdef __GNUC__ +#define INLINE inline +#else +#define INLINE +#endif /* GNU C? */ +#endif /* INLINE */ + +#if __GNUC__ >= 2 && __GNUC_MINOR__ >= 7 +/* Declare the functions with the unused attribute to avoid warnings. */ +static INLINE unsigned int assemble_3 (unsigned int) + __attribute__ ((__unused__)); +static INLINE void dis_assemble_3 (unsigned int, unsigned int *) + __attribute__ ((__unused__)); +static INLINE unsigned int assemble_12 (unsigned int, unsigned int) + __attribute__ ((__unused__)); +static INLINE void dis_assemble_12 (unsigned int, unsigned int *, + unsigned int *) + __attribute__ ((__unused__)); +static INLINE unsigned long assemble_17 (unsigned int, unsigned int, + unsigned int) + __attribute__ ((__unused__)); +static INLINE void dis_assemble_17 (unsigned int, unsigned int *, + unsigned int *, unsigned int *) + __attribute__ ((__unused__)); +static INLINE unsigned long assemble_21 (unsigned int) + __attribute ((__unused__)); +static INLINE void dis_assemble_21 (unsigned int, unsigned int *) + __attribute__ ((__unused__)); +static INLINE unsigned long sign_extend (unsigned int, unsigned int) + __attribute__ ((__unused__)); +static INLINE unsigned int ones (int) __attribute ((__unused__)); +static INLINE void sign_unext (unsigned int, unsigned int, unsigned int *) + __attribute__ ((__unused__)); +static INLINE unsigned long low_sign_extend (unsigned int, unsigned int) + __attribute__ ((__unused__)); +static INLINE void low_sign_unext (unsigned int, unsigned int, unsigned int *) + __attribute__ ((__unused__)); +static INLINE unsigned long hppa_field_adjust (unsigned long, unsigned long, + unsigned short) + __attribute__ ((__unused__)); +static INLINE char bfd_hppa_insn2fmt (unsigned long) + __attribute__ ((__unused__)); +static INLINE unsigned long hppa_rebuild_insn (bfd *, unsigned long, + unsigned long, unsigned long) + __attribute__ ((__unused__)); +#endif /* gcc 2.7 or higher */ + + +/* The PA instruction set variants. */ +enum pa_arch {pa10 = 10, pa11 = 11, pa20 = 20}; + +/* HP PA-RISC relocation types */ + +enum hppa_reloc_field_selector_type + { + R_HPPA_FSEL = 0x0, + R_HPPA_LSSEL = 0x1, + R_HPPA_RSSEL = 0x2, + R_HPPA_LSEL = 0x3, + R_HPPA_RSEL = 0x4, + R_HPPA_LDSEL = 0x5, + R_HPPA_RDSEL = 0x6, + R_HPPA_LRSEL = 0x7, + R_HPPA_RRSEL = 0x8, + R_HPPA_NSEL = 0x9, + R_HPPA_NLSEL = 0xa, + R_HPPA_NLRSEL = 0xb, + R_HPPA_PSEL = 0xc, + R_HPPA_LPSEL = 0xd, + R_HPPA_RPSEL = 0xe, + R_HPPA_TSEL = 0xf, + R_HPPA_LTSEL = 0x10, + R_HPPA_RTSEL = 0x11 + }; + +/* /usr/include/reloc.h defines these to constants. We want to use + them in enums, so #undef them before we start using them. We might + be able to fix this another way by simply managing not to include + /usr/include/reloc.h, but currently GDB picks up these defines + somewhere. */ +#undef e_fsel +#undef e_lssel +#undef e_rssel +#undef e_lsel +#undef e_rsel +#undef e_ldsel +#undef e_rdsel +#undef e_lrsel +#undef e_rrsel +#undef e_nsel +#undef e_nlsel +#undef e_nlrsel +#undef e_psel +#undef e_lpsel +#undef e_rpsel +#undef e_tsel +#undef e_ltsel +#undef e_rtsel +#undef e_one +#undef e_two +#undef e_pcrel +#undef e_con +#undef e_plabel +#undef e_abs + +/* for compatibility */ +enum hppa_reloc_field_selector_type_alt + { + e_fsel = R_HPPA_FSEL, + e_lssel = R_HPPA_LSSEL, + e_rssel = R_HPPA_RSSEL, + e_lsel = R_HPPA_LSEL, + e_rsel = R_HPPA_RSEL, + e_ldsel = R_HPPA_LDSEL, + e_rdsel = R_HPPA_RDSEL, + e_lrsel = R_HPPA_LRSEL, + e_rrsel = R_HPPA_RRSEL, + e_nsel = R_HPPA_NSEL, + e_nlsel = R_HPPA_NLSEL, + e_nlrsel = R_HPPA_NLRSEL, + e_psel = R_HPPA_PSEL, + e_lpsel = R_HPPA_LPSEL, + e_rpsel = R_HPPA_RPSEL, + e_tsel = R_HPPA_TSEL, + e_ltsel = R_HPPA_LTSEL, + e_rtsel = R_HPPA_RTSEL + }; + +enum hppa_reloc_expr_type + { + R_HPPA_E_ONE = 0, + R_HPPA_E_TWO = 1, + R_HPPA_E_PCREL = 2, + R_HPPA_E_CON = 3, + R_HPPA_E_PLABEL = 7, + R_HPPA_E_ABS = 18 + }; + +/* for compatibility */ +enum hppa_reloc_expr_type_alt + { + e_one = R_HPPA_E_ONE, + e_two = R_HPPA_E_TWO, + e_pcrel = R_HPPA_E_PCREL, + e_con = R_HPPA_E_CON, + e_plabel = R_HPPA_E_PLABEL, + e_abs = R_HPPA_E_ABS + }; + + +/* Relocations for function calls must be accompanied by parameter + relocation bits. These bits describe exactly where the caller has + placed the function's arguments and where it expects to find a return + value. + + Both ELF and SOM encode this information within the addend field + of the call relocation. (Note this could break very badly if one + was to make a call like bl foo + 0x12345678). + + The high order 10 bits contain parameter relocation information, + the low order 22 bits contain the constant offset. */ + +#define HPPA_R_ARG_RELOC(a) (((a) >> 22) & 0x3FF) +#define HPPA_R_CONSTANT(a) ((((int)(a)) << 10) >> 10) +#define HPPA_R_ADDEND(r,c) (((r) << 22) + ((c) & 0x3FFFFF)) +#define HPPA_WIDE (0) /* PSW W-bit, need to check! FIXME */ + +/* These macros get bit fields using HP's numbering (MSB = 0), + * but note that "MASK" assumes that the LSB bits are what's + * wanted. + */ +#ifndef GET_FIELD +#define GET_FIELD(X, FROM, TO) \ + ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) +#endif +#define GET_BIT( X, WHICH ) \ + GET_FIELD( X, WHICH, WHICH ) + +#define MASK( SIZE ) \ + (~((-1) << SIZE)) + +#define CATENATE( X, XSIZE, Y, YSIZE ) \ + (((X & MASK( XSIZE )) << YSIZE) | (Y & MASK( YSIZE ))) + +#define ELEVEN( X ) \ + CATENATE( GET_BIT( X, 10 ), 1, GET_FIELD( X, 0, 9 ), 10) + +/* Some functions to manipulate PA instructions. */ + +/* NOTE: these use the HP convention that f{1} is the _left_ most + * bit (MSB) of f; they sometimes have to impose an assumption + * about the size of a field; and as far as I can tell, most + * aren't used. + */ + +static INLINE unsigned long +sign_extend (x, len) + unsigned int x, len; +{ + return (int)(x >> (len - 1) ? (-1 << len) | x : x); +} + +static INLINE unsigned int +assemble_3 (x) + unsigned int x; +{ + return (((x & 1) << 2) | ((x & 6) >> 1)) & 7; +} + +static INLINE void +dis_assemble_3 (x, r) + unsigned int x; + unsigned int *r; +{ + *r = (((x & 4) >> 2) | ((x & 3) << 1)) & 7; +} + +static INLINE unsigned int /* PA 2.0 */ +assemble_6 (x, y) + unsigned int x, y; +{ + return (((x & 0x1) << 5) + (32 - (y & 0x1f))); +} + +static INLINE unsigned int +assemble_12 (x, y) + unsigned int x, y; +{ + return CATENATE( CATENATE( y, 1, + GET_BIT( x, 10 ), 1), 2, + GET_FIELD( x, 0, 9 ), 9); +} + +static INLINE void +dis_assemble_12 (as12, x, y) + unsigned int as12; + unsigned int *x, *y; +{ + *y = (as12 & 0x800) >> 11; + *x = ((as12 & 0x3ff) << 1) | ((as12 & 0x400) >> 10); +} + +static INLINE unsigned long /* PA 2.0 */ +assemble_16 (x, y) + unsigned int x, y; +{ + /* Depends on PSW W-bit !*/ + unsigned int temp; + + if( HPPA_WIDE ) { + temp = CATENATE( CATENATE( GET_BIT( y, 13 ), 1, + (GET_BIT( y, 13 )^GET_BIT( x, 0)), 1 ), 2, + CATENATE( (GET_BIT( y, 13 )^GET_BIT( x, 1)), 1, + GET_FIELD( y, 0, 12 ), 13 ), 14 ); + } + else { + temp = CATENATE( CATENATE( GET_BIT( y, 13 ), 1, + GET_BIT( y, 13 ), 1 ), 2, + CATENATE( GET_BIT( y, 13 ), 1, + GET_FIELD( y, 0, 12 ), 13 ), 14 ); + } + + return sign_extend( temp, 16 ); +} + + +static INLINE unsigned long /* PA 2.0 */ +assemble_16a (x, y, z) + unsigned int x, y, z; +{ + /* Depends on PSW W-bit !*/ + unsigned int temp; + + if( HPPA_WIDE ) { + temp = CATENATE( CATENATE( z, 1, + (z^GET_BIT( x, 0 )), 1), 2, + + CATENATE( (z^GET_BIT( x, 1 )), 1, + y, 11), 12); + } + else { + temp = CATENATE( CATENATE( z, 1, + z, 1), 2, + CATENATE( z, 1, + y, 11), 12); + + } + + return sign_extend( (temp << 2), 16 ); +} + +static INLINE unsigned long +assemble_17 (x, y, z) + unsigned int x, y, z; +{ + unsigned long temp; + int q; + + temp = CATENATE( CATENATE( z, q, + x, q), q, + CATENATE( GET_BIT( y, 1 ), 1, + GET_FIELD( y, 0, 9 ), 10), 11); + + return temp; +} + +static INLINE void +dis_assemble_17 (as17, x, y, z) + unsigned int as17; + unsigned int *x, *y, *z; +{ + + *z = (as17 & 0x10000) >> 16; + *x = (as17 & 0x0f800) >> 11; + *y = (((as17 & 0x00400) >> 10) | ((as17 & 0x3ff) << 1)) & 0x7ff; +} + +static INLINE unsigned long +assemble_21 (x) + unsigned int x; +{ + unsigned long temp; + + temp = ((x & 1) << 20) | + ((x & 0xffe) << 8) | + ((x & 0xc000) >> 7) | + ((x & 0x1f0000) >> 14) | + ((x & 0x003000) >> 12); + return temp & 0x1fffff; +} + +static INLINE unsigned long /* PA 2.0 */ +assemble_22 (a,b,c,d) + unsigned int a,b,c,d; +{ + unsigned long temp; + + temp = CATENATE( CATENATE( d, 1, + a, 5 ), 6, + CATENATE( b, 5, + ELEVEN( c ), 11 ), 16 ); + + return sign_extend( temp, 22 ); +} + +static INLINE void +dis_assemble_21 (as21, x) + unsigned int as21, *x; +{ + unsigned long temp; + + + temp = (as21 & 0x100000) >> 20; + temp |= (as21 & 0x0ffe00) >> 8; + temp |= (as21 & 0x000180) << 7; + temp |= (as21 & 0x00007c) << 14; + temp |= (as21 & 0x000003) << 12; + *x = temp; +} + +static INLINE unsigned int +ones (n) + int n; +{ + unsigned int len_ones; + int i; + + i = 0; + len_ones = 0; + while (i < n) + { + len_ones = (len_ones << 1) | 1; + i++; + } + + return len_ones; +} + +static INLINE void +sign_unext (x, len, result) + unsigned int x, len; + unsigned int *result; +{ + unsigned int len_ones; + + len_ones = ones (len); + + *result = x & len_ones; +} + +static INLINE unsigned long +low_sign_extend (x, len) + unsigned int x, len; +{ + return (int)((x & 0x1 ? (-1 << (len - 1)) : 0) | x >> 1); +} + +static INLINE void +low_sign_unext (x, len, result) + unsigned int x, len; + unsigned int *result; +{ + unsigned int temp; + unsigned int sign; + unsigned int rest; + unsigned int one_bit_at_len; + unsigned int len_ones; + + len_ones = ones (len); + one_bit_at_len = 1 << (len - 1); + + sign_unext (x, len, &temp); + sign = temp & one_bit_at_len; + sign >>= (len - 1); + + rest = temp & (len_ones ^ one_bit_at_len); + rest <<= 1; + + *result = rest | sign; +} + +/* Handle field selectors for PA instructions. */ + +static INLINE unsigned long +hppa_field_adjust (value, constant_value, r_field) + unsigned long value; + unsigned long constant_value; + unsigned short r_field; +{ + switch (r_field) + { + case e_fsel: /* F : no change */ + case e_nsel: /* N : no change */ + value += constant_value; + break; + + case e_lssel: /* LS : if (bit 21) then add 0x800 + arithmetic shift right 11 bits */ + value += constant_value; + if (value & 0x00000400) + value += 0x800; + value = (value & 0xfffff800) >> 11; + break; + + case e_rssel: /* RS : Sign extend from bit 21 */ + value += constant_value; + if (value & 0x00000400) + value |= 0xfffff800; + else + value &= 0x7ff; + break; + + case e_lsel: /* L : Arithmetic shift right 11 bits */ + case e_nlsel: /* NL : Arithmetic shift right 11 bits */ + value += constant_value; + value = (value & 0xfffff800) >> 11; + break; + + case e_rsel: /* R : Set bits 0-20 to zero */ + value += constant_value; + value = value & 0x7ff; + break; + + case e_ldsel: /* LD : Add 0x800, arithmetic shift + right 11 bits */ + value += constant_value; + value += 0x800; + value = (value & 0xfffff800) >> 11; + break; + + case e_rdsel: /* RD : Set bits 0-20 to one */ + value += constant_value; + value |= 0xfffff800; + break; + + case e_lrsel: /* LR : L with "rounded" constant */ + case e_nlrsel: /* NLR : NL with "rounded" constant */ + value = value + ((constant_value + 0x1000) & 0xffffe000); + value = (value & 0xfffff800) >> 11; + break; + + case e_rrsel: /* RR : R with "rounded" constant */ + value = value + ((constant_value + 0x1000) & 0xffffe000); + value = (value & 0x7ff) + constant_value - ((constant_value + 0x1000) & 0xffffe000); + break; + + default: + abort (); + } + return value; + +} + +/* PA-RISC OPCODES */ +#define get_opcode(insn) ((insn) & 0xfc000000) >> 26 + +/* FIXME: this list is incomplete. It should also be an enumerated + type rather than #defines. */ + +#define LDO 0x0d +#define LDB 0x10 +#define LDH 0x11 +#define LDW 0x12 +#define LDWM 0x13 +#define STB 0x18 +#define STH 0x19 +#define STW 0x1a +#define STWM 0x1b +#define COMICLR 0x24 +#define SUBI 0x25 +#define SUBIO 0x25 +#define ADDIT 0x2c +#define ADDITO 0x2c +#define ADDI 0x2d +#define ADDIO 0x2d +#define LDIL 0x08 +#define ADDIL 0x0a + +#define MOVB 0x32 +#define MOVIB 0x33 +#define COMBT 0x20 +#define COMBF 0x22 +#define COMIBT 0x21 +#define COMIBF 0x23 +#define ADDBT 0x28 +#define ADDBF 0x2a +#define ADDIBT 0x29 +#define ADDIBF 0x2b +#define BVB 0x30 +#define BB 0x31 + +#define BL 0x3a +#define BLE 0x39 +#define BE 0x38 + + +/* Given a machine instruction, return its format. + + FIXME: opcodes which do not map to a known format + should return an error of some sort. */ + +static INLINE char +bfd_hppa_insn2fmt (insn) + unsigned long insn; +{ + char fmt = -1; + unsigned char op = get_opcode (insn); + + switch (op) + { + case ADDI: + case ADDIT: + case SUBI: + fmt = 11; + break; + case MOVB: + case MOVIB: + case COMBT: + case COMBF: + case COMIBT: + case COMIBF: + case ADDBT: + case ADDBF: + case ADDIBT: + case ADDIBF: + case BVB: + case BB: + fmt = 12; + break; + case LDO: + case LDB: + case LDH: + case LDW: + case LDWM: + case STB: + case STH: + case STW: + case STWM: + fmt = 14; + break; + case BL: + case BE: + case BLE: + fmt = 17; + break; + case LDIL: + case ADDIL: + fmt = 21; + break; + default: + fmt = 32; + break; + } + return fmt; +} + + +/* Insert VALUE into INSN using R_FORMAT to determine exactly what + bits to change. */ + +static INLINE unsigned long +hppa_rebuild_insn (abfd, insn, value, r_format) + bfd *abfd; + unsigned long insn; + unsigned long value; + unsigned long r_format; +{ + unsigned long const_part; + unsigned long rebuilt_part; + + switch (r_format) + { + case 11: + { + unsigned w1, w; + + const_part = insn & 0xffffe002; + dis_assemble_12 (value, &w1, &w); + rebuilt_part = (w1 << 2) | w; + return const_part | rebuilt_part; + } + + case 12: + { + unsigned w1, w; + + const_part = insn & 0xffffe002; + dis_assemble_12 (value, &w1, &w); + rebuilt_part = (w1 << 2) | w; + return const_part | rebuilt_part; + } + + case 14: + { + unsigned int ext; + + const_part = insn & 0xffffc000; + low_sign_unext (value, 14, &ext); + return const_part | ext; + } + + case 17: + { + unsigned w1, w2, w; + + const_part = insn & 0xffe0e002; + dis_assemble_17 (value, &w1, &w2, &w); + rebuilt_part = (w2 << 2) | (w1 << 16) | w; + return const_part | rebuilt_part; + } + + case 21: + { + unsigned int w; + + const_part = insn & 0xffe00000; + dis_assemble_21 (value, &w); + return const_part | w; + } + + case 32: + const_part = 0; + return value; + + default: + abort (); + } + return insn; +} + +#endif /* _HPPA_H */ |