2004-08-26 Jeff Baker * config/tc-mips.c (QNX_GP_REG): Define. (load_address): Added code to handle QNX_PIC pic level. (macro): Likewise. (mips_validate_fix): Likewise. (mips_fix_adjustable): Likewise. (s_cpsetup): Likewise. (s_cplocal): Likewise. (s_cprestore): Likewise. (s_cpreturn): Likewise. (s_cpadd): Likewise. (s_gpvalue): Likewise. (s_gpword): Likewise. (s_gpdword): Likewise. (md_longopts): Define qnx_pic command line argument. (md_parse_option): Handle qnx_pic command line argument. (s_qnxpiccalls): New function. (s_noqnxpiccalls): New function. * config/tc-mips.h (mips_pic_level): Add QNX_PIC pic level. Index: tc-mips.c =================================================================== RCS file: /cvs/src/src/gas/config/tc-mips.c,v retrieving revision 1.270 diff -w -u -1 -0 -p -r1.270 tc-mips.c --- tc-mips.c 18 Aug 2004 15:58:11 -0000 1.270 +++ tc-mips.c 26 Aug 2004 20:44:59 -0000 @@ -84,20 +84,21 @@ int mips_flag_pdr = TRUE; #endif #include "ecoff.h" #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) static char *mips_regmask_frag; #endif #define ZERO 0 #define AT 1 +#define QNX_GP_REG 23 #define TREG 24 #define PIC_CALL_REG 25 #define KT0 26 #define KT1 27 #define GP 28 #define SP 29 #define FP 30 #define RA 31 #define ILLEGAL_REG (32) @@ -877,20 +878,22 @@ static size_t my_getSmallExpression static void my_getExpression (expressionS *, char *); static void s_align (int); static void s_change_sec (int); static void s_change_section (int); static void s_cons (int); static void s_float_cons (int); static void s_mips_globl (int); static void s_option (int); static void s_mipsset (int); static void s_abicalls (int); +static void s_qnxpiccalls PARAMS ((int)); +static void s_noqnxpiccalls PARAMS ((int)); static void s_cpload (int); static void s_cpsetup (int); static void s_cplocal (int); static void s_cprestore (int); static void s_cpreturn (int); static void s_gpvalue (int); static void s_gpword (int); static void s_gpdword (int); static void s_cpadd (int); static void s_insn (int); @@ -943,20 +946,22 @@ static const struct mips_cpu_info *mips_ static const pseudo_typeS mips_pseudo_table[] = { /* MIPS specific pseudo-ops. */ {"option", s_option, 0}, {"set", s_mipsset, 0}, {"rdata", s_change_sec, 'r'}, {"sdata", s_change_sec, 's'}, {"livereg", s_ignore, 0}, {"abicalls", s_abicalls, 0}, + {"qnxpiccalls", s_qnxpiccalls, 0}, + {"noqnxpiccalls", s_noqnxpiccalls, 0}, {"cpload", s_cpload, 0}, {"cpsetup", s_cpsetup, 0}, {"cplocal", s_cplocal, 0}, {"cprestore", s_cprestore, 0}, {"cpreturn", s_cpreturn, 0}, {"gpvalue", s_gpvalue, 0}, {"gpword", s_gpword, 0}, {"gpdword", s_gpdword, 0}, {"cpadd", s_cpadd, 0}, {"insn", s_insn, 0}, @@ -3877,21 +3882,21 @@ load_address (int reg, expressionS *ep, mips_gp_register, BFD_RELOC_GPREL16); relax_switch (); } macro_build_lui (ep, reg); macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg, BFD_RELOC_LO16); if (mips_relax.sequence) relax_end (); } } - else if (mips_pic == SVR4_PIC && ! mips_big_got) + else if ((mips_pic == SVR4_PIC || mips_pic == QNX_PIC) && ! mips_big_got) { expressionS ex; /* If this is a reference to an external symbol, we want lw $reg,($gp) (BFD_RELOC_MIPS_GOT16) Otherwise we want lw $reg,($gp) (BFD_RELOC_MIPS_GOT16) nop addiu $reg,$reg, (BFD_RELOC_LO16) If there is a constant, it must be added in after. @@ -3938,21 +3943,21 @@ load_address (int reg, expressionS *ep, if (ex.X_add_number != 0) { if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000) as_bad (_("PIC code offset overflow (max 16 signed bits)")); ex.X_op = O_constant; macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j", reg, reg, BFD_RELOC_LO16); } } } - else if (mips_pic == SVR4_PIC) + else if (mips_pic == SVR4_PIC || mips_pic == QNX_PIC) { expressionS ex; /* This is the large GOT case. If this is a reference to an external symbol, we want lui $reg, (BFD_RELOC_MIPS_GOT_HI16) addu $reg,$reg,$gp lw $reg,($reg) (BFD_RELOC_MIPS_GOT_LO16) Otherwise, for a reference to a local symbol in old ABI, we want @@ -4969,21 +4974,21 @@ macro (struct mips_cl_insn *ip) tempreg, mips_gp_register, BFD_RELOC_GPREL16); relax_switch (); } macro_build_lui (&offset_expr, tempreg); macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg, tempreg, BFD_RELOC_LO16); if (mips_relax.sequence) relax_end (); } } - else if (mips_pic == SVR4_PIC && ! mips_big_got && ! HAVE_NEWABI) + else if ((mips_pic == SVR4_PIC || mips_pic == QNX_PIC) && ! mips_big_got && ! HAVE_NEWABI) { int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16; /* If this is a reference to an external symbol, and there is no constant, we want lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT16) or for lca or if tempreg is PIC_CALL_REG lw $tempreg,($gp) (BFD_RELOC_MIPS_CALL16) For a local symbol, we want lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT16) @@ -5062,21 +5067,21 @@ macro (struct mips_cl_insn *ip) load_delay_nop (); macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", treg, AT, breg); breg = 0; tempreg = treg; } add_got_offset_hilo (tempreg, &offset_expr, AT); used_at = 1; } } - else if (mips_pic == SVR4_PIC && ! mips_big_got && HAVE_NEWABI) + else if ((mips_pic == SVR4_PIC || mips_pic == QNX_PIC) && ! mips_big_got && HAVE_NEWABI) { int add_breg_early = 0; /* If this is a reference to an external, and there is no constant, or local symbol (*), with or without a constant, we want lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_DISP) or for lca or if tempreg is PIC_CALL_REG lw $tempreg,($gp) (BFD_RELOC_MIPS_CALL16) @@ -5165,21 +5170,21 @@ macro (struct mips_cl_insn *ip) macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg, BFD_RELOC_MIPS_GOT_DISP, mips_gp_register); relax_end (); } else { macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg, BFD_RELOC_MIPS_GOT_DISP, mips_gp_register); } } - else if (mips_pic == SVR4_PIC && ! HAVE_NEWABI) + else if ((mips_pic == SVR4_PIC || mips_pic == QNX_PIC) && ! HAVE_NEWABI) { int gpdelay; int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16; int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16; int local_reloc_type = (int) BFD_RELOC_MIPS_GOT16; /* This is the large GOT case. If this is a reference to an external symbol, and there is no constant, we want lui $tempreg, (BFD_RELOC_MIPS_GOT_HI16) addu $tempreg,$tempreg,$gp @@ -5321,21 +5326,21 @@ macro (struct mips_cl_insn *ip) } macro_build_lui (&expr1, AT); macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", AT, AT, BFD_RELOC_LO16); macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg, AT); } relax_end (); } - else if (mips_pic == SVR4_PIC && HAVE_NEWABI) + else if ((mips_pic == SVR4_PIC || mips_pic == QNX_PIC) && HAVE_NEWABI) { int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16; int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16; int add_breg_early = 0; /* This is the large GOT case. If this is a reference to an external symbol, and there is no constant, we want lui $tempreg, (BFD_RELOC_MIPS_GOT_HI16) add $tempreg,$tempreg,$gp lw $tempreg,($tempreg) (BFD_RELOC_MIPS_GOT_LO16) @@ -5467,61 +5472,64 @@ macro (struct mips_cl_insn *ip) /* The jal instructions must be handled as macros because when generating PIC code they expand to multi-instruction sequences. Normally they are simple instructions. */ case M_JAL_1: dreg = RA; /* Fall through. */ case M_JAL_2: if (mips_pic == NO_PIC) macro_build (NULL, "jalr", "d,s", dreg, sreg); - else if (mips_pic == SVR4_PIC) + else if (mips_pic == SVR4_PIC || mips_pic == QNX_PIC) { - if (sreg != PIC_CALL_REG) + if ((sreg != PIC_CALL_REG) && (mips_pic != QNX_PIC)) as_warn (_("MIPS PIC call to register other than $25")); macro_build (NULL, "jalr", "d,s", dreg, sreg); if (! HAVE_NEWABI) { - if (mips_cprestore_offset < 0) + if (mips_cprestore_offset < 0){ + if (mips_pic != QNX_PIC) as_warn (_("No .cprestore pseudo-op used in PIC code")); + } else { if (! mips_frame_reg_valid) { as_warn (_("No .frame pseudo-op used in PIC code")); /* Quiet this warning. */ mips_frame_reg_valid = 1; } if (! mips_cprestore_valid) { + if (mips_pic != QNX_PIC) as_warn (_("No .cprestore pseudo-op used in PIC code")); /* Quiet this warning. */ mips_cprestore_valid = 1; } expr1.X_add_number = mips_cprestore_offset; macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN, mips_gp_register, mips_frame_reg, HAVE_64BIT_ADDRESSES); } } } else abort (); return; case M_JAL_A: if (mips_pic == NO_PIC) macro_build (&offset_expr, "jal", "a"); - else if (mips_pic == SVR4_PIC) + else if (mips_pic == SVR4_PIC || mips_pic == QNX_PIC) { /* If this is a reference to an external symbol, and we are using a small GOT, we want lw $25,($gp) (BFD_RELOC_MIPS_CALL16) nop jalr $ra,$25 nop lw $gp,cprestore($sp) The cprestore value is set using the .cprestore pseudo-op. If we are using a big GOT, we want @@ -5578,20 +5586,28 @@ macro (struct mips_cl_insn *ip) relax_end (); } macro_build_jalr (&offset_expr); } else { relax_start (offset_expr.X_add_symbol); if (! mips_big_got) { + if(mips_pic != QNX_PIC) + macro_build (&offset_expr, + ((bfd_arch_bits_per_address (stdoutput) == 32 + || ! ISA_HAS_64BIT_REGS (mips_opts.isa)) + ? "lw" : "ld"), + "t,o(b)", PIC_CALL_REG, + (int) BFD_RELOC_MIPS_CALL16, mips_gp_register); + else macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", PIC_CALL_REG, BFD_RELOC_MIPS_CALL16, mips_gp_register); load_delay_nop (); relax_switch (); } else { int gpdelay; @@ -5610,22 +5626,24 @@ macro (struct mips_cl_insn *ip) } macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", PIC_CALL_REG, BFD_RELOC_MIPS_GOT16, mips_gp_register); load_delay_nop (); macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", PIC_CALL_REG, PIC_CALL_REG, BFD_RELOC_LO16); relax_end (); macro_build_jalr (&offset_expr); - if (mips_cprestore_offset < 0) + if (mips_cprestore_offset < 0) { + if (mips_pic != QNX_PIC) as_warn (_("No .cprestore pseudo-op used in PIC code")); + } else { if (! mips_frame_reg_valid) { as_warn (_("No .frame pseudo-op used in PIC code")); /* Quiet this warning. */ mips_frame_reg_valid = 1; } if (! mips_cprestore_valid) { @@ -6010,21 +6028,21 @@ macro (struct mips_cl_insn *ip) } macro_build_lui (&offset_expr, tempreg); macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg, breg); macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg); if (mips_relax.sequence) relax_end (); } } - else if (mips_pic == SVR4_PIC && ! mips_big_got) + else if ((mips_pic == SVR4_PIC || mips_pic == QNX_PIC) && ! mips_big_got) { int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16; /* If this is a reference to an external symbol, we want lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT16) nop $treg,0($tempreg) Otherwise we want lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT16) nop @@ -6068,21 +6086,21 @@ macro (struct mips_cl_insn *ip) relax_start (offset_expr.X_add_symbol); relax_switch (); macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg, tempreg, BFD_RELOC_LO16); relax_end (); if (breg != 0) macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg, breg); macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg); } - else if (mips_pic == SVR4_PIC && ! HAVE_NEWABI) + else if ((mips_pic == SVR4_PIC || mips_pic == QNX_PIC) && ! HAVE_NEWABI) { int gpdelay; /* If this is a reference to an external symbol, we want lui $tempreg, (BFD_RELOC_MIPS_GOT_HI16) addu $tempreg,$tempreg,$gp lw $tempreg,($tempreg) (BFD_RELOC_MIPS_GOT_LO16) $treg,0($tempreg) Otherwise we want lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT16) @@ -6117,21 +6135,21 @@ macro (struct mips_cl_insn *ip) load_delay_nop (); macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg, tempreg, BFD_RELOC_LO16); relax_end (); if (breg != 0) macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg, breg); macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg); } - else if (mips_pic == SVR4_PIC && HAVE_NEWABI) + else if ((mips_pic == SVR4_PIC || mips_pic == QNX_PIC) && HAVE_NEWABI) { /* If this is a reference to an external symbol, we want lui $tempreg, (BFD_RELOC_MIPS_GOT_HI16) add $tempreg,$tempreg,$gp lw $tempreg,($tempreg) (BFD_RELOC_MIPS_GOT_LO16) $treg,($tempreg) Otherwise, for local symbols, we want: lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_PAGE) $treg,($tempreg) (BFD_RELOC_MIPS_GOT_OFST) */ assert (offset_expr.X_op == O_symbol); @@ -6238,21 +6256,21 @@ macro (struct mips_cl_insn *ip) } return; } /* We know that sym is in the .rdata section. First we get the upper 16 bits of the address. */ if (mips_pic == NO_PIC) { macro_build_lui (&offset_expr, AT); } - else if (mips_pic == SVR4_PIC) + else if (mips_pic == SVR4_PIC || mips_pic == QNX_PIC) { macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT, BFD_RELOC_MIPS_GOT16, mips_gp_register); } else abort (); /* Now we load the register(s). */ if (HAVE_64BIT_GPRS) macro_build (&offset_expr, "ld", "t,o(b)", treg, BFD_RELOC_LO16, AT); @@ -6310,21 +6328,21 @@ macro (struct mips_cl_insn *ip) BFD_RELOC_MIPS_LITERAL, mips_gp_register); return; } breg = mips_gp_register; r = BFD_RELOC_MIPS_LITERAL; goto dob; } else { assert (strcmp (s, RDATA_SECTION_NAME) == 0); - if (mips_pic == SVR4_PIC) + if (mips_pic == SVR4_PIC || mips_pic == QNX_PIC) macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT, BFD_RELOC_MIPS_GOT16, mips_gp_register); else { /* FIXME: This won't work for a 64 bit address. */ macro_build_lui (&offset_expr, AT); } if (mips_opts.isa != ISA_MIPS1) { @@ -6524,21 +6542,21 @@ macro (struct mips_cl_insn *ip) macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg, BFD_RELOC_LO16, AT); /* FIXME: How do we handle overflow here? */ offset_expr.X_add_number += 4; /* Itbl support may require additional care here. */ macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1, BFD_RELOC_LO16, AT); if (mips_relax.sequence) relax_end (); } - else if (mips_pic == SVR4_PIC && ! mips_big_got) + else if ((mips_pic == SVR4_PIC || mips_pic == QNX_PIC) && ! mips_big_got) { /* If this is a reference to an external symbol, we want lw $at,($gp) (BFD_RELOC_MIPS_GOT16) nop $treg,0($at) $treg+1,4($at) Otherwise we want lw $at,($gp) (BFD_RELOC_MIPS_GOT16) nop $treg,($at) (BFD_RELOC_LO16) @@ -6571,21 +6589,21 @@ macro (struct mips_cl_insn *ip) relax_switch (); macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg, BFD_RELOC_LO16, AT); offset_expr.X_add_number += 4; macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1, BFD_RELOC_LO16, AT); relax_end (); mips_optimize = hold_mips_optimize; } - else if (mips_pic == SVR4_PIC) + else if (mips_pic == SVR4_PIC || mips_pic == QNX_PIC) { int gpdelay; /* If this is a reference to an external symbol, we want lui $at, (BFD_RELOC_MIPS_GOT_HI16) addu $at,$at,$gp lw $at,($at) (BFD_RELOC_MIPS_GOT_LO16) nop $treg,0($at) $treg+1,4($at) @@ -10120,20 +10138,22 @@ struct option md_longopts[] = #define OPTION_64 (OPTION_ELF_BASE + 6) {"64", no_argument, NULL, OPTION_64}, #define OPTION_MDEBUG (OPTION_ELF_BASE + 7) {"mdebug", no_argument, NULL, OPTION_MDEBUG}, #define OPTION_NO_MDEBUG (OPTION_ELF_BASE + 8) {"no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG}, #define OPTION_PDR (OPTION_ELF_BASE + 9) {"mpdr", no_argument, NULL, OPTION_PDR}, #define OPTION_NO_PDR (OPTION_ELF_BASE + 10) {"mno-pdr", no_argument, NULL, OPTION_NO_PDR}, +#define OPTION_QNX_PIC (OPTION_ELF_BASE + 11) + {"qnx_pic", no_argument, NULL, OPTION_QNX_PIC}, #endif /* OBJ_ELF */ {NULL, no_argument, NULL, 0} }; size_t md_longopts_size = sizeof (md_longopts); /* Set STRING_PTR (either &mips_arch_string or &mips_tune_string) to NEW_VALUE. Warn if another value was already specified. Note: we have to defer parsing the -march and -mtune arguments in order to handle 'from-abi' correctly, since the ABI might be specified @@ -10461,20 +10481,37 @@ md_parse_option (int c, char *arg) mips_flag_mdebug = FALSE; break; case OPTION_PDR: mips_flag_pdr = TRUE; break; case OPTION_NO_PDR: mips_flag_pdr = FALSE; break; + + case OPTION_QNX_PIC: + if (OUTPUT_FLAVOR != bfd_target_elf_flavour) + { + as_bad ("-qnx_pic is supported only for ELF format"); + return 0; + } + mips_pic = QNX_PIC; + mips_gp_register = QNX_GP_REG; + if (g_switch_seen && g_switch_value != 0) + { + as_bad ("-G may not be used with QNX PIC code"); + return 0; + } + g_switch_value = 0; + break; + #endif /* OBJ_ELF */ default: return 0; } return 1; } /* Set up globals to generate code for the ISA or processor @@ -10865,21 +10902,21 @@ mips_validate_fix (struct fix *fixP, ase else if (S_GET_SEGMENT (fixP->fx_addsy) != seg) { as_bad_where (fixP->fx_file, fixP->fx_line, _("Cannot branch to symbol in another section.")); fixP->fx_done = 1; } else if (S_IS_EXTERNAL (fixP->fx_addsy)) { symbolS *sym = fixP->fx_addsy; - if (mips_pic == SVR4_PIC) + if (mips_pic == SVR4_PIC || mips_pic == QNX_PIC) as_warn_where (fixP->fx_file, fixP->fx_line, _("Pretending global symbol used as branch target is local.")); fixP->fx_addsy = symbol_create (S_GET_NAME (sym), S_GET_SEGMENT (sym), S_GET_VALUE (sym), symbol_get_frag (sym)); copy_symbol_attributes (fixP->fx_addsy, sym); S_CLEAR_EXTERNAL (fixP->fx_addsy); assert (symbol_resolved_p (sym)); @@ -11759,62 +11796,152 @@ s_abicalls (int ignore ATTRIBUTE_UNUSED) mips_abicalls = TRUE; if (g_switch_seen && g_switch_value != 0) as_warn (_("-G may not be used with SVR4 PIC code")); g_switch_value = 0; bfd_set_gp_size (stdoutput, 0); demand_empty_rest_of_line (); } +/* This handles the .qnxpiccalls pseudo-op.i */ + +static void +s_qnxpiccalls (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + mips_pic = QNX_PIC; + mips_gp_register = QNX_GP_REG; + if (g_switch_seen && g_switch_value != 0) + as_warn ("-G may not be used with QNX PIC code"); + g_switch_value = 0; + bfd_set_gp_size (stdoutput, 0); + demand_empty_rest_of_line (); +} + +/* Allows us to turn off PIC code gen, in case that is needed */ + +static void +s_noqnxpiccalls (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + mips_pic = NO_PIC; + mips_gp_register = GP; + demand_empty_rest_of_line (); +} + + /* Handle the .cpload pseudo-op. This is used when generating SVR4 PIC code. It sets the $gp register for the function based on the function address, which is in the register named in the argument. This uses a relocation against _gp_disp, which is handled specially by the linker. The result is: lui $gp,%hi(_gp_disp) addiu $gp,$gp,%lo(_gp_disp) addu $gp,$gp,.cpload argument - The .cpload argument is normally $25 == $t9. */ + The .cpload argument is normally $25 == $t9. + + In the case of QNX pic code, we always compute the full address + of the GOT, therefore we do: + bltzal 0, 0f + nop + 0: lui $23, %hi(_gp_disp) + addiu $23, $23, %lo(_gp_disp) + addu $23, $23, $31 + One possible optimization would be to move the opcode + right before the bltzal into the nop slot. */ static void s_cpload (int ignore ATTRIBUTE_UNUSED) { expressionS ex; /* If we are not generating SVR4 PIC code, or if this is NewABI code, .cpload is ignored. */ - if (mips_pic != SVR4_PIC || HAVE_NEWABI) + if ((mips_pic != SVR4_PIC && mips_pic != QNX_PIC) || HAVE_NEWABI) { s_ignore (0); return; } /* .cpload should be in a .set noreorder section. */ - if (mips_opts.noreorder == 0) + if ((mips_opts.noreorder == 0) && (mips_pic != QNX_PIC)) as_warn (_(".cpload not in noreorder section")); ex.X_op = O_symbol; ex.X_add_symbol = symbol_find_or_make ("_gp_disp"); ex.X_op_symbol = NULL; ex.X_add_number = 0; /* In ELF, this symbol is implicitly an STT_OBJECT symbol. */ symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT; + if (mips_pic == QNX_PIC) { + expressionS ep; + /* In our case, we do a bltzal first to get the current IP, and + * then add the offset to the got... Thus, we always do "cpload $31" + */ + ep.X_op = O_constant; + ep.X_add_number = 4; + tc_get_register(0); // Flush any arg to cpload... + + /* See if we can swap the bltzal with the previous insn and save + * the nop... + * For simplicity, we only check that the insn is a move or sw, + * which are really the only two we should encounter. + * If it is anything else, we don't swap for now. + */ + if(0 && (mips_optimize > 1) + && prev_insn_valid + && (mips_opts.isa > 1) + && !(mips_opts.noreorder) + && (((prev_insn.insn_opcode & 0xfc1f07ff) == 0x00000021) + || ((prev_insn.insn_opcode & 0xfc000000) == 0xac000000))) + { + char *prev_f; + char temp[4]; + + prev_f = prev_insn_frag->fr_literal + prev_insn_where; + memcpy (temp, prev_f, 4); + *(unsigned long *)(prev_f) = 0x04100001; + macro_build (&ep, + "bltzal", "s,p", 0); + + prev_f = prev_insn_frag->fr_literal + prev_insn_where; + memcpy (prev_f, temp, 4); + mips_opts.noreorder ++; + } + else + { /* We need a NOP... */ + mips_opts.noreorder ++; + macro_build (&ep, + "bltzal", "s,p", 0); + macro_build ((expressionS *) NULL, "nop", ""); + } + macro_build_lui (&ex, 23); + macro_build (&ex, "addiu", "t,r,j", 23, 23, + (int) BFD_RELOC_LO16); + mips_opts.noreorder --; + + macro_build ((expressionS *) NULL, "addu", "d,v,t", + 23, 23, RA); + } else + { + macro_start (); macro_build_lui (&ex, mips_gp_register); macro_build (&ex, "addiu", "t,r,j", mips_gp_register, mips_gp_register, BFD_RELOC_LO16); macro_build (NULL, "addu", "d,v,t", mips_gp_register, mips_gp_register, tc_get_register (0)); macro_end (); +} demand_empty_rest_of_line (); } /* Handle the .cpsetup pseudo-op defined for NewABI PIC code. The syntax is: .cpsetup $reg1, offset|$reg2, label If offset is given, this results in: sd $gp, offset($sp) lui $gp, %hi(%neg(%gp_rel(label))) @@ -11830,21 +11957,21 @@ s_cpload (int ignore ATTRIBUTE_UNUSED) static void s_cpsetup (int ignore ATTRIBUTE_UNUSED) { expressionS ex_off; expressionS ex_sym; int reg1; char *f; /* If we are not generating SVR4 PIC code, .cpsetup is ignored. We also need NewABI support. */ - if (mips_pic != SVR4_PIC || ! HAVE_NEWABI) + if ((mips_pic != SVR4_PIC && mips_pic != QNX_PIC)|| ! HAVE_NEWABI) { s_ignore (0); return; } reg1 = tc_get_register (0); SKIP_WHITESPACE (); if (*input_line_pointer != ',') { as_bad (_("missing argument separator ',' for .cpsetup")); @@ -11912,42 +12039,42 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED) macro_end (); demand_empty_rest_of_line (); } static void s_cplocal (int ignore ATTRIBUTE_UNUSED) { /* If we are not generating SVR4 PIC code, or if this is not NewABI code, .cplocal is ignored. */ - if (mips_pic != SVR4_PIC || ! HAVE_NEWABI) + if ((mips_pic != SVR4_PIC && mips_pic != QNX_PIC) || ! HAVE_NEWABI) { s_ignore (0); return; } mips_gp_register = tc_get_register (0); demand_empty_rest_of_line (); } /* Handle the .cprestore pseudo-op. This stores $gp into a given offset from $sp. The offset is remembered, and after making a PIC call $gp is restored from that location. */ static void s_cprestore (int ignore ATTRIBUTE_UNUSED) { expressionS ex; /* If we are not generating SVR4 PIC code, or if this is NewABI code, .cprestore is ignored. */ - if (mips_pic != SVR4_PIC || HAVE_NEWABI) + if ((mips_pic != SVR4_PIC && mips_pic != QNX_PIC) || HAVE_NEWABI) { s_ignore (0); return; } mips_cprestore_offset = get_absolute_expression (); mips_cprestore_valid = 1; ex.X_op = O_constant; ex.X_add_symbol = NULL; @@ -11969,21 +12096,21 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED If a register $reg2 was given there, it results in: daddu $gp, $reg2, $0 */ static void s_cpreturn (int ignore ATTRIBUTE_UNUSED) { expressionS ex; /* If we are not generating SVR4 PIC code, .cpreturn is ignored. We also need NewABI support. */ - if (mips_pic != SVR4_PIC || ! HAVE_NEWABI) + if ((mips_pic != SVR4_PIC && mips_pic != QNX_PIC) || ! HAVE_NEWABI) { s_ignore (0); return; } macro_start (); if (mips_cpreturn_register == -1) { ex.X_op = O_constant; ex.X_add_symbol = NULL; @@ -12001,21 +12128,21 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED) } /* Handle the .gpvalue pseudo-op. This is used when generating NewABI PIC code. It sets the offset to use in gp_rel relocations. */ static void s_gpvalue (int ignore ATTRIBUTE_UNUSED) { /* If we are not generating SVR4 PIC code, .gpvalue is ignored. We also need NewABI support. */ - if (mips_pic != SVR4_PIC || ! HAVE_NEWABI) + if ((mips_pic != SVR4_PIC && mips_pic != QNX_PIC) || ! HAVE_NEWABI) { s_ignore (0); return; } mips_gprel_offset = get_absolute_expression (); demand_empty_rest_of_line (); } @@ -12023,21 +12150,21 @@ s_gpvalue (int ignore ATTRIBUTE_UNUSED) code. It generates a 32 bit GP relative reloc. */ static void s_gpword (int ignore ATTRIBUTE_UNUSED) { symbolS *label; expressionS ex; char *p; /* When not generating PIC code, this is treated as .word. */ - if (mips_pic != SVR4_PIC) + if (mips_pic != SVR4_PIC && mips_pic != QNX_PIC) { s_cons (2); return; } label = insn_labels != NULL ? insn_labels->label : NULL; mips_emit_delays (TRUE); if (auto_align) mips_align (2, 0, label); mips_clear_insn_labels (); @@ -12059,21 +12186,21 @@ s_gpword (int ignore ATTRIBUTE_UNUSED) } static void s_gpdword (int ignore ATTRIBUTE_UNUSED) { symbolS *label; expressionS ex; char *p; /* When not generating PIC code, this is treated as .dword. */ - if (mips_pic != SVR4_PIC) + if (mips_pic != SVR4_PIC && mips_pic != QNX_PIC) { s_cons (3); return; } label = insn_labels != NULL ? insn_labels->label : NULL; mips_emit_delays (TRUE); if (auto_align) mips_align (3, 0, label); mips_clear_insn_labels (); @@ -12103,21 +12230,21 @@ s_gpdword (int ignore ATTRIBUTE_UNUSED) /* Handle the .cpadd pseudo-op. This is used when dealing with switch tables in SVR4 PIC code. */ static void s_cpadd (int ignore ATTRIBUTE_UNUSED) { int reg; /* This is ignored when not generating SVR4 PIC code. */ - if (mips_pic != SVR4_PIC) + if (mips_pic != SVR4_PIC && mips_pic != QNX_PIC) { s_ignore (0); return; } /* Add $gp to the register named as an argument. */ macro_start (); reg = tc_get_register (0); macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", reg, reg, mips_gp_register); macro_end (); @@ -12698,34 +12825,33 @@ relaxed_branch_length (fragS *fragp, ase encoded in the subtype information. For the mips16, we have to decide whether we are using an extended opcode or not. */ int md_estimate_size_before_relax (fragS *fragp, asection *segtype) { int change; if (RELAX_BRANCH_P (fragp->fr_subtype)) { - fragp->fr_var = relaxed_branch_length (fragp, segtype, FALSE); return fragp->fr_var; } if (RELAX_MIPS16_P (fragp->fr_subtype)) /* We don't want to modify the EXTENDED bit here; it might get us into infinite loops. We change it only in mips_relax_frag(). */ return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2); if (mips_pic == NO_PIC) change = nopic_need_relax (fragp->fr_symbol, 0); - else if (mips_pic == SVR4_PIC) + else if (mips_pic == SVR4_PIC || mips_pic == QNX_PIC) change = pic_need_relax (fragp->fr_symbol, segtype); else abort (); if (change) { fragp->fr_subtype |= RELAX_USE_SECOND; return -RELAX_FIRST (fragp->fr_subtype); } else @@ -12743,20 +12869,28 @@ mips_fix_adjustable (fixS *fixp) if (fixp->fx_r_type == BFD_RELOC_MIPS16_JMP) return 0; if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 0; if (fixp->fx_addsy == NULL) return 1; + if ((mips_pic == QNX_PIC) && + (fixp->fx_r_type == BFD_RELOC_MIPS_GOT16 || fixp->fx_r_type == BFD_RELOC_32)) + { + symbolS * sym = fixp->fx_addsy; + if (S_IS_EXTERN(sym) || S_IS_WEAK(sym)) return 0; + } + + /* If symbol SYM is in a mergeable section, relocations of the form SYM + 0 can usually be made section-relative. The mergeable data is then identified by the section offset rather than by the symbol. However, if we're generating REL LO16 relocations, the offset is split between the LO16 and parterning high part relocation. The linker will need to recalculate the complete offset in order to correctly identify the merge data. The linker has traditionally not looked for the parterning high part Index: config/tc-mips.h =================================================================== RCS file: /cvs/src/src/gas/config/tc-mips.h,v retrieving revision 1.35 diff -w -u -1 -0 -p -r1.35 tc-mips.h --- config/tc-mips.h 29 Apr 2004 05:14:22 -0000 1.35 +++ config/tc-mips.h 26 Aug 2004 19:43:05 -0000 @@ -68,20 +68,23 @@ extern const char *mips_target_format (v /* MIPS PIC level. */ enum mips_pic_level { /* Do not generate PIC code. */ NO_PIC, /* Generate PIC code as in the SVR4 MIPS ABI. */ SVR4_PIC, + + /* Generate QNX PIC code. */ + QNX_PIC, }; extern enum mips_pic_level mips_pic; struct mips_cl_insn { unsigned long insn_opcode; const struct mips_opcode *insn_mo; /* The next two fields are used when generating mips16 code. */ bfd_boolean use_extend;