+ else if (mips_pic == SVR4_PIC && HAVE_NEWABI)
+ {
+ char *p = NULL;
+ int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
+ int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
+ int adj = 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,<sym> (BFD_RELOC_MIPS_GOT_HI16)
+ add $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ or if tempreg is PIC_CALL_REG
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_CALL_HI16)
+ add $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
+
+ If we have a small constant, and this is a reference to
+ an external symbol, we want
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
+ add $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ addi $tempreg,$tempreg,<constant>
+
+ If we have a large constant, and this is a reference to
+ an external symbol, we want
+ lui $tempreg,<sym> (BFD_RELOC_MIPS_GOT_HI16)
+ addu $tempreg,$tempreg,$gp
+ lw $tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
+ lui $at,<hiconstant>
+ addi $at,$at,<loconstant>
+ add $tempreg,$tempreg,$at
+
+ If we have NewABI, and we know it's a local symbol, we want
+ lw $reg,<sym>($gp) (BFD_RELOC_MIPS_GOT_PAGE)
+ addiu $reg,$reg,<sym> (BFD_RELOC_MIPS_GOT_OFST)
+ otherwise we have to resort to GOT_HI16/GOT_LO16. */
+
+ frag_grow (40);
+
+ frag_now->tc_frag_data.tc_fr_offset =
+ expr1.X_add_number = offset_expr.X_add_number;
+ offset_expr.X_add_number = 0;
+
+ if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG)
+ {
+ lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
+ lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
+ }
+ macro_build (NULL, &icnt, &offset_expr, "lui", "t,u",
+ tempreg, lui_reloc_type);
+ macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+ tempreg, tempreg, mips_gp_register);
+ macro_build (NULL, &icnt, &offset_expr, ADDRESS_LOAD_INSN,
+ "t,o(b)", tempreg, lw_reloc_type, tempreg);
+
+ if (expr1.X_add_number == 0)
+ {
+ p = frag_var (rs_machine_dependent, 8, 0,
+ RELAX_ENCODE (12, 8, 0, 4, 0,
+ mips_opts.warn_about_macros),
+ offset_expr.X_add_symbol, 0, NULL);
+ }
+ else if (expr1.X_add_number >= -0x8000
+ && expr1.X_add_number < 0x8000)
+ {
+ macro_build (NULL, &icnt, &expr1, ADDRESS_ADDI_INSN, "t,r,j",
+ tempreg, tempreg, BFD_RELOC_LO16);
+ p = frag_var (rs_machine_dependent, 8, 0,
+ RELAX_ENCODE (16, 8, 0, 4, 0,
+ mips_opts.warn_about_macros),
+ offset_expr.X_add_symbol, 0, NULL);
+ }
+ else if (IS_SEXT_32BIT_NUM (expr1.X_add_number))
+ {
+ int dreg;
+
+ /* If we are going to add in a base register, and the
+ target register and the base register are the same,
+ then we are using AT as a temporary register. Since
+ we want to load the constant into AT, we add our
+ current AT (from the global offset table) and the
+ register into the register now, and pretend we were
+ not using a base register. */
+ if (breg != treg)
+ dreg = tempreg;
+ else
+ {
+ assert (tempreg == AT);
+ macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+ treg, AT, breg);
+ dreg = treg;
+ adj = 4;
+ }
+
+ /* Set mips_optimize around the lui instruction to avoid
+ inserting an unnecessary nop after the lw. */
+ macro_build_lui (NULL, &icnt, &expr1, AT);
+ macro_build (NULL, &icnt, &expr1, ADDRESS_ADDI_INSN,
+ "t,r,j", AT, AT, BFD_RELOC_LO16);
+ macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+ dreg, dreg, AT);
+
+ p = frag_var (rs_machine_dependent, 8 + adj, 0,
+ RELAX_ENCODE (24 + adj, 8 + adj,
+ 0, 4, 0,
+ (breg == 0
+ ? mips_opts.warn_about_macros
+ : 0)),
+ offset_expr.X_add_symbol, 0, NULL);
+
+ used_at = 1;
+ }
+ else
+ as_bad (_("PIC code offset overflow (max 32 signed bits)"));
+
+ offset_expr.X_add_number = expr1.X_add_number;
+ macro_build (p, &icnt, &offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
+ tempreg, BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
+ macro_build (p + 4, &icnt, &offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
+ tempreg, tempreg, BFD_RELOC_MIPS_GOT_OFST);
+ if (adj)
+ {
+ macro_build (p + 8, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t",
+ treg, tempreg, breg);
+ breg = 0;
+ tempreg = treg;
+ }
+ }