+ else
+ {
+ /* If this is a reference to an external symbol, and there
+ is no constant, we want
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
+ For a local symbol, we want
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
+ nop
+ addiu $tempreg,$tempreg,<sym> (BFD_RELOC_LO16)
+
+ If we have a small constant, and this is a reference to
+ an external symbol, we want
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
+ nop
+ addiu $tempreg,$tempreg,<constant>
+ For a local symbol, we want the same instruction
+ sequence, but we output a BFD_RELOC_LO16 reloc on the
+ addiu instruction.
+
+ If we have a large constant, and this is a reference to
+ an external symbol, we want
+ lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
+ lui $at,<hiconstant>
+ addiu $at,$at,<loconstant>
+ addu $tempreg,$tempreg,$at
+ For a local symbol, we want the same instruction
+ sequence, but we output a BFD_RELOC_LO16 reloc on the
+ addiu instruction. */
+ expr1.X_add_number = offset_expr.X_add_number;
+ offset_expr.X_add_number = 0;
+ frag_grow (24);
+ macro_build ((char *) NULL, &icnt, &offset_expr,
+ mips_isa < 3 ? "lw" : "ld",
+ "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP);
+ if (expr1.X_add_number == 0)
+ {
+ int off;
+
+ if (breg == 0)
+ off = 0;
+ else
+ {
+ /* We're going to put in an addu instruction using
+ tempreg, so we may as well insert the nop right
+ now. */
+ macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+ "nop", "");
+ off = 4;
+ }
+ p = frag_var (rs_machine_dependent, 8 - off, 0,
+ RELAX_ENCODE (0, 8 - off, -4 - off, 4 - off, 0,
+ (breg == 0
+ ? mips_warn_about_macros
+ : 0)),
+ offset_expr.X_add_symbol, (long) 0,
+ (char *) NULL);
+ if (breg == 0)
+ {
+ macro_build (p, &icnt, (expressionS *) NULL, "nop", "");
+ p += 4;
+ }
+ macro_build (p, &icnt, &expr1,
+ mips_isa < 3 ? "addiu" : "daddiu",
+ "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
+ /* FIXME: If breg == 0, and the next instruction uses
+ $tempreg, then if this variant case is used an extra
+ nop will be generated. */
+ }
+ else if (expr1.X_add_number >= -0x8000
+ && expr1.X_add_number < 0x8000)
+ {
+ macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+ "nop", "");
+ macro_build ((char *) NULL, &icnt, &expr1,
+ mips_isa < 3 ? "addiu" : "daddiu",
+ "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
+ (void) frag_var (rs_machine_dependent, 0, 0,
+ RELAX_ENCODE (0, 0, -12, -4, 0, 0),
+ offset_expr.X_add_symbol, (long) 0,
+ (char *) NULL);
+ }
+ else
+ {
+ int off1;
+
+ /* 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)
+ off1 = 0;
+ else
+ {
+ macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+ "nop", "");
+ macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+ mips_isa < 3 ? "addu" : "daddu",
+ "d,v,t", treg, AT, breg);
+ breg = 0;
+ tempreg = treg;
+ off1 = -8;
+ }
+
+ macro_build_lui ((char *) NULL, &icnt, &expr1, AT);
+ macro_build ((char *) NULL, &icnt, &expr1,
+ mips_isa < 3 ? "addiu" : "daddiu",
+ "t,r,j", AT, AT, (int) BFD_RELOC_LO16);
+ macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
+ mips_isa < 3 ? "addu" : "daddu",
+ "d,v,t", tempreg, tempreg, AT);
+ (void) frag_var (rs_machine_dependent, 0, 0,
+ RELAX_ENCODE (0, 0, -16 + off1, -8, 0, 0),
+ offset_expr.X_add_symbol, (long) 0,
+ (char *) NULL);
+ used_at = 1;
+ }
+ }
+