(root)/
binutils-2.41/
bfd/
libhppa.h
       1  /* HP PA-RISC SOM object file format:  definitions internal to BFD.
       2     Copyright (C) 1990-2023 Free Software Foundation, Inc.
       3  
       4     Contributed by the Center for Software Science at the
       5     University of Utah (pa-gdb-bugs@cs.utah.edu).
       6  
       7     This file is part of BFD, the Binary File Descriptor library.
       8  
       9     This program is free software; you can redistribute it and/or modify
      10     it under the terms of the GNU General Public License as published by
      11     the Free Software Foundation; either version 3 of the License, or
      12     (at your option) any later version.
      13  
      14     This program is distributed in the hope that it will be useful,
      15     but WITHOUT ANY WARRANTY; without even the implied warranty of
      16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17     GNU General Public License for more details.
      18  
      19     You should have received a copy of the GNU General Public License
      20     along with this program; if not, write to the Free Software
      21     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
      22     MA 02110-1301, USA.  */
      23  
      24  #ifndef _LIBHPPA_H
      25  #define _LIBHPPA_H
      26  
      27  #define BYTES_IN_WORD 4
      28  #define PA_PAGESIZE 0x1000
      29  
      30  /* The PA instruction set variants.  */
      31  enum pa_arch {pa10 = 10, pa11 = 11, pa20 = 20, pa20w = 25};
      32  
      33  /* HP PA-RISC relocation types */
      34  
      35  enum hppa_reloc_field_selector_type
      36    {
      37      R_HPPA_FSEL = 0x0,
      38      R_HPPA_LSSEL = 0x1,
      39      R_HPPA_RSSEL = 0x2,
      40      R_HPPA_LSEL = 0x3,
      41      R_HPPA_RSEL = 0x4,
      42      R_HPPA_LDSEL = 0x5,
      43      R_HPPA_RDSEL = 0x6,
      44      R_HPPA_LRSEL = 0x7,
      45      R_HPPA_RRSEL = 0x8,
      46      R_HPPA_NSEL  = 0x9,
      47      R_HPPA_NLSEL  = 0xa,
      48      R_HPPA_NLRSEL  = 0xb,
      49      R_HPPA_PSEL = 0xc,
      50      R_HPPA_LPSEL = 0xd,
      51      R_HPPA_RPSEL = 0xe,
      52      R_HPPA_TSEL = 0xf,
      53      R_HPPA_LTSEL = 0x10,
      54      R_HPPA_RTSEL = 0x11,
      55      R_HPPA_LTPSEL = 0x12,
      56      R_HPPA_RTPSEL = 0x13
      57    };
      58  
      59  /* /usr/include/reloc.h defines these to constants.  We want to use
      60     them in enums, so #undef them before we start using them.  We might
      61     be able to fix this another way by simply managing not to include
      62     /usr/include/reloc.h, but currently GDB picks up these defines
      63     somewhere.  */
      64  #undef e_fsel
      65  #undef e_lssel
      66  #undef e_rssel
      67  #undef e_lsel
      68  #undef e_rsel
      69  #undef e_ldsel
      70  #undef e_rdsel
      71  #undef e_lrsel
      72  #undef e_rrsel
      73  #undef e_nsel
      74  #undef e_nlsel
      75  #undef e_nlrsel
      76  #undef e_psel
      77  #undef e_lpsel
      78  #undef e_rpsel
      79  #undef e_tsel
      80  #undef e_ltsel
      81  #undef e_rtsel
      82  #undef e_one
      83  #undef e_two
      84  #undef e_pcrel
      85  #undef e_con
      86  #undef e_plabel
      87  #undef e_abs
      88  
      89  /* for compatibility */
      90  enum hppa_reloc_field_selector_type_alt
      91    {
      92      e_fsel = R_HPPA_FSEL,
      93      e_lssel = R_HPPA_LSSEL,
      94      e_rssel = R_HPPA_RSSEL,
      95      e_lsel = R_HPPA_LSEL,
      96      e_rsel = R_HPPA_RSEL,
      97      e_ldsel = R_HPPA_LDSEL,
      98      e_rdsel = R_HPPA_RDSEL,
      99      e_lrsel = R_HPPA_LRSEL,
     100      e_rrsel = R_HPPA_RRSEL,
     101      e_nsel = R_HPPA_NSEL,
     102      e_nlsel = R_HPPA_NLSEL,
     103      e_nlrsel = R_HPPA_NLRSEL,
     104      e_psel = R_HPPA_PSEL,
     105      e_lpsel = R_HPPA_LPSEL,
     106      e_rpsel = R_HPPA_RPSEL,
     107      e_tsel = R_HPPA_TSEL,
     108      e_ltsel = R_HPPA_LTSEL,
     109      e_rtsel = R_HPPA_RTSEL,
     110      e_ltpsel = R_HPPA_LTPSEL,
     111      e_rtpsel = R_HPPA_RTPSEL
     112    };
     113  
     114  enum hppa_reloc_expr_type
     115    {
     116      R_HPPA_E_ONE = 0,
     117      R_HPPA_E_TWO = 1,
     118      R_HPPA_E_PCREL = 2,
     119      R_HPPA_E_CON = 3,
     120      R_HPPA_E_PLABEL = 7,
     121      R_HPPA_E_ABS = 18
     122    };
     123  
     124  /* for compatibility */
     125  enum hppa_reloc_expr_type_alt
     126    {
     127      e_one = R_HPPA_E_ONE,
     128      e_two = R_HPPA_E_TWO,
     129      e_pcrel = R_HPPA_E_PCREL,
     130      e_con = R_HPPA_E_CON,
     131      e_plabel = R_HPPA_E_PLABEL,
     132      e_abs = R_HPPA_E_ABS
     133    };
     134  
     135  
     136  /* Relocations for function calls must be accompanied by parameter
     137     relocation bits.  These bits describe exactly where the caller has
     138     placed the function's arguments and where it expects to find a return
     139     value.
     140  
     141     Both ELF and SOM encode this information within the addend field
     142     of the call relocation.  (Note this could break very badly if one
     143     was to make a call like bl foo + 0x12345678).
     144  
     145     The high order 10 bits contain parameter relocation information,
     146     the low order 22 bits contain the constant offset.  */
     147  
     148  #define HPPA_R_ARG_RELOC(a)	\
     149    (((a) >> 22) & 0x3ff)
     150  #define HPPA_R_CONSTANT(a)	\
     151    ((((bfd_signed_vma) (a) & 0x3fffff) ^ 0x200000) - 0x200000)
     152  #define HPPA_R_ADDEND(r, c)	\
     153    (((r) << 22) + ((c) & 0x3fffff))
     154  
     155  
     156  /* Some functions to manipulate PA instructions.  */
     157  
     158  /* The *sign_extend functions are used to assemble various bitfields
     159     taken from an instruction and return the resulting immediate
     160     value.  */
     161  
     162  static inline unsigned ATTRIBUTE_UNUSED
     163  sign_extend (unsigned x, unsigned len)
     164  {
     165    unsigned signbit = (1u << (len - 1));
     166    unsigned mask = (signbit << 1) - 1;
     167    return ((x & mask) ^ signbit) - signbit;
     168  }
     169  
     170  static inline unsigned ATTRIBUTE_UNUSED
     171  low_sign_extend (unsigned x, unsigned len)
     172  {
     173    return (x >> 1) - ((x & 1) << (len - 1));
     174  }
     175  
     176  
     177  /* The re_assemble_* functions prepare an immediate value for
     178     insertion into an opcode. pa-risc uses all sorts of weird bitfields
     179     in the instruction to hold the value.  */
     180  
     181  static inline unsigned ATTRIBUTE_UNUSED
     182  sign_unext (unsigned x, unsigned len)
     183  {
     184    unsigned len_ones;
     185  
     186    len_ones = (1 << len) - 1;
     187  
     188    return x & len_ones;
     189  }
     190  
     191  static inline unsigned ATTRIBUTE_UNUSED
     192  low_sign_unext (unsigned x, unsigned len)
     193  {
     194    unsigned temp;
     195    unsigned sign;
     196  
     197    sign = (x >> (len-1)) & 1;
     198  
     199    temp = sign_unext (x, len-1);
     200  
     201    return (temp << 1) | sign;
     202  }
     203  
     204  static inline unsigned ATTRIBUTE_UNUSED
     205  re_assemble_3 (unsigned as3)
     206  {
     207    return ((  (as3 & 4) << (13-2))
     208  	  | ((as3 & 3) << (13+1)));
     209  }
     210  
     211  static inline unsigned ATTRIBUTE_UNUSED
     212  re_assemble_12 (unsigned as12)
     213  {
     214    return ((  (as12 & 0x800) >> 11)
     215  	  | ((as12 & 0x400) >> (10 - 2))
     216  	  | ((as12 & 0x3ff) << (1 + 2)));
     217  }
     218  
     219  static inline unsigned ATTRIBUTE_UNUSED
     220  re_assemble_14 (unsigned as14)
     221  {
     222    return ((  (as14 & 0x1fff) << 1)
     223  	  | ((as14 & 0x2000) >> 13));
     224  }
     225  
     226  static inline unsigned ATTRIBUTE_UNUSED
     227  re_assemble_16 (unsigned as16)
     228  {
     229    unsigned s, t;
     230  
     231    /* Unusual 16-bit encoding, for wide mode only.  */
     232    t = (as16 << 1) & 0xffff;
     233    s = (as16 & 0x8000);
     234    return (t ^ s ^ (s >> 1)) | (s >> 15);
     235  }
     236  
     237  static inline unsigned ATTRIBUTE_UNUSED
     238  re_assemble_17 (unsigned as17)
     239  {
     240    return ((  (as17 & 0x10000) >> 16)
     241  	  | ((as17 & 0x0f800) << (16 - 11))
     242  	  | ((as17 & 0x00400) >> (10 - 2))
     243  	  | ((as17 & 0x003ff) << (1 + 2)));
     244  }
     245  
     246  static inline unsigned ATTRIBUTE_UNUSED
     247  re_assemble_21 (unsigned as21)
     248  {
     249    return ((  (as21 & 0x100000) >> 20)
     250  	  | ((as21 & 0x0ffe00) >> 8)
     251  	  | ((as21 & 0x000180) << 7)
     252  	  | ((as21 & 0x00007c) << 14)
     253  	  | ((as21 & 0x000003) << 12));
     254  }
     255  
     256  static inline unsigned ATTRIBUTE_UNUSED
     257  re_assemble_22 (unsigned as22)
     258  {
     259    return ((  (as22 & 0x200000) >> 21)
     260  	  | ((as22 & 0x1f0000) << (21 - 16))
     261  	  | ((as22 & 0x00f800) << (16 - 11))
     262  	  | ((as22 & 0x000400) >> (10 - 2))
     263  	  | ((as22 & 0x0003ff) << (1 + 2)));
     264  }
     265  
     266  
     267  /* Handle field selectors for PA instructions.
     268     The L and R (and LS, RS etc.) selectors are used in pairs to form a
     269     full 32 bit address.  eg.
     270  
     271     LDIL	L'start,%r1		; put left part into r1
     272     LDW	R'start(%r1),%r2	; add r1 and right part to form address
     273  
     274     This function returns sign extended values in all cases.
     275  */
     276  
     277  static inline bfd_signed_vma ATTRIBUTE_UNUSED
     278  hppa_field_adjust (bfd_vma sym_val,
     279  		   bfd_signed_vma addend,
     280  		   enum hppa_reloc_field_selector_type_alt r_field)
     281  {
     282    bfd_signed_vma value;
     283  
     284    value = sym_val + addend;
     285    switch (r_field)
     286      {
     287      case e_fsel:
     288        /* F: No change.  */
     289        break;
     290  
     291      case e_nsel:
     292        /* N: null selector.  I don't really understand what this is all
     293  	 about, but HP's documentation says "this indicates that zero
     294  	 bits are to be used for the displacement on the instruction.
     295  	 This fixup is used to identify three-instruction sequences to
     296  	 access data (for importing shared library data)."  */
     297        value = 0;
     298        break;
     299  
     300      case e_lsel:
     301      case e_nlsel:
     302        /* L:  Select top 21 bits.  */
     303        value = value >> 11;
     304        break;
     305  
     306      case e_rsel:
     307        /* R:  Select bottom 11 bits.  */
     308        value = value & 0x7ff;
     309        break;
     310  
     311      case e_lssel:
     312        /* LS:  Round to nearest multiple of 2048 then select top 21 bits.  */
     313        value = value + 0x400;
     314        value = value >> 11;
     315        break;
     316  
     317      case e_rssel:
     318        /* RS:  Select bottom 11 bits for LS.
     319  	 We need to return a value such that 2048 * LS'x + RS'x == x.
     320  	 ie. RS'x = x - ((x + 0x400) & -0x800)
     321  	 this is just a sign extension from bit 21.  */
     322        value = ((value & 0x7ff) ^ 0x400) - 0x400;
     323        break;
     324  
     325      case e_ldsel:
     326        /* LD:  Round to next multiple of 2048 then select top 21 bits.
     327  	 Yes, if we are already on a multiple of 2048, we go up to the
     328  	 next one.  RD in this case will be -2048.  */
     329        value = value + 0x800;
     330        value = value >> 11;
     331        break;
     332  
     333      case e_rdsel:
     334        /* RD:  Set bits 0-20 to one.  */
     335        value = value | -0x800;
     336        break;
     337  
     338      case e_lrsel:
     339      case e_nlrsel:
     340        /* LR:  L with rounding of the addend to nearest 8k.  */
     341        value = sym_val + ((addend + 0x1000) & -0x2000);
     342        value = value >> 11;
     343        break;
     344  
     345      case e_rrsel:
     346        /* RR:  R with rounding of the addend to nearest 8k.
     347  	 We need to return a value such that 2048 * LR'x + RR'x == x
     348  	 ie. RR'x = s+a - (s + (((a + 0x1000) & -0x2000) & -0x800))
     349  	 .	  = s+a - ((s & -0x800) + ((a + 0x1000) & -0x2000))
     350  	 .	  = (s & 0x7ff) + a - ((a + 0x1000) & -0x2000)  */
     351        value = (sym_val & 0x7ff) + (((addend & 0x1fff) ^ 0x1000) - 0x1000);
     352        break;
     353  
     354      default:
     355        abort ();
     356      }
     357    return value;
     358  }
     359  
     360  /* PA-RISC OPCODES */
     361  #define get_opcode(insn)	(((insn) >> 26) & 0x3f)
     362  
     363  enum hppa_opcode_type
     364  {
     365    /* None of the opcodes in the first group generate relocs, so we
     366       aren't too concerned about them.  */
     367    OP_SYSOP   = 0x00,
     368    OP_MEMMNG  = 0x01,
     369    OP_ALU     = 0x02,
     370    OP_NDXMEM  = 0x03,
     371    OP_SPOP    = 0x04,
     372    OP_DIAG    = 0x05,
     373    OP_FMPYADD = 0x06,
     374    OP_UNDEF07 = 0x07,
     375    OP_COPRW   = 0x09,
     376    OP_COPRDW  = 0x0b,
     377    OP_COPR    = 0x0c,
     378    OP_FLOAT   = 0x0e,
     379    OP_PRDSPEC = 0x0f,
     380    OP_UNDEF15 = 0x15,
     381    OP_UNDEF1d = 0x1d,
     382    OP_FMPYSUB = 0x26,
     383    OP_FPFUSED = 0x2e,
     384    OP_SHEXDP0 = 0x34,
     385    OP_SHEXDP1 = 0x35,
     386    OP_SHEXDP2 = 0x36,
     387    OP_UNDEF37 = 0x37,
     388    OP_SHEXDP3 = 0x3c,
     389    OP_SHEXDP4 = 0x3d,
     390    OP_MULTMED = 0x3e,
     391    OP_UNDEF3f = 0x3f,
     392  
     393    OP_LDIL    = 0x08,
     394    OP_ADDIL   = 0x0a,
     395  
     396    OP_LDO     = 0x0d,
     397    OP_LDB     = 0x10,
     398    OP_LDH     = 0x11,
     399    OP_LDW     = 0x12,
     400    OP_LDWM    = 0x13,
     401    OP_STB     = 0x18,
     402    OP_STH     = 0x19,
     403    OP_STW     = 0x1a,
     404    OP_STWM    = 0x1b,
     405  
     406    OP_LDD     = 0x14,
     407    OP_STD     = 0x1c,
     408  
     409    OP_FLDW    = 0x16,
     410    OP_LDWL    = 0x17,
     411    OP_FSTW    = 0x1e,
     412    OP_STWL    = 0x1f,
     413  
     414    OP_COMBT   = 0x20,
     415    OP_COMIBT  = 0x21,
     416    OP_COMBF   = 0x22,
     417    OP_COMIBF  = 0x23,
     418    OP_CMPBDT  = 0x27,
     419    OP_ADDBT   = 0x28,
     420    OP_ADDIBT  = 0x29,
     421    OP_ADDBF   = 0x2a,
     422    OP_ADDIBF  = 0x2b,
     423    OP_CMPBDF  = 0x2f,
     424    OP_BVB     = 0x30,
     425    OP_BB      = 0x31,
     426    OP_MOVB    = 0x32,
     427    OP_MOVIB   = 0x33,
     428    OP_CMPIBD  = 0x3b,
     429  
     430    OP_COMICLR = 0x24,
     431    OP_SUBI    = 0x25,
     432    OP_ADDIT   = 0x2c,
     433    OP_ADDI    = 0x2d,
     434  
     435    OP_BE      = 0x38,
     436    OP_BLE     = 0x39,
     437    OP_BL      = 0x3a
     438  };
     439  
     440  
     441  /* Given a machine instruction, return its format.  */
     442  
     443  static inline unsigned ATTRIBUTE_UNUSED
     444  bfd_hppa_insn2fmt (bfd *abfd, unsigned insn)
     445  {
     446    enum hppa_opcode_type op = (enum hppa_opcode_type) get_opcode (insn);
     447  
     448    switch (op)
     449      {
     450      case OP_COMICLR:
     451      case OP_SUBI:
     452      case OP_ADDIT:
     453      case OP_ADDI:
     454        return 11;
     455  
     456      case OP_COMBT:
     457      case OP_COMIBT:
     458      case OP_COMBF:
     459      case OP_COMIBF:
     460      case OP_CMPBDT:
     461      case OP_ADDBT:
     462      case OP_ADDIBT:
     463      case OP_ADDBF:
     464      case OP_ADDIBF:
     465      case OP_CMPBDF:
     466      case OP_BVB:
     467      case OP_BB:
     468      case OP_MOVB:
     469      case OP_MOVIB:
     470      case OP_CMPIBD:
     471        return 12;
     472  
     473      case OP_LDO:
     474      case OP_LDB:
     475      case OP_LDH:
     476      case OP_LDW:
     477      case OP_LDWM:
     478      case OP_STB:
     479      case OP_STH:
     480      case OP_STW:
     481      case OP_STWM:
     482        if (abfd->arch_info->mach >= 25)
     483  	return 16;	/* Wide mode, format 16.  */
     484        return 14;
     485  
     486      case OP_FLDW:
     487      case OP_LDWL:
     488      case OP_FSTW:
     489      case OP_STWL:
     490        /* This is a hack.  Unfortunately, format 11 is already taken
     491  	 and we're using integers rather than an enum, so it's hard
     492  	 to describe the 11a format.  */
     493        if (abfd->arch_info->mach >= 25)
     494  	return -16;	/* Wide mode, format 16a.  */
     495        return -11;
     496  
     497      case OP_LDD:
     498      case OP_STD:
     499        if (abfd->arch_info->mach >= 25)
     500  	return -10;	/* Wide mode, format 10a.  */
     501        return 10;
     502  
     503      case OP_BL:
     504        if ((insn & 0x8000) != 0)
     505  	return 22;
     506        /* fall thru */
     507      case OP_BE:
     508      case OP_BLE:
     509        return 17;
     510  
     511      case OP_LDIL:
     512      case OP_ADDIL:
     513        return 21;
     514  
     515      default:
     516        break;
     517      }
     518    return 32;
     519  }
     520  
     521  
     522  /* Insert VALUE into INSN using R_FORMAT to determine exactly what
     523     bits to change.  */
     524  
     525  static inline unsigned ATTRIBUTE_UNUSED
     526  hppa_rebuild_insn (unsigned insn, unsigned value, int r_format)
     527  {
     528    switch (r_format)
     529      {
     530      case 11:
     531        return (insn & ~ 0x7ff) | low_sign_unext (value, 11);
     532  
     533      case 12:
     534        return (insn & ~ 0x1ffd) | re_assemble_12 (value);
     535  
     536  
     537      case 10:
     538        return (insn & ~ 0x3ff1) | re_assemble_14 (value & -8);
     539  
     540      case -11:
     541        return (insn & ~ 0x3ff9) | re_assemble_14 (value & -4);
     542  
     543      case 14:
     544        return (insn & ~ 0x3fff) | re_assemble_14 (value);
     545  
     546  
     547      case -10:
     548        return (insn & ~ 0xfff1) | re_assemble_16 (value & -8);
     549  
     550      case -16:
     551        return (insn & ~ 0xfff9) | re_assemble_16 (value & -4);
     552  
     553      case 16:
     554        return (insn & ~ 0xffff) | re_assemble_16 (value);
     555  
     556  
     557      case 17:
     558        return (insn & ~ 0x1f1ffd) | re_assemble_17 (value);
     559  
     560      case 21:
     561        return (insn & ~ 0x1fffff) | re_assemble_21 (value);
     562  
     563      case 22:
     564        return (insn & ~ 0x3ff1ffd) | re_assemble_22 (value);
     565  
     566      case 32:
     567        return value;
     568  
     569      default:
     570        abort ();
     571      }
     572    return insn;
     573  }
     574  
     575  #endif /* _LIBHPPA_H */